diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/clap_builder/src/builder/ext.rs | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | third_party/rust/clap_builder/src/builder/ext.rs | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/third_party/rust/clap_builder/src/builder/ext.rs b/third_party/rust/clap_builder/src/builder/ext.rs new file mode 100644 index 0000000000..2fb0d96b9d --- /dev/null +++ b/third_party/rust/clap_builder/src/builder/ext.rs @@ -0,0 +1,216 @@ +use crate::util::AnyValueId; +use crate::util::FlatMap; + +#[derive(Default, Clone, Debug)] +pub(crate) struct Extensions { + extensions: FlatMap<AnyValueId, BoxedExtension>, +} + +impl Extensions { + #[allow(dead_code)] + pub(crate) fn get<T: Extension>(&self) -> Option<&T> { + let id = AnyValueId::of::<T>(); + self.extensions.get(&id).map(|e| e.as_ref::<T>()) + } + + #[allow(dead_code)] + pub(crate) fn get_mut<T: Extension>(&mut self) -> Option<&mut T> { + let id = AnyValueId::of::<T>(); + self.extensions.get_mut(&id).map(|e| e.as_mut::<T>()) + } + + #[allow(dead_code)] + pub(crate) fn get_or_insert_default<T: Extension + Default>(&mut self) -> &mut T { + let id = AnyValueId::of::<T>(); + self.extensions + .entry(id) + .or_insert_with(|| BoxedExtension::new(T::default())) + .as_mut::<T>() + } + + #[allow(dead_code)] + pub(crate) fn set<T: Extension + Into<BoxedEntry>>(&mut self, tagged: T) -> bool { + let BoxedEntry { id, value } = tagged.into(); + self.extensions.insert(id, value).is_some() + } + + #[allow(dead_code)] + pub(crate) fn remove<T: Extension>(&mut self) -> Option<Box<dyn Extension>> { + let id = AnyValueId::of::<T>(); + self.extensions.remove(&id).map(BoxedExtension::into_inner) + } + + pub(crate) fn update(&mut self, other: &Self) { + for (key, value) in other.extensions.iter() { + self.extensions.insert(*key, value.clone()); + } + } +} + +/// Supports conversion to `Any`. Traits to be extended by `impl_downcast!` must extend `Extension`. +pub(crate) trait Extension: std::fmt::Debug + Send + Sync + 'static { + /// Convert `Box<dyn Trait>` (where `Trait: Extension`) to `Box<dyn Any>`. + /// + /// `Box<dyn Any>` can /// then be further `downcast` into + /// `Box<ConcreteType>` where `ConcreteType` implements `Trait`. + fn into_any(self: Box<Self>) -> Box<dyn std::any::Any>; + /// Clone `&Box<dyn Trait>` (where `Trait: Extension`) to `Box<dyn Extension>`. + /// + /// `Box<dyn Any>` can /// then be further `downcast` into + // `Box<ConcreteType>` where `ConcreteType` implements `Trait`. + fn clone_extension(&self) -> Box<dyn Extension>; + /// Convert `&Trait` (where `Trait: Extension`) to `&Any`. + /// + /// This is needed since Rust cannot /// generate `&Any`'s vtable from + /// `&Trait`'s. + fn as_any(&self) -> &dyn std::any::Any; + /// Convert `&mut Trait` (where `Trait: Extension`) to `&Any`. + /// + /// This is needed since Rust cannot /// generate `&mut Any`'s vtable from + /// `&mut Trait`'s. + fn as_any_mut(&mut self) -> &mut dyn std::any::Any; +} + +impl<T> Extension for T +where + T: Clone + std::fmt::Debug + Send + Sync + 'static, +{ + fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> { + self + } + fn clone_extension(&self) -> Box<dyn Extension> { + Box::new(self.clone()) + } + fn as_any(&self) -> &dyn std::any::Any { + self + } + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + self + } +} + +impl Clone for Box<dyn Extension> { + fn clone(&self) -> Self { + self.as_ref().clone_extension() + } +} + +#[derive(Clone)] +#[repr(transparent)] +struct BoxedExtension(Box<dyn Extension>); + +impl BoxedExtension { + fn new<T: Extension>(inner: T) -> Self { + Self(Box::new(inner)) + } + + fn into_inner(self) -> Box<dyn Extension> { + self.0 + } + + fn as_ref<T: Extension>(&self) -> &T { + self.0.as_ref().as_any().downcast_ref::<T>().unwrap() + } + + fn as_mut<T: Extension>(&mut self) -> &mut T { + self.0.as_mut().as_any_mut().downcast_mut::<T>().unwrap() + } +} + +impl std::fmt::Debug for BoxedExtension { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + self.0.fmt(f) + } +} + +#[derive(Clone)] +pub(crate) struct BoxedEntry { + id: AnyValueId, + value: BoxedExtension, +} + +impl BoxedEntry { + pub(crate) fn new(r: impl Extension) -> Self { + let id = AnyValueId::from(&r); + let value = BoxedExtension::new(r); + BoxedEntry { id, value } + } +} + +impl<R: Extension> From<R> for BoxedEntry { + fn from(inner: R) -> Self { + BoxedEntry::new(inner) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] + struct Number(usize); + + #[test] + fn get() { + let mut ext = Extensions::default(); + ext.set(Number(10)); + assert_eq!(ext.get::<Number>(), Some(&Number(10))); + } + + #[test] + fn get_mut() { + let mut ext = Extensions::default(); + ext.set(Number(10)); + *ext.get_mut::<Number>().unwrap() = Number(20); + assert_eq!(ext.get::<Number>(), Some(&Number(20))); + } + + #[test] + fn get_or_insert_default_empty() { + let mut ext = Extensions::default(); + assert_eq!(ext.get_or_insert_default::<Number>(), &Number(0)); + } + + #[test] + fn get_or_insert_default_full() { + let mut ext = Extensions::default(); + ext.set(Number(10)); + assert_eq!(ext.get_or_insert_default::<Number>(), &Number(10)); + } + + #[test] + fn set() { + let mut ext = Extensions::default(); + assert!(!ext.set(Number(10))); + assert_eq!(ext.get::<Number>(), Some(&Number(10))); + assert!(ext.set(Number(20))); + assert_eq!(ext.get::<Number>(), Some(&Number(20))); + } + + #[test] + fn reset() { + let mut ext = Extensions::default(); + assert_eq!(ext.get::<Number>(), None); + + assert!(ext.remove::<Number>().is_none()); + assert_eq!(ext.get::<Number>(), None); + + assert!(!ext.set(Number(10))); + assert_eq!(ext.get::<Number>(), Some(&Number(10))); + + assert!(ext.remove::<Number>().is_some()); + assert_eq!(ext.get::<Number>(), None); + } + + #[test] + fn update() { + let mut ext = Extensions::default(); + assert_eq!(ext.get::<Number>(), None); + + let mut new = Extensions::default(); + assert!(!new.set(Number(10))); + + ext.update(&new); + assert_eq!(ext.get::<Number>(), Some(&Number(10))); + } +} |