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}