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