diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml index 80f1c44..4b0f0cf 100644 --- a/.github/workflows/rust-ci.yml +++ b/.github/workflows/rust-ci.yml @@ -42,6 +42,21 @@ jobs: - name: cargo hack check run: cargo hack check --each-feature --no-dev-deps --all + check-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + profile: minimal + - uses: Swatinem/rust-cache@v1 + - name: cargo doc + env: + RUSTDOCFLAGS: "-D broken-intra-doc-links" + run: cargo doc --all-features --no-deps + no-std-build: runs-on: ubuntu-latest steps: diff --git a/crates/mirror-mirror-macros/Cargo.toml b/crates/mirror-mirror-macros/Cargo.toml index e3e238e..fdfdd1c 100644 --- a/crates/mirror-mirror-macros/Cargo.toml +++ b/crates/mirror-mirror-macros/Cargo.toml @@ -17,6 +17,9 @@ proc-macro2 = "1.0.47" quote = "1.0.21" syn = { version = "1.0.102", features = ["full", "visit"] } +[dev-dependencies] +mirror-mirror = { path = "../mirror-mirror", version = "0.1", default-features = false } + [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] diff --git a/crates/mirror-mirror-macros/src/lib.rs b/crates/mirror-mirror-macros/src/lib.rs index b3bface..602905f 100644 --- a/crates/mirror-mirror-macros/src/lib.rs +++ b/crates/mirror-mirror-macros/src/lib.rs @@ -48,6 +48,204 @@ use syn::parse::Parse; mod derive_reflect; +/// Derive an implementation of `Reflect` and other appropriate traits. +/// +/// # Structs +/// +/// On structs `#[derive(Reflect)]` will also derive `Struct` and `FromReflect`. +/// +/// ``` +/// use mirror_mirror::Reflect; +/// +/// #[derive(Reflect, Clone, Debug)] +/// struct Foo { +/// a: i32, +/// b: bool, +/// c: String, +/// } +/// ``` +/// +/// Unit structs are treated as tuple structs with no fields. +/// +/// # Tuple structs +/// +/// On tuple structs `#[derive(Reflect)]` will also derive `TupleStruct` and `FromReflect`. +/// +/// ``` +/// use mirror_mirror::Reflect; +/// +/// #[derive(Reflect, Clone, Debug)] +/// struct Foo(i32, bool, String); +/// ``` +/// +/// # Enums +/// +/// On enums `#[derive(Reflect)]` will also derive `Enum` and `FromReflect`. +/// +/// ``` +/// use mirror_mirror::Reflect; +/// +/// #[derive(Reflect, Clone, Debug)] +/// enum Foo { +/// A(i32), +/// B { b: bool }, +/// C, +/// } +/// ``` +/// +/// # Options +/// +/// ## `opt_out` +/// +/// By default types are required to implement `Clone` and `Debug`. You can opt-out of these +/// requirements with `#[reflect(opt_out(Clone, Debug))]` +/// +/// ``` +/// use mirror_mirror::Reflect; +/// +/// #[derive(Reflect)] +/// #[reflect(opt_out(Debug, Clone))] +/// struct Foo(i32); +/// ``` +/// +/// This changes the implementation of `Reflect::clone_reflect` and `Reflect::debug` to something +/// that works for any type but is less performant. +/// +/// You can also opt-out of deriving `FromReflect` so you can provide you own implementation: +/// +/// ``` +/// use mirror_mirror::{Reflect, FromReflect}; +/// +/// #[derive(Reflect, Debug, Clone)] +/// #[reflect(opt_out(FromReflect))] +/// struct Foo(i32); +/// +/// impl FromReflect for Foo { +/// fn from_reflect(value: &dyn Reflect) -> Option { +/// Some(Self(*value.downcast_ref::()?)) +/// } +/// } +/// ``` +/// +/// ## `skip` +/// +/// You can exclude fields or variants from being reflected with `#[reflect(skip)]`. The type of the skipped field/variant is +/// required to implement `Default` by the default `FromReflect` implementation. +/// +/// ``` +/// use mirror_mirror::{Reflect, FromReflect}; +/// +/// #[derive(Reflect, Debug, Clone)] +/// struct Foo { +/// #[reflect(skip)] +/// not_reflect: NotReflect, +/// } +/// +/// #[derive(Reflect, Debug, Clone)] +/// struct Bar(#[reflect(skip)] NotReflect); +/// +/// #[derive(Reflect, Debug, Clone)] +/// enum Baz { +/// #[reflect(skip)] +/// OnVariant(NotReflect), +/// +/// OnTupleField(#[reflect(skip)] NotReflect), +/// +/// OnStructField { +/// #[reflect(skip)] +/// not_reflect: NotReflect, +/// } +/// } +/// +/// // A type that isn't compatible with reflection +/// #[derive(Debug, Clone, Default)] +/// struct NotReflect; +/// ``` +/// +/// ## `from_reflect_with` +/// +/// You can override `FromReflect` for a single field by specifying a function to do the +/// conversion: +/// +/// ``` +/// use mirror_mirror::{Reflect, FromReflect}; +/// +/// #[derive(Reflect, Debug, Clone)] +/// struct Foo { +/// #[reflect(from_reflect_with(n_from_reflect))] +/// n: i32, +/// } +/// +/// fn n_from_reflect(field: &dyn Reflect) -> Option { +/// Some(*field.downcast_ref::()?) +/// } +/// ``` +/// +/// ## `meta` +/// +/// Metadata associated with types or enum variants can be added with `#[reflect(meta(...))]` +/// +/// ``` +/// use mirror_mirror::{ +/// Reflect, +/// key_path, +/// key_path::GetTypePath, +/// FromReflect, +/// type_info::{GetMeta, Typed}, +/// }; +/// +/// #[derive(Reflect, Debug, Clone)] +/// #[reflect(meta( +/// // a comma separated list of `key = value` pairs. +/// // +/// // `key` must be an identifier and `value` can be anything that +/// // implements `Reflect` +/// item_key = "item value", +/// ))] +/// struct Foo { +/// #[reflect(meta(field_key = 1337))] +/// n: i32, +/// } +/// +/// // Access the metadata through the type information +/// let type_info = ::type_info(); +/// +/// assert_eq!( +/// type_info.get_meta::("item_key").unwrap(), +/// "item value", +/// ); +/// +/// assert_eq!( +/// type_info +/// .as_struct() +/// .unwrap() +/// .field_type("n") +/// .unwrap() +/// .get_meta::("field_key") +/// .unwrap(), +/// 1337, +/// ); +/// ``` +/// +/// ## `crate_name` +/// +/// You can specify a "use path" for `mirror_mirror` with `crate_name`. This is useful if you're +/// using a library that re-exports `mirror_mirror`'s derive macro: +/// +/// ``` +/// # use mirror_mirror as some_library; +/// use some_library::Reflect; +/// +/// #[derive(Reflect, Debug, Clone)] +/// #[reflect(crate_name(some_library))] +/// struct Foo { +/// n: i32, +/// } +/// ``` +/// +/// This causes the macro generate paths like `some_library::FromReflect`. +/// +/// [`Reflect`]: crate::Reflect #[proc_macro_derive(Reflect, attributes(reflect))] pub fn derive_reflect(item: TokenStream) -> TokenStream { expand_with(item, derive_reflect::expand) diff --git a/crates/mirror-mirror/src/array.rs b/crates/mirror-mirror/src/array.rs index eaebfac..996cd25 100644 --- a/crates/mirror-mirror/src/array.rs +++ b/crates/mirror-mirror/src/array.rs @@ -3,6 +3,7 @@ use core::fmt; use crate::iter::ValueIterMut; use crate::Reflect; +/// A reflected array type. pub trait Array: Reflect { fn get(&self, index: usize) -> Option<&dyn Reflect>; diff --git a/crates/mirror-mirror/src/enum_.rs b/crates/mirror-mirror/src/enum_.rs index 76d0811..88e0e9a 100644 --- a/crates/mirror-mirror/src/enum_.rs +++ b/crates/mirror-mirror/src/enum_.rs @@ -22,6 +22,9 @@ use crate::TypeRoot; use crate::Typed; use crate::Value; +/// A reflected enum type. +/// +/// Will be implemented by `#[derive(Reflect)]` on enums. pub trait Enum: Reflect { fn variant_name(&self) -> &str; diff --git a/crates/mirror-mirror/src/get_field.rs b/crates/mirror-mirror/src/get_field.rs index fe10514..2fb8276 100644 --- a/crates/mirror-mirror/src/get_field.rs +++ b/crates/mirror-mirror/src/get_field.rs @@ -12,12 +12,14 @@ use crate::Tuple; use crate::TupleStruct; use crate::Value; +/// Helper trait for accessing and downcasting fields on reflected values. pub trait GetField<'a, K, M> { fn get_field(self, key: K) -> Option<&'a T> where T: Reflect; } +/// Helper trait for mutably accessing and downcasting fields on reflected values. pub trait GetFieldMut<'a, K, M> { fn get_field_mut(self, key: K) -> Option<&'a mut T> where diff --git a/crates/mirror-mirror/src/key_path.rs b/crates/mirror-mirror/src/key_path.rs index fb437fd..8eef178 100644 --- a/crates/mirror-mirror/src/key_path.rs +++ b/crates/mirror-mirror/src/key_path.rs @@ -240,18 +240,12 @@ impl KeyPath { self.path.push(Key::FieldAt(field.into())) } - pub fn variant(mut self, variant: S) -> Self - where - S: Into, - { + pub fn variant(mut self, variant: impl Into) -> Self { self.push_variant(variant); self } - pub fn push_variant(&mut self, variant: S) - where - S: Into, - { + pub fn push_variant(&mut self, variant: impl Into) { self.path.push(Key::Variant(variant.into())); } @@ -328,13 +322,13 @@ pub fn get(field: impl Into) -> KeyPath { KeyPath::default().get(field) } -pub fn variant(variant: S) -> KeyPath -where - S: Into, -{ +pub fn variant(variant: impl Into) -> KeyPath { KeyPath::default().variant(variant) } +/// Convenience macro for creating [`KeyPath`]s. +/// +/// Expands to calls to [`field`], [`get`], [`variant`], and methods on [`KeyPath`]. #[macro_export] macro_rules! key_path { // base case diff --git a/crates/mirror-mirror/src/lib.rs b/crates/mirror-mirror/src/lib.rs index 515c4d8..4646a60 100644 --- a/crates/mirror-mirror/src/lib.rs +++ b/crates/mirror-mirror/src/lib.rs @@ -1,3 +1,216 @@ +//! General purpose reflection library for Rust. +//! +//! # 🚨 Warning 🚨 +//! +//! This library is still experimental and should not be used for anything serious, yet. Many +//! things are still undocumented and breaking changes are to be expected, though we do adhere to +//! semver. +//! +//! # Examples +//! +//! ## Access a field by its string name and mutate it +//! +//! ``` +//! use mirror_mirror::{Reflect, Struct}; +//! +//! #[derive(Reflect, Clone, Debug)] +//! struct Foo { +//! x: i32, +//! } +//! +//! let mut foo = Foo { x: 42 }; +//! +//! # (|| { +//! // Get a `Struct` trait object for `Foo`. +//! // +//! // The `Struct` trait has methods available for all structs such as accessing +//! // fields by name and iterating over the fields. +//! let struct_obj: &mut dyn Struct = foo.as_struct_mut()?; +//! +//! // Mutably borrow the `x` field. We can access fields using string names. +//! let x: &mut dyn Reflect = struct_obj.field_mut("x")?; +//! +//! // Downcast `x` into a mutable `i32` +//! let x: &mut i32 = x.downcast_mut::()?; +//! +//! // Change the value of `x` +//! *x += 1; +//! +//! // The value of `x` in `foo` has now changed. +//! assert_eq!(foo.x, 43); +//! # Some(()) +//! # })().unwrap(); +//! ``` +//! +//! ## Iterate over all fields +//! +//! ``` +//! use mirror_mirror::{Reflect, Struct, ReflectMut, ScalarMut, enum_::VariantFieldMut}; +//! +//! // A function that iterates over the fields in an enum and mutates them. +//! fn change_enum_fields(value: &mut dyn Reflect) -> Option<()> { +//! let enum_ = value.as_enum_mut()?; +//! +//! for field in enum_.fields_mut() { +//! match field { +//! VariantFieldMut::Struct(_, value) | VariantFieldMut::Tuple(value) => { +//! match value.reflect_mut() { +//! ReflectMut::Scalar(ScalarMut::i32(n)) => { +//! *n *= 2; +//! } +//! ReflectMut::Scalar(ScalarMut::String(s)) => { +//! *s = format!("{s}bar"); +//! } +//! // Ignore other types +//! _ => {} +//! } +//! } +//! } +//! } +//! +//! Some(()) +//! } +//! +//! #[derive(Reflect, Clone, Debug)] +//! enum Bar { +//! X { x: i32 }, +//! Y(String), +//! } +//! +//! # (|| { +//! let mut bar = Bar::X { x: 42 }; +//! change_enum_fields(bar.as_reflect_mut())?; +//! +//! assert!(matches!(bar, Bar::X { x: 84 })); +//! +//! let mut bar = Bar::Y("foo".to_owned()); +//! change_enum_fields(bar.as_reflect_mut())?; +//! +//! assert!(matches!(bar, Bar::Y(s) if s == "foobar")); +//! # Some(()) +//! # })().unwrap(); +//! ``` +//! +//! ## Query value and type information using key paths +//! +//! ``` +//! use mirror_mirror::{ +//! Reflect, +//! key_path, +//! key_path::{GetPath, GetTypePath, field}, +//! type_info::{Typed, ScalarType}, +//! }; +//! +//! // Some complex nested data type. +//! #[derive(Reflect, Clone, Debug)] +//! struct User { +//! employer: Option, +//! } +//! +//! #[derive(Reflect, Clone, Debug)] +//! struct Company { +//! countries: Vec, +//! } +//! +//! #[derive(Reflect, Clone, Debug)] +//! struct Country { +//! name: String +//! } +//! +//! let user = User { +//! employer: Some(Company { +//! countries: vec![Country { +//! name: "Denmark".to_owned(), +//! }], +//! }), +//! }; +//! +//! // Build a key path that represents accessing `.employer::Some.0.countries[0].name`. +//! // +//! // `::Some` means to access the `Some` variant of `Option`. +//! let path = field("employer").variant("Some").field(0).field("countries").get(0).field("name"); +//! +//! // Get the value at the key path. +//! assert_eq!(user.get_at::(&path).unwrap(), "Denmark"); +//! +//! // Key paths can also be constructed using the `key_path!` macro. +//! // This invocation expands the same code we have above. +//! let path = key_path!(.employer::Some.0.countries[0].name); +//! +//! // Use the same key path to query type information. You don't need a value +//! // of the type to access its type information. +//! let user_type = ::type_info(); +//! assert!(matches!( +//! user_type.type_at(&path).unwrap().as_scalar().unwrap(), +//! ScalarType::String, +//! )); +//! ``` +//! +//! ## Using opaque `Value` types +//! +//! ``` +//! use mirror_mirror::{Reflect, Value, FromReflect}; +//! +//! #[derive(Reflect, Clone, Debug)] +//! struct Foo(Vec); +//! +//! # (|| { +//! let foo = Foo(vec![1, 2, 3]); +//! +//! // Convert `foo` into general "value" type. +//! let mut value: Value = foo.to_value(); +//! +//! // `Value` also implements `Reflect` so it can be mutated in the +//! // same way we've seen before. So these mutations can be made +//! // by another crate that doesn't know about the `Foo` type. +//! // +//! // `Value` is also serializable with `speedy`, for binary serialization, +//! // or `serde`, for everything else. +//! value +//! .as_tuple_struct_mut()? +//! .field_at_mut(0)? +//! .as_list_mut()? +//! .push(&4); +//! +//! // Convert the `value` back into a `Foo`. +//! let new_foo = Foo::from_reflect(&value)?; +//! +//! // Our changes were applied. +//! assert_eq!(new_foo.0, vec![1, 2, 3, 4]); +//! # Some(()) +//! # })().unwrap(); +//! ``` +//! +//! # Inspiration +//! +//! The design of this library is heavily inspired by [`bevy_reflect`] but with a few key +//! differences: +//! +//! - [`speedy`] integration which is useful for marshalling data perhaps to send it across FFI. +//! - A [`Value`] type that can be serialized and deserialized without using trait objects. +//! - More [type information][type_info] captured. +//! - Add meta data to types which becomes part of the type information. +//! - [Key paths][mod@key_path] for querying value and type information. +//! - No dependencies on [`bevy`] specific crates. +//! - `#![no_std]` support. +//! +//! # Feature flags +//! +//! mirror-mirror uses a set of [feature flags] to optionally reduce the number of dependencies. +//! +//! The following optional features are available: +//! +//! Name | Description | Default? +//! ---|---|--- +//! `std` | Enables using the standard library (`core` and `alloc` are always required) | Yes +//! `speedy` | Enables [`speedy`] support for most types | Yes +//! `serde` | Enables [`serde`] support for most types | Yes +//! +//! [`speedy`]: https://crates.io/crates/speedy +//! [`serde`]: https://crates.io/crates/serde +//! [`bevy_reflect`]: https://crates.io/crates/bevy_reflect +//! [`bevy`]: https://crates.io/crates/bevy + #![cfg_attr(not(feature = "std"), no_std)] #![warn( clippy::all, @@ -85,17 +298,40 @@ macro_rules! trivial_reflect_methods { }; } +/// Reflected array types. pub mod array; + +/// Reflected enum types. pub mod enum_; + +/// Helper traits for accessing fields on reflected values. pub mod get_field; + +/// Iterator types. pub mod iter; + +/// Key paths for querying value and type information. pub mod key_path; + +/// Reflected list types. pub mod list; + +/// Reflected map types. pub mod map; + +/// Reflected struct types. pub mod struct_; + +/// Reflected tuple types. pub mod tuple; + +/// Reflected tuple struct types. pub mod tuple_struct; + +/// Type information. pub mod type_info; + +/// Type erased value types. pub mod value; mod std_impls; @@ -132,6 +368,7 @@ pub use self::type_info::Typed; #[doc(inline)] pub use self::value::Value; +/// A reflected type. pub trait Reflect: Any + Send + 'static { fn type_info(&self) -> TypeRoot; @@ -433,10 +670,16 @@ impl<'a> From<&'a mut String> for ScalarMut<'a> { } } +/// A trait for types which can be constructed from a reflected type. +/// +/// Will be implemented by `#[derive(Reflect)]`. pub trait FromReflect: Reflect + Sized { fn from_reflect(reflect: &dyn Reflect) -> Option; } +/// An owned reflected value. +/// +/// Constructed with [`Reflect::reflect_owned`]. #[derive(Debug)] pub enum ReflectOwned { Struct(Box), @@ -533,6 +776,7 @@ impl Clone for ReflectOwned { } } +/// An owned reflected scalar type. #[derive(Debug, Clone)] #[allow(non_camel_case_types)] pub enum ScalarOwned { @@ -554,6 +798,9 @@ pub enum ScalarOwned { String(String), } +/// An immutable reflected value. +/// +/// Constructed with [`Reflect::reflect_ref`]. #[derive(Debug, Copy, Clone)] pub enum ReflectRef<'a> { Struct(&'a dyn Struct), @@ -634,6 +881,7 @@ impl<'a> ReflectRef<'a> { } } +/// An immutable reflected scalar value. #[derive(Debug, Copy, Clone)] #[allow(non_camel_case_types)] pub enum ScalarRef<'a> { @@ -655,6 +903,9 @@ pub enum ScalarRef<'a> { String(&'a str), } +/// A mutable reflected value. +/// +/// Constructed with [`Reflect::reflect_mut`]. #[derive(Debug)] pub enum ReflectMut<'a> { Struct(&'a mut dyn Struct), @@ -735,6 +986,7 @@ impl<'a> ReflectMut<'a> { } } +/// An mutable reflected scalar value. #[derive(Debug)] #[allow(non_camel_case_types)] pub enum ScalarMut<'a> { @@ -756,6 +1008,7 @@ pub enum ScalarMut<'a> { String(&'a mut String), } +/// Debug formatter for any reflection value. pub fn reflect_debug(value: &dyn Reflect, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn scalar_debug( scalar: &dyn core::fmt::Debug, diff --git a/crates/mirror-mirror/src/list.rs b/crates/mirror-mirror/src/list.rs index a2c9193..95e5314 100644 --- a/crates/mirror-mirror/src/list.rs +++ b/crates/mirror-mirror/src/list.rs @@ -4,6 +4,7 @@ use core::fmt; use crate::array::Array; use crate::Reflect; +/// A reflected list type. pub trait List: Array { fn push(&mut self, value: &dyn Reflect); diff --git a/crates/mirror-mirror/src/map.rs b/crates/mirror-mirror/src/map.rs index 9aeb0eb..0a63a4d 100644 --- a/crates/mirror-mirror/src/map.rs +++ b/crates/mirror-mirror/src/map.rs @@ -4,6 +4,17 @@ use core::fmt; use crate::iter::PairIterMut; use crate::Reflect; +/// A reflected map type. +/// +/// Note this is only implemented for [`BTreeMap`] and _not_ [`HashMap`] due to technical +/// limitations. +/// +/// [`BTreeMap`]: alloc::collections::BTreeMap +/// [`HashMap`]: std::collections::HashMap +// HashMap isn't supported because we need a `Value` variant for map values. The most obvious +// choice is `enum Value { Map(HashMap) }`. However now `Value` is used as the key in +// a `HashMap` so it most implement `Hash + Eq` but it can't since it contains a `HashMap` which +// doesn't implement `Hash + Eq`, because there is no stable iteration order. pub trait Map: Reflect { fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect>; diff --git a/crates/mirror-mirror/src/struct_.rs b/crates/mirror-mirror/src/struct_.rs index 25cab95..7f9625b 100644 --- a/crates/mirror-mirror/src/struct_.rs +++ b/crates/mirror-mirror/src/struct_.rs @@ -18,6 +18,9 @@ use crate::TypeRoot; use crate::Typed; use crate::Value; +/// A reflected struct type. +/// +/// Will be implemented by `#[derive(Reflect)]` on structs. pub trait Struct: Reflect { fn field(&self, name: &str) -> Option<&dyn Reflect>; diff --git a/crates/mirror-mirror/src/tuple.rs b/crates/mirror-mirror/src/tuple.rs index be9217d..a2d0430 100644 --- a/crates/mirror-mirror/src/tuple.rs +++ b/crates/mirror-mirror/src/tuple.rs @@ -19,6 +19,7 @@ use crate::TypeRoot; use crate::Typed; use crate::Value; +/// A reflected tuple type. pub trait Tuple: Reflect { fn field_at(&self, index: usize) -> Option<&dyn Reflect>; diff --git a/crates/mirror-mirror/src/tuple_struct.rs b/crates/mirror-mirror/src/tuple_struct.rs index 082457f..a10b694 100644 --- a/crates/mirror-mirror/src/tuple_struct.rs +++ b/crates/mirror-mirror/src/tuple_struct.rs @@ -17,6 +17,9 @@ use crate::TypeRoot; use crate::Typed; use crate::Value; +/// A reflected tuple struct type. +/// +/// Will be implemented by `#[derive(Reflect)]` on tuple structs. pub trait TupleStruct: Reflect { fn field_at(&self, index: usize) -> Option<&dyn Reflect>; diff --git a/crates/mirror-mirror/src/type_info/mod.rs b/crates/mirror-mirror/src/type_info/mod.rs index d87f43e..d726f9c 100644 --- a/crates/mirror-mirror/src/type_info/mod.rs +++ b/crates/mirror-mirror/src/type_info/mod.rs @@ -22,6 +22,9 @@ use crate::Value; pub mod graph; +/// Trait for accessing type information. +/// +/// Will be implemented by `#[derive(Reflect)]`. pub trait Typed: 'static { fn type_info() -> TypeRoot { let mut graph = TypeGraph::default(); @@ -32,6 +35,12 @@ pub trait Typed: 'static { fn build(graph: &mut TypeGraph) -> NodeId; } +/// The root of a type. +/// +/// Accessed via the [`Typed`] trait. +/// +/// `mirror-mirror` represents types as (possibly cyclic) graphs since types can contain +/// themselves. For example `struct Foo(Vec)`. #[derive(Debug, Clone)] #[cfg_attr(feature = "speedy", derive(speedy::Readable, speedy::Writable))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -96,6 +105,16 @@ impl<'a> GetTypePath<'a> for &'a TypeRoot { } } +impl<'a> GetMeta<'a> for &'a TypeRoot { + fn meta(self, key: &str) -> Option<&'a dyn Reflect> { + self.get_type().meta(key) + } + + fn docs(self) -> &'a [String] { + self.get_type().docs() + } +} + #[derive(Copy, Clone, Debug)] pub enum Type<'a> { Struct(StructType<'a>), @@ -446,6 +465,7 @@ mod private { pub trait Sealed {} + impl<'a> Sealed for &'a TypeRoot {} impl Sealed for Type<'_> {} impl Sealed for StructType<'_> {} impl Sealed for TupleStructType<'_> {} diff --git a/crates/mirror-mirror/src/value.rs b/crates/mirror-mirror/src/value.rs index bcab5be..d2be92d 100644 --- a/crates/mirror-mirror/src/value.rs +++ b/crates/mirror-mirror/src/value.rs @@ -27,6 +27,9 @@ use crate::ScalarRef; use crate::TypeRoot; use crate::Typed; +/// A type erased value type. +/// +/// Constructed with [`Reflect::to_value`]. #[allow(non_camel_case_types)] #[derive(Debug, Clone)] #[cfg_attr(feature = "speedy", derive(speedy::Readable, speedy::Writable))]