Crate mirror_mirror

Source
Expand description

General purpose reflection library for Rust.

§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::<i32>()?;

// Change the value of `x`
*x += 1;

// The value of `x` in `foo` has now changed.
assert_eq!(foo.x, 43);

§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"));

§Query value and type information using key paths

use mirror_mirror::{
    Reflect,
    key_path,
    key_path::{GetPath, GetTypePath, field},
    type_info::{DescribeType, ScalarType},
};

// Some complex nested data type.
#[derive(Reflect, Clone, Debug)]
struct User {
    employer: Option<Company>,
}

#[derive(Reflect, Clone, Debug)]
struct Company {
    countries: Vec<Country>,
}

#[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<Company>`.
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::<String>(&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 = <User as DescribeType>::type_descriptor();
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<i32>);

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]);

§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 captured.
  • Add meta data to types which becomes part of the type information.
  • Key paths 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:

NameDescriptionDefault?
stdEnables using the standard library (core and alloc are always required)Yes
speedyEnables speedy support for most typesYes
serdeEnables serde support for most typesYes
glamEnables impls for glamNo
macawEnables impls for macawNo

Modules§

array
Reflected array types.
enum_
Reflected enum types.
get_field
Helper traits for accessing fields on reflected values.
iter
Iterator types.
key_path
Key paths for querying value and type information.
list
Reflected list types.
map
Reflected map types.
struct_
Reflected struct types.
try_visit
tuple
Reflected tuple types.
tuple_struct
Reflected tuple struct types.
type_info
Type information.
value
Type erased value types.

Macros§

key_path
Convenience macro for creating KeyPaths.

Structs§

TypeDescriptor
The root of a type.

Enums§

ReflectMut
A mutable reflected value.
ReflectOwned
An owned reflected value.
ReflectRef
An immutable reflected value.
ScalarMut
An mutable reflected scalar value.
ScalarOwned
An owned reflected scalar type.
ScalarRef
An immutable reflected scalar value.
Value
A type erased value type.

Traits§

Array
A reflected array type.
DescribeType
Trait for accessing type information.
Enum
A reflected enum type.
FromReflect
A trait for types which can be constructed from a reflected type.
GetField
Helper trait for accessing and downcasting fields on reflected values.
GetFieldMut
Helper trait for mutably accessing and downcasting fields on reflected values.
List
A reflected list type.
Map
A reflected map type.
Reflect
A reflected type.
Struct
A reflected struct type.
Tuple
A reflected tuple type.
TupleStruct
A reflected tuple struct type.

Functions§

reflect_debug
Debug formatter for any reflection value.
reflect_eq
Compare two reflected values for equality.

Derive Macros§

Reflect
Derive an implementation of Reflect and other appropriate traits.