opendal_core/raw/accessor.rs
1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::fmt::Debug;
19use std::future::ready;
20use std::hash::Hash;
21use std::hash::Hasher;
22use std::mem;
23use std::sync::Arc;
24
25use futures::Future;
26
27use crate::raw::*;
28use crate::*;
29
30/// Underlying trait of all backends for implementers.
31///
32/// The actual data access of storage service happens in Accessor layer.
33/// Every storage supported by OpenDAL must implement [`Access`] but not all
34/// methods of [`Access`] will be implemented according to how the storage service is.
35///
36/// For example, user can not modify the content from one HTTP file server directly.
37/// So [`Http`][crate::services::Http] implements and provides only read related actions.
38///
39/// [`Access`] gives default implementation for all methods which will raise [`ErrorKind::Unsupported`] error.
40/// And what action this [`Access`] supports will be pointed out in [`AccessorInfo`].
41///
42/// # Note
43///
44/// Visit [`internals`][crate::docs::internals] for more tutorials.
45///
46/// # Operations
47///
48/// - Path in args will all be normalized into the same style, services
49/// should handle them based on services' requirement.
50/// - Path that ends with `/` means it's Dir, otherwise, it's File.
51/// - Root dir is `/`
52/// - Path will never be empty.
53/// - Operations without capability requirement like `metadata`, `create` are
54/// basic operations.
55/// - All services must implement them.
56/// - Use `unimplemented!()` if not implemented or can't implement.
57/// - Operations with capability requirement like `presign` are optional operations.
58/// - Services can implement them based on services capabilities.
59/// - The default implementation should return [`ErrorKind::Unsupported`].
60pub trait Access: Send + Sync + Debug + Unpin + 'static {
61 /// Reader is the associated reader returned in `read` operation.
62 type Reader: oio::Read;
63 /// Writer is the associated writer returned in `write` operation.
64 type Writer: oio::Write;
65 /// Lister is the associated lister returned in `list` operation.
66 type Lister: oio::List;
67 /// Deleter is the associated deleter returned in `delete` operation.
68 type Deleter: oio::Delete;
69 /// Copier is the associated copier returned in `copy` operation.
70 type Copier: oio::Copy;
71
72 /// Invoke the `info` operation to get metadata of accessor.
73 ///
74 /// # Notes
75 ///
76 /// This function is required to be implemented.
77 ///
78 /// By returning AccessorInfo, underlying services can declare
79 /// some useful information about itself.
80 ///
81 /// - scheme: declare the scheme of backend.
82 /// - capabilities: declare the capabilities of current backend.
83 fn info(&self) -> Arc<AccessorInfo>;
84
85 /// Invoke the `create` operation on the specified path
86 ///
87 /// Require [`Capability::create_dir`]
88 ///
89 /// # Behavior
90 ///
91 /// - Input path MUST match with EntryMode, DON'T NEED to check mode.
92 /// - Create on existing dir SHOULD succeed.
93 fn create_dir(
94 &self,
95 path: &str,
96 args: OpCreateDir,
97 ) -> impl Future<Output = Result<RpCreateDir>> + MaybeSend {
98 let (_, _) = (path, args);
99
100 ready(Err(Error::new(
101 ErrorKind::Unsupported,
102 "operation is not supported",
103 )))
104 }
105
106 /// Invoke the `stat` operation on the specified path.
107 ///
108 /// Require [`Capability::stat`]
109 ///
110 /// # Behavior
111 ///
112 /// - `stat` empty path means stat backend's root path.
113 /// - `stat` a path endswith "/" means stating a dir.
114 /// - `mode` and `content_length` must be set.
115 fn stat(&self, path: &str, args: OpStat) -> impl Future<Output = Result<RpStat>> + MaybeSend {
116 let (_, _) = (path, args);
117
118 ready(Err(Error::new(
119 ErrorKind::Unsupported,
120 "operation is not supported",
121 )))
122 }
123
124 /// Invoke the `read` operation on the specified path, returns a
125 /// [`Reader`][crate::Reader] if operate successful.
126 ///
127 /// Require [`Capability::read`]
128 ///
129 /// # Behavior
130 ///
131 /// - Input path MUST be file path, DON'T NEED to check mode.
132 /// - The returning content length may be smaller than the range specified.
133 fn read(
134 &self,
135 path: &str,
136 args: OpRead,
137 ) -> impl Future<Output = Result<(RpRead, Self::Reader)>> + MaybeSend {
138 let (_, _) = (path, args);
139
140 ready(Err(Error::new(
141 ErrorKind::Unsupported,
142 "operation is not supported",
143 )))
144 }
145
146 /// Invoke the `write` operation on the specified path, returns a
147 /// written size if operate successful.
148 ///
149 /// Require [`Capability::write`]
150 ///
151 /// # Behavior
152 ///
153 /// - Input path MUST be file path, DON'T NEED to check mode.
154 fn write(
155 &self,
156 path: &str,
157 args: OpWrite,
158 ) -> impl Future<Output = Result<(RpWrite, Self::Writer)>> + MaybeSend {
159 let (_, _) = (path, args);
160
161 ready(Err(Error::new(
162 ErrorKind::Unsupported,
163 "operation is not supported",
164 )))
165 }
166
167 /// Invoke the `delete` operation on the specified path.
168 ///
169 /// Require [`Capability::delete`]
170 ///
171 /// # Behavior
172 ///
173 /// - `delete` is an idempotent operation, it's safe to call `Delete` on the same path multiple times.
174 /// - `delete` SHOULD return `Ok(())` if the path is deleted successfully or not exist.
175 fn delete(&self) -> impl Future<Output = Result<(RpDelete, Self::Deleter)>> + MaybeSend {
176 ready(Err(Error::new(
177 ErrorKind::Unsupported,
178 "operation is not supported",
179 )))
180 }
181
182 /// Invoke the `list` operation on the specified path.
183 ///
184 /// Require [`Capability::list`]
185 ///
186 /// # Behavior
187 ///
188 /// - Input path MUST be dir path, DON'T NEED to check mode.
189 /// - List non-exist dir should return Empty.
190 fn list(
191 &self,
192 path: &str,
193 args: OpList,
194 ) -> impl Future<Output = Result<(RpList, Self::Lister)>> + MaybeSend {
195 let (_, _) = (path, args);
196
197 ready(Err(Error::new(
198 ErrorKind::Unsupported,
199 "operation is not supported",
200 )))
201 }
202
203 /// Invoke the `copy` operation on the specified `from` path and `to` path.
204 ///
205 /// Require [Capability::copy]
206 ///
207 /// # Behaviour
208 ///
209 /// - `from` and `to` MUST be file path, DON'T NEED to check mode.
210 /// - Copy on existing file SHOULD succeed.
211 /// - Copy on existing file SHOULD overwrite and truncate.
212 fn copy(
213 &self,
214 from: &str,
215 to: &str,
216 args: OpCopy,
217 opts: OpCopier,
218 ) -> impl Future<Output = Result<(RpCopy, Self::Copier)>> + MaybeSend {
219 let (_, _, _, _) = (from, to, args, opts);
220
221 ready(Err(Error::new(
222 ErrorKind::Unsupported,
223 "operation is not supported",
224 )))
225 }
226
227 /// Invoke the `rename` operation on the specified `from` path and `to` path.
228 ///
229 /// Require [Capability::rename]
230 fn rename(
231 &self,
232 from: &str,
233 to: &str,
234 args: OpRename,
235 ) -> impl Future<Output = Result<RpRename>> + MaybeSend {
236 let (_, _, _) = (from, to, args);
237
238 ready(Err(Error::new(
239 ErrorKind::Unsupported,
240 "operation is not supported",
241 )))
242 }
243
244 /// Invoke the `presign` operation on the specified path.
245 ///
246 /// Require [`Capability::presign`]
247 ///
248 /// # Behavior
249 ///
250 /// - This API is optional, return [`std::io::ErrorKind::Unsupported`] if not supported.
251 fn presign(
252 &self,
253 path: &str,
254 args: OpPresign,
255 ) -> impl Future<Output = Result<RpPresign>> + MaybeSend {
256 let (_, _) = (path, args);
257
258 ready(Err(Error::new(
259 ErrorKind::Unsupported,
260 "operation is not supported",
261 )))
262 }
263}
264
265/// `AccessDyn` is the dyn version of [`Access`] make it possible to use as
266/// `Box<dyn AccessDyn>`.
267pub trait AccessDyn: Send + Sync + Debug + Unpin {
268 /// Dyn version of [`Accessor::info`]
269 fn info_dyn(&self) -> Arc<AccessorInfo>;
270 /// Dyn version of [`Accessor::create_dir`]
271 fn create_dir_dyn<'a>(
272 &'a self,
273 path: &'a str,
274 args: OpCreateDir,
275 ) -> BoxedFuture<'a, Result<RpCreateDir>>;
276 /// Dyn version of [`Accessor::stat`]
277 fn stat_dyn<'a>(&'a self, path: &'a str, args: OpStat) -> BoxedFuture<'a, Result<RpStat>>;
278 /// Dyn version of [`Accessor::read`]
279 fn read_dyn<'a>(
280 &'a self,
281 path: &'a str,
282 args: OpRead,
283 ) -> BoxedFuture<'a, Result<(RpRead, oio::Reader)>>;
284 /// Dyn version of [`Accessor::write`]
285 fn write_dyn<'a>(
286 &'a self,
287 path: &'a str,
288 args: OpWrite,
289 ) -> BoxedFuture<'a, Result<(RpWrite, oio::Writer)>>;
290 /// Dyn version of [`Accessor::delete`]
291 fn delete_dyn(&self) -> BoxedFuture<'_, Result<(RpDelete, oio::Deleter)>>;
292 /// Dyn version of [`Accessor::list`]
293 fn list_dyn<'a>(
294 &'a self,
295 path: &'a str,
296 args: OpList,
297 ) -> BoxedFuture<'a, Result<(RpList, oio::Lister)>>;
298 /// Dyn version of [`Accessor::copy`]
299 fn copy_dyn<'a>(
300 &'a self,
301 from: &'a str,
302 to: &'a str,
303 args: OpCopy,
304 opts: OpCopier,
305 ) -> BoxedFuture<'a, Result<(RpCopy, oio::Copier)>>;
306 /// Dyn version of [`Accessor::rename`]
307 fn rename_dyn<'a>(
308 &'a self,
309 from: &'a str,
310 to: &'a str,
311 args: OpRename,
312 ) -> BoxedFuture<'a, Result<RpRename>>;
313 /// Dyn version of [`Accessor::presign`]
314 fn presign_dyn<'a>(
315 &'a self,
316 path: &'a str,
317 args: OpPresign,
318 ) -> BoxedFuture<'a, Result<RpPresign>>;
319}
320
321impl<A: ?Sized> AccessDyn for A
322where
323 A: Access<
324 Reader = oio::Reader,
325 Writer = oio::Writer,
326 Lister = oio::Lister,
327 Deleter = oio::Deleter,
328 Copier = oio::Copier,
329 >,
330{
331 fn info_dyn(&self) -> Arc<AccessorInfo> {
332 self.info()
333 }
334
335 fn create_dir_dyn<'a>(
336 &'a self,
337 path: &'a str,
338 args: OpCreateDir,
339 ) -> BoxedFuture<'a, Result<RpCreateDir>> {
340 Box::pin(self.create_dir(path, args))
341 }
342
343 fn stat_dyn<'a>(&'a self, path: &'a str, args: OpStat) -> BoxedFuture<'a, Result<RpStat>> {
344 Box::pin(self.stat(path, args))
345 }
346
347 fn read_dyn<'a>(
348 &'a self,
349 path: &'a str,
350 args: OpRead,
351 ) -> BoxedFuture<'a, Result<(RpRead, oio::Reader)>> {
352 Box::pin(self.read(path, args))
353 }
354
355 fn write_dyn<'a>(
356 &'a self,
357 path: &'a str,
358 args: OpWrite,
359 ) -> BoxedFuture<'a, Result<(RpWrite, oio::Writer)>> {
360 Box::pin(self.write(path, args))
361 }
362
363 fn delete_dyn(&self) -> BoxedFuture<'_, Result<(RpDelete, oio::Deleter)>> {
364 Box::pin(self.delete())
365 }
366
367 fn list_dyn<'a>(
368 &'a self,
369 path: &'a str,
370 args: OpList,
371 ) -> BoxedFuture<'a, Result<(RpList, oio::Lister)>> {
372 Box::pin(self.list(path, args))
373 }
374
375 fn copy_dyn<'a>(
376 &'a self,
377 from: &'a str,
378 to: &'a str,
379 args: OpCopy,
380 opts: OpCopier,
381 ) -> BoxedFuture<'a, Result<(RpCopy, oio::Copier)>> {
382 Box::pin(self.copy(from, to, args, opts))
383 }
384
385 fn rename_dyn<'a>(
386 &'a self,
387 from: &'a str,
388 to: &'a str,
389 args: OpRename,
390 ) -> BoxedFuture<'a, Result<RpRename>> {
391 Box::pin(self.rename(from, to, args))
392 }
393
394 fn presign_dyn<'a>(
395 &'a self,
396 path: &'a str,
397 args: OpPresign,
398 ) -> BoxedFuture<'a, Result<RpPresign>> {
399 Box::pin(self.presign(path, args))
400 }
401}
402
403impl Access for dyn AccessDyn {
404 type Reader = oio::Reader;
405 type Writer = oio::Writer;
406 type Deleter = oio::Deleter;
407 type Lister = oio::Lister;
408 type Copier = oio::Copier;
409
410 fn info(&self) -> Arc<AccessorInfo> {
411 self.info_dyn()
412 }
413
414 async fn create_dir(&self, path: &str, args: OpCreateDir) -> Result<RpCreateDir> {
415 self.create_dir_dyn(path, args).await
416 }
417
418 async fn stat(&self, path: &str, args: OpStat) -> Result<RpStat> {
419 self.stat_dyn(path, args).await
420 }
421
422 async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> {
423 self.read_dyn(path, args).await
424 }
425
426 async fn write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::Writer)> {
427 self.write_dyn(path, args).await
428 }
429
430 async fn delete(&self) -> Result<(RpDelete, Self::Deleter)> {
431 self.delete_dyn().await
432 }
433
434 async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Lister)> {
435 self.list_dyn(path, args).await
436 }
437
438 async fn copy(
439 &self,
440 from: &str,
441 to: &str,
442 args: OpCopy,
443 opts: OpCopier,
444 ) -> Result<(RpCopy, Self::Copier)> {
445 self.copy_dyn(from, to, args, opts).await
446 }
447
448 async fn rename(&self, from: &str, to: &str, args: OpRename) -> Result<RpRename> {
449 self.rename_dyn(from, to, args).await
450 }
451
452 async fn presign(&self, path: &str, args: OpPresign) -> Result<RpPresign> {
453 self.presign_dyn(path, args).await
454 }
455}
456
457/// Dummy implementation of accessor.
458impl Access for () {
459 type Reader = ();
460 type Writer = ();
461 type Lister = ();
462 type Deleter = ();
463 type Copier = ();
464
465 fn info(&self) -> Arc<AccessorInfo> {
466 let ai = AccessorInfo::default();
467 ai.set_scheme("dummy")
468 .set_root("")
469 .set_name("dummy")
470 .set_native_capability(Capability::default());
471 ai.into()
472 }
473}
474
475/// All functions in `Accessor` only requires `&self`, so it's safe to implement
476/// `Accessor` for `Arc<impl Access>`.
477// If we use async fn directly, some weird higher rank trait bound error (`Send`/`Accessor` impl not general enough) will happen.
478// Probably related to https://github.com/rust-lang/rust/issues/96865
479#[allow(clippy::manual_async_fn)]
480impl<T: Access + ?Sized> Access for Arc<T> {
481 type Reader = T::Reader;
482 type Writer = T::Writer;
483 type Lister = T::Lister;
484 type Deleter = T::Deleter;
485 type Copier = T::Copier;
486
487 fn info(&self) -> Arc<AccessorInfo> {
488 self.as_ref().info()
489 }
490
491 fn create_dir(
492 &self,
493 path: &str,
494 args: OpCreateDir,
495 ) -> impl Future<Output = Result<RpCreateDir>> + MaybeSend {
496 async move { self.as_ref().create_dir(path, args).await }
497 }
498
499 fn stat(&self, path: &str, args: OpStat) -> impl Future<Output = Result<RpStat>> + MaybeSend {
500 async move { self.as_ref().stat(path, args).await }
501 }
502
503 fn read(
504 &self,
505 path: &str,
506 args: OpRead,
507 ) -> impl Future<Output = Result<(RpRead, Self::Reader)>> + MaybeSend {
508 async move { self.as_ref().read(path, args).await }
509 }
510
511 fn write(
512 &self,
513 path: &str,
514 args: OpWrite,
515 ) -> impl Future<Output = Result<(RpWrite, Self::Writer)>> + MaybeSend {
516 async move { self.as_ref().write(path, args).await }
517 }
518
519 fn delete(&self) -> impl Future<Output = Result<(RpDelete, Self::Deleter)>> + MaybeSend {
520 async move { self.as_ref().delete().await }
521 }
522
523 fn list(
524 &self,
525 path: &str,
526 args: OpList,
527 ) -> impl Future<Output = Result<(RpList, Self::Lister)>> + MaybeSend {
528 async move { self.as_ref().list(path, args).await }
529 }
530
531 fn copy(
532 &self,
533 from: &str,
534 to: &str,
535 args: OpCopy,
536 opts: OpCopier,
537 ) -> impl Future<Output = Result<(RpCopy, Self::Copier)>> + MaybeSend {
538 async move { self.as_ref().copy(from, to, args, opts).await }
539 }
540
541 fn rename(
542 &self,
543 from: &str,
544 to: &str,
545 args: OpRename,
546 ) -> impl Future<Output = Result<RpRename>> + MaybeSend {
547 async move { self.as_ref().rename(from, to, args).await }
548 }
549
550 fn presign(
551 &self,
552 path: &str,
553 args: OpPresign,
554 ) -> impl Future<Output = Result<RpPresign>> + MaybeSend {
555 async move { self.as_ref().presign(path, args).await }
556 }
557}
558
559/// Accessor is the type erased accessor with `Arc<dyn Accessor>`.
560pub type Accessor = Arc<dyn AccessDyn>;
561
562#[derive(Debug)]
563struct AccessorInfoInner {
564 scheme: &'static str,
565 root: Arc<str>,
566 name: Arc<str>,
567
568 native_capability: Capability,
569 full_capability: Capability,
570
571 http_client: HttpClient,
572 executor: Executor,
573}
574
575impl Default for AccessorInfoInner {
576 fn default() -> Self {
577 Self {
578 scheme: "unknown",
579 root: Arc::from(""),
580 name: Arc::from(""),
581 native_capability: Capability::default(),
582 full_capability: Capability::default(),
583 http_client: HttpClient::default(),
584 executor: Executor::default(),
585 }
586 }
587}
588
589/// Info for the accessor. Users can use this struct to retrieve information about the underlying backend.
590///
591/// This struct is intentionally not implemented with `Clone` to ensure that all accesses
592/// within the same operator, access layers, and services use the same instance of `AccessorInfo`.
593/// This is especially important for `HttpClient` and `Executor`.
594///
595/// ## Panic Safety
596///
597/// All methods provided by `AccessorInfo` will safely handle lock poisoning scenarios.
598/// If the inner `RwLock` is poisoned (which happens when another thread panicked while holding
599/// the write lock), this method will gracefully continue execution.
600///
601/// - For read operations, the method will return the current state.
602/// - For write operations, the method will do nothing.
603///
604/// ## Maintain Notes
605///
606/// We are using `std::sync::RwLock` to provide thread-safe access to the inner data.
607///
608/// I have performed [the bench across different arc-swap alike crates](https://github.com/krdln/arc-swap-benches):
609///
610/// ```txt
611/// test arcswap ... bench: 14.85 ns/iter (+/- 0.33)
612/// test arcswap_full ... bench: 128.27 ns/iter (+/- 4.30)
613/// test baseline ... bench: 11.33 ns/iter (+/- 0.76)
614/// test mutex_4 ... bench: 296.73 ns/iter (+/- 49.96)
615/// test mutex_unconteded ... bench: 13.26 ns/iter (+/- 0.56)
616/// test rwlock_fast_4 ... bench: 201.60 ns/iter (+/- 7.47)
617/// test rwlock_fast_uncontended ... bench: 12.77 ns/iter (+/- 0.37)
618/// test rwlock_parking_4 ... bench: 232.02 ns/iter (+/- 11.14)
619/// test rwlock_parking_uncontended ... bench: 13.18 ns/iter (+/- 0.39)
620/// test rwlock_std_4 ... bench: 219.56 ns/iter (+/- 5.56)
621/// test rwlock_std_uncontended ... bench: 13.55 ns/iter (+/- 0.33)
622/// ```
623///
624/// The results show that as long as there aren't too many uncontended accesses, `RwLock` is the
625/// best choice, allowing for fast access and the ability to modify partial data without cloning
626/// everything.
627///
628/// And it's true: we only update and modify the internal data in a few instances, such as when
629/// building an operator or applying new layers.
630#[derive(Debug, Default)]
631pub struct AccessorInfo {
632 inner: std::sync::RwLock<AccessorInfoInner>,
633}
634
635impl PartialEq for AccessorInfo {
636 fn eq(&self, other: &Self) -> bool {
637 self.scheme() == other.scheme()
638 && self.root() == other.root()
639 && self.name() == other.name()
640 }
641}
642
643impl Eq for AccessorInfo {}
644
645impl Hash for AccessorInfo {
646 fn hash<H: Hasher>(&self, state: &mut H) {
647 self.scheme().hash(state);
648 self.root().hash(state);
649 self.name().hash(state);
650 }
651}
652
653impl AccessorInfo {
654 /// Scheme of backend.
655 ///
656 /// # Panic Safety
657 ///
658 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
659 /// this method will gracefully continue execution by simply returning the current scheme.
660 pub fn scheme(&self) -> &'static str {
661 match self.inner.read() {
662 Ok(v) => v.scheme,
663 Err(err) => err.get_ref().scheme,
664 }
665 }
666
667 /// Set scheme for backend.
668 ///
669 /// # Panic Safety
670 ///
671 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
672 /// this method will gracefully continue execution by simply skipping the update operation
673 /// rather than propagating the panic.
674 pub fn set_scheme(&self, scheme: &'static str) -> &Self {
675 if let Ok(mut v) = self.inner.write() {
676 v.scheme = scheme;
677 }
678
679 self
680 }
681
682 /// Root of backend, will be in format like `/path/to/dir/`
683 ///
684 /// # Panic Safety
685 ///
686 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
687 /// this method will gracefully continue execution by simply returning the current root.
688 pub fn root(&self) -> Arc<str> {
689 match self.inner.read() {
690 Ok(v) => v.root.clone(),
691 Err(err) => err.get_ref().root.clone(),
692 }
693 }
694
695 /// Set root for backend.
696 ///
697 /// Note: input root must be normalized.
698 ///
699 /// # Panic Safety
700 ///
701 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
702 /// this method will gracefully continue execution by simply skipping the update operation
703 /// rather than propagating the panic.
704 pub fn set_root(&self, root: &str) -> &Self {
705 if let Ok(mut v) = self.inner.write() {
706 v.root = Arc::from(root);
707 }
708
709 self
710 }
711
712 /// Name of backend, could be empty if underlying backend doesn't have namespace concept.
713 ///
714 /// For example:
715 ///
716 /// - `s3` => bucket name
717 /// - `azblob` => container name
718 /// - `azdfs` => filesystem name
719 /// - `azfile` => share name
720 ///
721 /// # Panic Safety
722 ///
723 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
724 /// this method will gracefully continue execution by simply returning the current scheme.
725 pub fn name(&self) -> Arc<str> {
726 match self.inner.read() {
727 Ok(v) => v.name.clone(),
728 Err(err) => err.get_ref().name.clone(),
729 }
730 }
731
732 /// Set name of this backend.
733 ///
734 /// # Panic Safety
735 ///
736 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
737 /// this method will gracefully continue execution by simply skipping the update operation
738 /// rather than propagating the panic.
739 pub fn set_name(&self, name: &str) -> &Self {
740 if let Ok(mut v) = self.inner.write() {
741 v.name = Arc::from(name)
742 }
743
744 self
745 }
746
747 /// Get backend's native capabilities.
748 ///
749 /// # Panic Safety
750 ///
751 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
752 /// this method will gracefully continue execution by simply returning the current native capability.
753 pub fn native_capability(&self) -> Capability {
754 match self.inner.read() {
755 Ok(v) => v.native_capability,
756 Err(err) => err.get_ref().native_capability,
757 }
758 }
759
760 /// Set native capabilities for service.
761 ///
762 /// # NOTES
763 ///
764 /// Set native capability will also flush the full capability. The only way to change
765 /// full_capability is via `update_full_capability`.
766 ///
767 /// # Panic Safety
768 ///
769 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
770 /// this method will gracefully continue execution by simply skipping the update operation
771 /// rather than propagating the panic.
772 pub fn set_native_capability(&self, capability: Capability) -> &Self {
773 if let Ok(mut v) = self.inner.write() {
774 v.native_capability = capability;
775 v.full_capability = capability;
776 }
777
778 self
779 }
780
781 /// Get service's full capabilities.
782 ///
783 /// # Panic Safety
784 ///
785 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
786 /// this method will gracefully continue execution by simply returning the current native capability.
787 pub fn full_capability(&self) -> Capability {
788 match self.inner.read() {
789 Ok(v) => v.full_capability,
790 Err(err) => err.get_ref().full_capability,
791 }
792 }
793
794 /// Update service's full capabilities.
795 ///
796 /// # Panic Safety
797 ///
798 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
799 /// this method will gracefully continue execution by simply skipping the update operation
800 /// rather than propagating the panic.
801 pub fn update_full_capability(&self, f: impl FnOnce(Capability) -> Capability) -> &Self {
802 if let Ok(mut v) = self.inner.write() {
803 v.full_capability = f(v.full_capability);
804 }
805
806 self
807 }
808
809 /// Get http client from the context.
810 ///
811 /// # Panic Safety
812 ///
813 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
814 /// this method will gracefully continue execution by simply returning the current http client.
815 pub fn http_client(&self) -> HttpClient {
816 match self.inner.read() {
817 Ok(v) => v.http_client.clone(),
818 Err(err) => err.get_ref().http_client.clone(),
819 }
820 }
821
822 /// Update http client for the context.
823 ///
824 /// # Note
825 ///
826 /// Requests must be forwarded to the old HTTP client after the update. Otherwise, features such as retry, tracing, and metrics may not function properly.
827 ///
828 /// # Panic Safety
829 ///
830 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
831 /// this method will gracefully continue execution by simply skipping the update operation.
832 pub fn update_http_client(&self, f: impl FnOnce(HttpClient) -> HttpClient) -> &Self {
833 if let Ok(mut v) = self.inner.write() {
834 let client = mem::take(&mut v.http_client);
835 v.http_client = f(client);
836 }
837
838 self
839 }
840
841 /// Get executor from the context.
842 ///
843 /// # Panic Safety
844 ///
845 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
846 /// this method will gracefully continue execution by simply returning the current executor.
847 pub fn executor(&self) -> Executor {
848 match self.inner.read() {
849 Ok(v) => v.executor.clone(),
850 Err(err) => err.get_ref().executor.clone(),
851 }
852 }
853
854 /// Update executor for the context.
855 ///
856 /// # Note
857 ///
858 /// Tasks must be forwarded to the old executor after the update. Otherwise, features such as retry, timeout, and metrics may not function properly.
859 ///
860 /// # Panic Safety
861 ///
862 /// This method safely handles lock poisoning scenarios. If the inner `RwLock` is poisoned,
863 /// this method will gracefully continue execution by simply skipping the update operation.
864 pub fn update_executor(&self, f: impl FnOnce(Executor) -> Executor) -> &Self {
865 if let Ok(mut v) = self.inner.write() {
866 let executor = mem::take(&mut v.executor);
867 v.executor = f(executor);
868 }
869
870 self
871 }
872}