Skip to main content

ferro_class

Macro ferro_class 

Source
macro_rules! ferro_class {
    (@class_members $name:ident) => { ... };
    (@register_class $name:ident : $base:ident) => { ... };
    (@common $name:ident : $base:ident) => { ... };
    ($name:ident : $base:ident) => { ... };
    (
        $name:ident : $base:ident, virtuals $impl_trait:ident : $parent_impl:path {
            $(
                $(#[$meta:meta])*
                fn $method:ident(this $(, $arg:ident : $arg_ty:ty)* $(,)?) $(-> $ret:ty)?;
            )*
        }
    ) => { ... };
}
Expand description

Declares a class.

ⓘ
#[repr(C)]
pub struct Decorator { base: Control, /* fields */ }

// A class without new virtual members:
ferro_class!(Decorator: Control);

// A class that introduces virtual members:
ferro_class! {
    Layoutable: Visual, virtuals LayoutableImpl: VisualImpl {
        /// Measures the control.
        fn measure_override(this, available_size: Size) -> Size;
        fn arrange_override(this, final_size: Size) -> Size;
    }
}

Both forms generate Deref<Target = Base>, Upcast to every ancestor, the TYPE runtime type and ObjectType, including the static initialisation of the class (ObjectType::register_class). What the initialisation does is taken from the other declarations of the class, each optional and found by the macro without being named here:

  • ferro_properties! { impl Decorator { .. } }, the property definitions;
  • fn static_constructor(), an inherent function declared in the same module (ClassDefaults::static_constructor);
  • ferro_class_info!(Decorator { new: Decorator::new, interfaces: [..] }), the default constructor and the interface handles the class converts to.

The second form also generates:

  • LayoutableVTable, the table of the new members;
  • trait LayoutableImpl, with one associated function per member taking this: &Self. Every class deriving from Layoutable implements it (impl LayoutableImpl for Border {}) and overrides what it needs ([ferro_impl_classes!] and [ferro_overrides!] write the same implementation and state what it overrides, which shortens the calls);
  • LayoutableImplExt::parent_<member>, to call the base implementation from an override;
  • Layoutable::<member>(&self, ..), which performs the virtual call.

The declaring class must implement every member itself; these are the base implementations.