Derive Macro Reflect

Source
#[derive(Reflect)]
{
    // Attributes available to this derive:
    #[reflect]
}
Expand description

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<Self> {
        Some(Self(*value.downcast_ref::<i32>()?))
    }
}

§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<i32> {
    Some(*field.downcast_ref::<i32>()?)
}

§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, DescribeType},
};

#[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 = <Foo as DescribeType>::type_descriptor();

assert_eq!(
    type_info.get_meta::<String>("item_key").unwrap(),
    "item value",
);

assert_eq!(
    type_info
        .as_struct()
        .unwrap()
        .field_type("n")
        .unwrap()
        .get_meta::<i32>("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 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.