summaryrefslogtreecommitdiffstats
path: root/vendor/valuable/src/enumerable.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/valuable/src/enumerable.rs')
-rw-r--r--vendor/valuable/src/enumerable.rs682
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()]),
+ }
+ }
+}