use crate::field::*;
use crate::*;
use core::fmt;
pub trait Structable: Valuable {
fn definition(&self) -> StructDef<'_>;
}
#[derive(Debug)]
#[non_exhaustive]
pub enum StructDef<'a> {
#[non_exhaustive]
Static {
name: &'static str,
fields: Fields<'static>,
},
#[non_exhaustive]
Dynamic {
name: &'a str,
fields: Fields<'a>,
},
}
impl fmt::Debug for dyn Structable + '_ {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let def = self.definition();
if def.fields().is_named() {
struct DebugStruct<'a, 'b> {
fmt: fmt::DebugStruct<'a, 'b>,
}
let mut debug = DebugStruct {
fmt: fmt.debug_struct(def.name()),
};
impl Visit for DebugStruct<'_, '_> {
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 DebugStruct<'a, 'b> {
fmt: fmt::DebugTuple<'a, 'b>,
}
let mut debug = DebugStruct {
fmt: fmt.debug_tuple(def.name()),
};
impl Visit for DebugStruct<'_, '_> {
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()
}
}
}
impl<'a> StructDef<'a> {
pub const fn new_static(name: &'static str, fields: Fields<'static>) -> StructDef<'a> {
StructDef::Static { name, fields }
}
pub const fn new_dynamic(name: &'a str, fields: Fields<'a>) -> StructDef<'a> {
StructDef::Dynamic { name, fields }
}
pub const fn name(&self) -> &'a str {
match self {
StructDef::Static { name, .. } => name,
StructDef::Dynamic { name, .. } => name,
}
}
pub const fn fields(&self) -> &Fields<'a> {
match self {
StructDef::Static { fields, .. } => fields,
StructDef::Dynamic { fields, .. } => fields,
}
}
pub const fn is_static(&self) -> bool {
matches!(self, StructDef::Static { .. })
}
pub const fn is_dynamic(&self) -> bool {
matches!(self, StructDef::Dynamic { .. })
}
}
macro_rules! deref {
(
$(
$(#[$attrs:meta])*
$ty:ty,
)*
) => {
$(
$(#[$attrs])*
impl<T: ?Sized + Structable> Structable for $ty {
fn definition(&self) -> StructDef<'_> {
T::definition(&**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>,
}