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