#![warn(missing_docs, non_ascii_idents, trivial_numeric_casts,
noop_method_call, single_use_lifetimes, trivial_casts,
unused_lifetimes, nonstandard_style, variant_size_differences)]
#![deny(keyword_idents)]
#![warn(clippy::missing_docs_in_private_items)]
#![allow(clippy::needless_return, clippy::while_let_on_iterator)]
pub use struct_metadata_derive::{Described, MetadataKind};
use std::collections::HashMap;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Descriptor<Metadata: Default> {
pub docs: Option<Vec<&'static str>>,
pub metadata: Metadata,
pub kind: Kind<Metadata>,
}
impl<Metadata: MetadataKind> Descriptor<Metadata> {
pub fn propagate(&mut self, context: Option<&Metadata> ) {
let context = match context {
Some(context) => {
self.metadata.forward_propagate_context(context);
context
},
None => {
&self.metadata
}
};
match &mut self.kind {
Kind::Struct { children, .. } => {
for child in children {
child.metadata.forward_propagate_entry_defaults(context, &child.type_info.metadata);
child.type_info.propagate(Some(&child.metadata));
child.metadata.backward_propagate_entry_defaults(context, &child.type_info.metadata);
}
},
Kind::Aliased { kind, .. } |
Kind::Sequence(kind) |
Kind::Option(kind) => {
self.metadata.forward_propagate_child_defaults(&kind.metadata);
kind.propagate(Some(&self.metadata));
self.metadata.backward_propagate_child_defaults(&kind.metadata);
},
Kind::Mapping(key, value) => {
self.metadata.forward_propagate_child_defaults(&key.metadata);
self.metadata.forward_propagate_child_defaults(&value.metadata);
key.propagate(Some(&self.metadata));
value.propagate(Some(&self.metadata));
self.metadata.backward_propagate_child_defaults(&value.metadata);
self.metadata.backward_propagate_child_defaults(&key.metadata);
},
_ => {}
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub enum Kind<Metadata: Default> {
Struct {
name: &'static str,
children: Vec<Entry<Metadata>>,
},
Aliased {
name: &'static str,
kind: Box<Descriptor<Metadata>>
},
Enum {
name: &'static str,
variants: Vec<Variant<Metadata>>,
},
Sequence( Box<Descriptor<Metadata>> ),
Option( Box<Descriptor<Metadata>> ),
Mapping( Box<Descriptor<Metadata>>, Box<Descriptor<Metadata>> ),
DateTime,
String,
U128,
I128,
U64,
I64,
U32,
I32,
U16,
I16,
U8,
I8,
F64,
F32,
Bool,
JSON,
Any,
}
impl<Metadata: MetadataKind> Kind<Metadata> {
pub fn name(&self) -> &'static str {
match self {
Kind::Struct { name, .. } => name,
Kind::Aliased { name, .. } => name,
Kind::Enum { name, .. } => name,
Kind::Sequence(_) => "sequence",
Kind::Option(_) => "option",
Kind::Mapping(_, _) => "mapping",
Kind::DateTime => "datetime",
Kind::String => "string",
Kind::U128 => "u128",
Kind::I128 => "i128",
Kind::U64 => "u64",
Kind::I64 => "i64",
Kind::U32 => "u32",
Kind::I32 => "i32",
Kind::U16 => "u16",
Kind::I16 => "i16",
Kind::U8 => "u8",
Kind::I8 => "i8",
Kind::F64 => "f64",
Kind::F32 => "f32",
Kind::Bool => "bool",
Kind::JSON => "json",
Kind::Any => "any",
}
}
pub fn new_struct(name: &'static str, mut children: Vec<Entry<Metadata>>, flattened_children: &mut [Descriptor<Metadata>], flattened_metadata: &mut [Metadata]) -> Self {
for (child, meta) in flattened_children.iter_mut().zip(flattened_metadata.iter_mut()) {
if let Kind::Struct { children: flattening, .. } = &mut child.kind {
for child in flattening.iter_mut() {
child.metadata.forward_propagate_entry_defaults(meta, &child.type_info.metadata);
child.type_info.propagate(Some(&child.metadata));
child.metadata.backward_propagate_entry_defaults(meta, &child.type_info.metadata);
}
children.append(flattening)
}
}
Self::Struct { name, children }
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Variant<Metadata: Default> {
pub label: &'static str,
pub docs: Option<Vec<&'static str>>,
pub metadata: Metadata,
pub aliases: &'static [&'static str]
}
#[derive(Debug, Clone)]
pub struct Entry<Metadata: Default> {
pub label: &'static str,
pub docs: Option<Vec<&'static str>>,
pub metadata: Metadata,
pub type_info: Descriptor<Metadata>,
pub has_default: bool,
pub aliases: &'static [&'static str]
}
impl<T: PartialEq + Default> PartialEq for Entry<T> {
fn eq(&self, other: &Self) -> bool {
self.label == other.label && self.docs == other.docs && self.metadata == other.metadata && self.type_info == other.type_info && self.has_default == other.has_default
}
}
impl<T: Eq + Default> Eq for Entry<T> {}
pub trait Described<M: Default=HashMap<&'static str, &'static str>> {
fn metadata() -> Descriptor<M>;
}
macro_rules! basic_described {
($type_name:ident, $type_macro:ident) => {
impl<M: Default> Described<M> for $type_name {
fn metadata() -> Descriptor<M> { Descriptor { docs: None, metadata: M::default(), kind: Kind::$type_macro } }
}
};
}
basic_described!{String, String}
basic_described!{i128, I128}
basic_described!{u128, U128}
basic_described!{i64, I64}
basic_described!{u64, U64}
basic_described!{i32, I32}
basic_described!{u32, U32}
basic_described!{i16, I16}
basic_described!{u16, U16}
basic_described!{i8, I8}
basic_described!{u8, U8}
basic_described!{f64, F64}
basic_described!{f32, F32}
basic_described!{bool, Bool}
impl<M: Default, T: Described<M>> Described<M> for Option<T> {
fn metadata() -> Descriptor<M> {
Descriptor {
docs: None,
metadata: M::default(),
kind: Kind::Option(Box::new(T::metadata()))
}
}
}
#[cfg(feature = "std")]
impl<M: Default, T: Described<M>> Described<M> for Box<T> {
fn metadata() -> Descriptor<M> { T::metadata() }
}
#[cfg(feature = "std")]
impl<M: Default, T: Described<M>> Described<M> for Vec<T> {
fn metadata() -> Descriptor<M> {
Descriptor {
docs: None,
metadata: M::default(),
kind: Kind::Sequence(Box::new(T::metadata()))
}
}
}
#[cfg(feature = "std")]
impl<M: Default, K: Described<M> + core::hash::Hash, V: Described<M>> Described<M> for HashMap<K, V> {
fn metadata() -> Descriptor<M> {
Descriptor {
docs: None,
metadata: M::default(),
kind: Kind::Mapping(Box::new(K::metadata()), Box::new(V::metadata()))
}
}
}
#[cfg(feature = "chrono")]
impl<M: Default, Tz: chrono::TimeZone> Described<M> for chrono::DateTime<Tz> {
fn metadata() -> Descriptor<M> {
Descriptor { docs: None, metadata: M::default(), kind: Kind::DateTime }
}
}
#[cfg(feature = "serde_json")]
impl<M: Default> Described<M> for serde_json::Value {
fn metadata() -> Descriptor<M> {
Descriptor { docs: None, metadata: M::default(), kind: Kind::JSON }
}
}
#[cfg(feature = "serde_json")]
impl<M: Default, K: Described<M>, V: Described<M>> Described<M> for serde_json::Map<K, V> {
fn metadata() -> Descriptor<M> {
Descriptor {
docs: None,
metadata: M::default(),
kind: Kind::Mapping(Box::new(K::metadata()), Box::new(V::metadata()))
}
}
}
pub trait MetadataKind: Default {
fn forward_propagate_context(&mut self, _context: &Self) {}
fn forward_propagate_entry_defaults(&mut self, _context: &Self, _kind: &Self) {}
fn backward_propagate_entry_defaults(&mut self, _context: &Self, _kind: &Self) {}
fn forward_propagate_child_defaults(&mut self, _kind: &Self) {}
fn backward_propagate_child_defaults(&mut self, _kind: &Self) {}
}
impl<K, V> MetadataKind for HashMap<K, V> {}
impl<V> MetadataKind for Vec<V> {}