diff options
Diffstat (limited to 'vendor/valuable/src/enumerable.rs')
-rw-r--r-- | vendor/valuable/src/enumerable.rs | 682 |
1 files changed, 682 insertions, 0 deletions
diff --git a/vendor/valuable/src/enumerable.rs b/vendor/valuable/src/enumerable.rs new file mode 100644 index 000000000..3161f19f0 --- /dev/null +++ b/vendor/valuable/src/enumerable.rs @@ -0,0 +1,682 @@ +use crate::field::*; +use crate::*; + +#[cfg(feature = "alloc")] +use alloc::format; +use core::fmt; + +/// An enum-like [`Valuable`] sub-type. +/// +/// Implemented by [`Valuable`] types that have an enum-like shape. Fields may +/// be named or unnamed (tuple). Values that implement `Enumerable` must return +/// [`Value::Enumerable`] from their [`Valuable::as_value`] implementation. +/// +/// # Inspecting +/// +/// The [`variant()`] method returns the `Enumerable` instance's variant. The +/// `Enumerable` may also have unnamed fields (tuple) or named fields. +/// Inspecting the field values is done by visiting the enum. When visiting an +/// `Enumerable`, either the [`visit_named_fields()`] or the +/// [`visit_unnamed_fields()`] methods of [`Visit`] are called. Each method may +/// be called multiple times per `Enumerable`, but the two methods are never +/// mixed. +/// +/// [`variant()`]: Enumerable::variant +/// [`visit_named_fields()`]: Visit::visit_named_fields +/// [`visit_unnamed_fields()`]: Visit::visit_unnamed_fields +/// +/// ``` +/// use valuable::{Valuable, Value, Visit}; +/// +/// #[derive(Valuable)] +/// enum MyEnum { +/// Foo, +/// Bar(u32), +/// } +/// +/// struct PrintVariant; +/// +/// impl Visit for PrintVariant { +/// fn visit_unnamed_fields(&mut self, values: &[Value<'_>]) { +/// for value in values { +/// println!(" - {:?}", value); +/// } +/// } +/// +/// fn visit_value(&mut self, value: Value<'_>) { +/// match value { +/// Value::Enumerable(v) => { +/// println!("{}", v.variant().name()); +/// v.visit(self) +/// } +/// _ => {} +/// } +/// } +/// } +/// +/// let my_enum = MyEnum::Bar(123); +/// +/// valuable::visit(&my_enum, &mut PrintVariant); +/// ``` +/// +/// If the enum is **statically** defined, then all variants, and variant fields +/// are known ahead of time and may be accessed via the [`EnumDef`] instance +/// returned by [`definition()`]. +/// +/// [`definition()`]: Enumerable::definition +/// +/// # Implementing +/// +/// Implementing `Enumerable` is usually done by adding `#[derive(Valuable)]` to +/// a Rust `enum` definition. +/// +/// ``` +/// use valuable::{Valuable, Enumerable, EnumDef}; +/// +/// #[derive(Valuable)] +/// enum MyEnum { +/// Foo, +/// Bar(u32), +/// } +/// +/// let my_enum = MyEnum::Bar(123); +/// +/// let variants = match my_enum.definition() { +/// EnumDef::Static { name, variants, .. } => { +/// assert_eq!("MyEnum", name); +/// variants +/// } +/// _ => unreachable!(), +/// }; +/// +/// assert_eq!(2, variants.len()); +/// assert_eq!("Foo", variants[0].name()); +/// assert!(variants[0].fields().is_unnamed()); +/// ``` +pub trait Enumerable: Valuable { + /// Returns the enum's definition. + /// + /// See [`EnumDef`] documentation for more details. + /// + /// # Examples + /// + /// ``` + /// use valuable::{Enumerable, Valuable}; + /// + /// #[derive(Valuable)] + /// enum MyEnum { + /// Foo, + /// Bar(u32), + /// } + /// + /// let my_enum = MyEnum::Bar(123); + /// + /// assert_eq!("MyEnum", my_enum.definition().name()); + /// ``` + fn definition(&self) -> EnumDef<'_>; + + /// Returns the `enum`'s current variant. + /// + /// # Examples + /// + /// ``` + /// use valuable::{Enumerable, Valuable}; + /// + /// #[derive(Valuable)] + /// enum MyEnum { + /// Foo, + /// Bar(u32), + /// } + /// + /// let my_enum = MyEnum::Foo; + /// assert_eq!("Foo", my_enum.variant().name()); + /// ``` + fn variant(&self) -> Variant<'_>; +} + +/// An enum's variants, variant fields, and other enum-level information. +/// +/// Returned by [`Enumerable::definition()`], `EnumDef` provides the caller with +/// information about the enum's definition. +#[non_exhaustive] +#[derive(Debug)] +pub enum EnumDef<'a> { + /// The enum is statically-defined, all variants and variant-level fields + /// are known ahead of time. + /// + /// Most `Enumerable` definitions for Rust enum types will be + /// `EnumDef::Static`. + /// + /// # Examples + /// + /// A statically defined enum + /// + /// ``` + /// use valuable::{Valuable, Enumerable, EnumDef}; + /// + /// #[derive(Valuable)] + /// enum MyEnum { + /// Foo, + /// Bar(u32), + /// } + /// + /// let my_enum = MyEnum::Bar(123); + /// + /// let variants = match my_enum.definition() { + /// EnumDef::Static { name, variants, .. } => { + /// assert_eq!("MyEnum", name); + /// variants + /// } + /// _ => unreachable!(), + /// }; + /// + /// assert_eq!(2, variants.len()); + /// assert_eq!("Foo", variants[0].name()); + /// assert_eq!("Bar", variants[1].name()); + /// ``` + #[non_exhaustive] + Static { + /// The enum's name + name: &'static str, + + /// The enum's variants + variants: &'static [VariantDef<'static>], + }, + + /// The enum is dynamically-defined, not all variants and fields are known + /// ahead of time. + /// + /// # Examples + /// + /// The enum variant is tracked as a string + /// + /// ``` + /// use valuable::{Enumerable, EnumDef, Fields, VariantDef, Valuable, Value, Variant, Visit}; + /// + /// /// A dynamic enum + /// struct DynEnum { + /// // The enum name + /// name: String, + /// + /// // The current variant + /// variant: String, + /// } + /// + /// impl Valuable for DynEnum { + /// fn as_value(&self) -> Value<'_> { + /// Value::Enumerable(self) + /// } + /// + /// fn visit(&self, _visit: &mut dyn Visit) { + /// // No variant fields, so there is nothing to call here. + /// } + /// } + /// + /// impl Enumerable for DynEnum { + /// fn definition(&self) -> EnumDef<'_> { + /// EnumDef::new_dynamic(&self.name, &[]) + /// } + /// + /// fn variant(&self) -> Variant<'_> { + /// Variant::Dynamic(VariantDef::new(&self.variant, Fields::Unnamed(0))) + /// } + /// } + /// ``` + #[non_exhaustive] + Dynamic { + /// The enum's name + name: &'a str, + + /// The enum's variants + variants: &'a [VariantDef<'a>], + }, +} + +/// An enum variant definition. +/// +/// Included with [`EnumDef`] returned by [`Enumerable::definition()`], +/// `VariantDef` provides the caller with information about a specific variant. +#[derive(Debug)] +pub struct VariantDef<'a> { + /// Variant name + name: &'a str, + + /// Variant fields + fields: Fields<'a>, +} + +/// An enum variant +/// +/// Returned by [`Enumerable::variant()`], `Variant` represents a single enum +/// variant. +#[derive(Debug)] +pub enum Variant<'a> { + /// The variant is statically defined by the associated enum. + Static(&'static VariantDef<'static>), + + /// The variant is dynamically defined and not included as part of + /// [`Enumerable::definition()`]. + Dynamic(VariantDef<'a>), +} + +impl<'a> EnumDef<'a> { + /// Create a new [`EnumDef::Static`] instance. + /// + /// This should be used when an enum's variants are fixed and known ahead of + /// time. + /// + /// # Examples + /// + /// ``` + /// use valuable::{EnumDef, Fields, VariantDef}; + /// + /// static VARIANTS: &[VariantDef<'static>] = &[ + /// VariantDef::new("Bar", Fields::Unnamed(1)), + /// ]; + /// + /// let def = EnumDef::new_static( "Foo", VARIANTS); + /// ``` + pub const fn new_static( + name: &'static str, + variants: &'static [VariantDef<'static>], + ) -> EnumDef<'a> { + EnumDef::Static { name, variants } + } + + /// Create a new [`EnumDef::Dynamic`] instance. + /// + /// This is used when the enum's variants may vary at runtime. + /// + /// # Examples + /// + /// ``` + /// use valuable::{EnumDef, Fields, VariantDef}; + /// + /// let def = EnumDef::new_dynamic( + /// "Foo", + /// &[VariantDef::new("Bar", Fields::Unnamed(1))] + /// ); + /// ``` + pub const fn new_dynamic(name: &'a str, variants: &'a [VariantDef<'a>]) -> EnumDef<'a> { + EnumDef::Dynamic { name, variants } + } + + /// Returns the enum's name + /// + /// # Examples + /// + /// ``` + /// use valuable::{Enumerable, Valuable}; + /// + /// #[derive(Valuable)] + /// enum Foo { + /// Bar, + /// Baz, + /// } + /// + /// let def = Foo::Bar.definition(); + /// assert_eq!("Foo", def.name()); + /// ``` + pub fn name(&self) -> &str { + match self { + EnumDef::Static { name, .. } => name, + EnumDef::Dynamic { name, .. } => name, + } + } + + /// Returns the enum's variants + /// + /// # Examples + /// + /// ``` + /// use valuable::{Enumerable, Valuable}; + /// + /// #[derive(Valuable)] + /// enum Foo { + /// Bar, + /// Baz, + /// } + /// + /// let def = Foo::Bar.definition(); + /// let variants = def.variants(); + /// + /// assert_eq!(2, variants.len()); + /// assert_eq!("Bar", variants[0].name()); + /// ``` + pub fn variants(&self) -> &[VariantDef<'_>] { + match self { + EnumDef::Static { variants, .. } => variants, + EnumDef::Dynamic { variants, .. } => variants, + } + } + + /// Returns `true` if the enum is [statically defined](EnumDef::Static). + /// + /// # Examples + /// + /// With a static enum + /// + /// ``` + /// use valuable::{Enumerable, Valuable}; + /// + /// #[derive(Valuable)] + /// enum Foo { + /// Bar, + /// Baz, + /// } + /// + /// let def = Foo::Bar.definition(); + /// assert!(def.is_static()); + /// ``` + /// + /// With a dynamic enum + /// + /// ``` + /// use valuable::{EnumDef, Fields, VariantDef}; + /// + /// let def = EnumDef::new_dynamic("Foo", &[]); + /// assert!(!def.is_static()); + /// ``` + pub fn is_static(&self) -> bool { + matches!(self, EnumDef::Static { .. }) + } + + /// Returns `true` if the enum is [dynamically defined](EnumDef::Dynamic). + /// + /// # Examples + /// + /// With a static enum + /// + /// ``` + /// use valuable::{Enumerable, Valuable}; + /// + /// #[derive(Valuable)] + /// enum Foo { + /// Bar, + /// Baz, + /// } + /// + /// let def = Foo::Bar.definition(); + /// assert!(!def.is_dynamic()); + /// ``` + /// + /// With a dynamic enum + /// + /// ``` + /// use valuable::{EnumDef, Fields, VariantDef}; + /// + /// let def = EnumDef::new_dynamic("Foo", &[]); + /// assert!(def.is_dynamic()); + /// ``` + pub fn is_dynamic(&self) -> bool { + matches!(self, EnumDef::Dynamic { .. }) + } +} + +impl<'a> VariantDef<'a> { + /// Creates a new `VariantDef` instance. + /// + /// # Examples + /// + /// ``` + /// use valuable::{Fields, VariantDef}; + /// + /// let def = VariantDef::new("Foo", Fields::Unnamed(2)); + /// ``` + pub const fn new(name: &'a str, fields: Fields<'a>) -> VariantDef<'a> { + VariantDef { name, fields } + } + + /// Returns the variant's name + /// + /// # Examples + /// + /// ``` + /// use valuable::{Fields, VariantDef}; + /// + /// let def = VariantDef::new("Foo", Fields::Unnamed(2)); + /// assert_eq!("Foo", def.name()); + /// ``` + pub fn name(&self) -> &str { + self.name + } + + /// Returns the variant's fields + /// + /// # Examples + /// + /// ``` + /// use valuable::{Fields, VariantDef}; + /// + /// let def = VariantDef::new("Foo", Fields::Unnamed(3)); + /// assert!(matches!(def.fields(), Fields::Unnamed(_))); + /// ``` + pub fn fields(&self) -> &Fields<'_> { + &self.fields + } +} + +impl Variant<'_> { + /// Returns the variant's name + /// + /// # Examples + /// + /// ``` + /// use valuable::{Fields, Variant, VariantDef}; + /// + /// static VARIANT: &VariantDef<'static> = &VariantDef::new( + /// "Foo", Fields::Unnamed(2)); + /// + /// let variant = Variant::Static(VARIANT); + /// assert_eq!("Foo", variant.name()); + /// ``` + pub fn name(&self) -> &str { + match self { + Variant::Static(v) => v.name(), + Variant::Dynamic(v) => v.name(), + } + } + + /// Returns the variant's fields + pub fn fields(&self) -> &Fields<'_> { + match self { + Variant::Static(v) => v.fields(), + Variant::Dynamic(v) => v.fields(), + } + } + + /// Returns `true` if the variant has associated named fields. + /// + /// # Examples + /// + /// With named fields + /// + /// ``` + /// use valuable::{Fields, NamedField, Variant, VariantDef}; + /// + /// static VARIANT: &VariantDef<'static> = &VariantDef::new( + /// "Foo", Fields::Named(&[NamedField::new("hello")])); + /// + /// let variant = Variant::Static(VARIANT); + /// assert!(variant.is_named_fields()); + /// ``` + /// + /// With unnamed fields + /// + /// ``` + /// use valuable::{Fields, Variant, VariantDef}; + /// + /// static VARIANT: &VariantDef<'static> = &VariantDef::new( + /// "Foo", Fields::Unnamed(1)); + /// + /// let variant = Variant::Static(VARIANT); + /// assert!(!variant.is_named_fields()); + /// ``` + pub fn is_named_fields(&self) -> bool { + self.fields().is_named() + } + + /// Returns `true` if the variant has associated unnamed fields. + /// + /// # Examples + /// + /// With named fields + /// + /// ``` + /// use valuable::{Fields, NamedField, Variant, VariantDef}; + /// + /// static VARIANT: &VariantDef<'static> = &VariantDef::new( + /// "Foo", Fields::Named(&[NamedField::new("hello")])); + /// + /// let variant = Variant::Static(VARIANT); + /// assert!(!variant.is_unnamed_fields()); + /// ``` + /// + /// With unnamed fields + /// + /// ``` + /// use valuable::{Fields, Variant, VariantDef}; + /// + /// static VARIANT: &VariantDef<'static> = &VariantDef::new( + /// "Foo", Fields::Unnamed(1)); + /// + /// let variant = Variant::Static(VARIANT); + /// assert!(variant.is_unnamed_fields()); + /// ``` + pub fn is_unnamed_fields(&self) -> bool { + !self.is_named_fields() + } +} + +impl fmt::Debug for dyn Enumerable + '_ { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let variant = self.variant(); + #[cfg(feature = "alloc")] + let name = format!("{}::{}", self.definition().name(), variant.name()); + #[cfg(not(feature = "alloc"))] + let name = variant.name(); + + if variant.is_named_fields() { + struct DebugEnum<'a, 'b> { + fmt: fmt::DebugStruct<'a, 'b>, + } + + let mut debug = DebugEnum { + fmt: fmt.debug_struct(&name), + }; + + impl Visit for DebugEnum<'_, '_> { + fn visit_named_fields(&mut self, named_values: &NamedValues<'_>) { + for (field, value) in named_values { + self.fmt.field(field.name(), value); + } + } + + fn visit_value(&mut self, _: Value<'_>) { + unreachable!(); + } + } + + self.visit(&mut debug); + + debug.fmt.finish() + } else { + struct DebugEnum<'a, 'b> { + fmt: fmt::DebugTuple<'a, 'b>, + } + + let mut debug = DebugEnum { + fmt: fmt.debug_tuple(&name), + }; + + impl Visit for DebugEnum<'_, '_> { + fn visit_unnamed_fields(&mut self, values: &[Value<'_>]) { + for value in values { + self.fmt.field(value); + } + } + + fn visit_value(&mut self, _: Value<'_>) { + unreachable!(); + } + } + + self.visit(&mut debug); + + debug.fmt.finish() + } + } +} + +macro_rules! deref { + ( + $( + $(#[$attrs:meta])* + $ty:ty, + )* + ) => { + $( + $(#[$attrs])* + impl<T: ?Sized + Enumerable> Enumerable for $ty { + fn definition(&self) -> EnumDef<'_> { + T::definition(&**self) + } + + fn variant(&self) -> Variant<'_> { + T::variant(&**self) + } + } + )* + }; +} + +deref! { + &T, + &mut T, + #[cfg(feature = "alloc")] + alloc::boxed::Box<T>, + #[cfg(feature = "alloc")] + alloc::rc::Rc<T>, + #[cfg(not(valuable_no_atomic_cas))] + #[cfg(feature = "alloc")] + alloc::sync::Arc<T>, +} + +static RESULT_VARIANTS: &[VariantDef<'static>] = &[ + VariantDef::new("Ok", Fields::Unnamed(1)), + VariantDef::new("Err", Fields::Unnamed(1)), +]; + +impl<T, E> Enumerable for Result<T, E> +where + T: Valuable, + E: Valuable, +{ + fn definition(&self) -> EnumDef<'_> { + EnumDef::new_static("Result", RESULT_VARIANTS) + } + + fn variant(&self) -> Variant<'_> { + match self { + Ok(_) => Variant::Static(&RESULT_VARIANTS[0]), + Err(_) => Variant::Static(&RESULT_VARIANTS[1]), + } + } +} + +impl<T, E> Valuable for Result<T, E> +where + T: Valuable, + E: Valuable, +{ + fn as_value(&self) -> Value<'_> { + Value::Enumerable(self) + } + + fn visit(&self, visitor: &mut dyn Visit) { + match self { + Ok(val) => visitor.visit_unnamed_fields(&[val.as_value()]), + Err(val) => visitor.visit_unnamed_fields(&[val.as_value()]), + } + } +} |