blob: 3161f19f0dafca6dd6ce542f16fb684cc71c4711 [file] [log] [blame] [edit]
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()]),
}
}
}