Skip to main content

ferroui_base/
type_system.rs

1//! Runtime type information and the class model of the object hierarchy.
2//!
3//! The framework is a deep single-inheritance class hierarchy with virtual
4//! members. It is modelled as follows:
5//!
6//! * A class is a `#[repr(C)]` struct whose first field, `base`, is its base
7//!   class. It derefs to the base, so inherited members are reached through
8//!   auto-deref with static dispatch and no runtime cost.
9//! * Objects live on the heap behind [`Ref<T>`], a reference-counted handle
10//!   that can be upcast to any base class for free and downcast with a runtime
11//!   check, like an object reference in a managed language.
12//! * Virtual members are declared once with [`ferro_class!`]. For each class
13//!   that introduces virtuals this generates a `<Class>Impl` trait whose
14//!   associated functions are the overridable members. A subclass overrides a
15//!   member by implementing the function; members it does not implement fall
16//!   through to the nearest base class that does, and an override can call
17//!   its base implementation with `parent_<member>`.
18//! * Dispatch goes through one per-class table of function pointers. An
19//!   object holds a single pointer to the table of its most-derived class.
20//! * The slot of a member a class does not override holds the implementation
21//!   the member falls through to, where the class states what it overrides
22//!   ([`ferro_impl_classes!`], [`ferro_overrides!`]); otherwise it holds a
23//!   function of the class that forwards to the table of its base class.
24//!
25//! All `unsafe` needed for this lives in this module and in the macros it
26//! exports, and rests on two invariants that the macros establish and check
27//! at compile time: a class struct starts with its base class at offset zero,
28//! and a class's virtual table starts with its base class's virtual table.
29
30use crate::metadata::{MarkupType, TypeOf};
31use crate::{FerroObject, FerroProperty};
32use std::any::{Any, TypeId};
33use std::collections::HashMap;
34use std::fmt;
35use std::hash::{Hash, Hasher};
36use std::marker::PhantomData;
37use std::ops::Deref;
38use std::rc::{Rc, Weak};
39use std::sync::{OnceLock, RwLock};
40
41/// Describes a class (or a non-instantiable type that owns attached
42/// properties): its name, where it is declared, its base class, how to
43/// initialise it and how to create an instance of it.
44///
45/// A `TypeInfo` is plain constant data, built by [`ferro_class!`] and
46/// [`ferro_static_type!`].
47pub struct TypeInfo {
48    name: &'static str,
49    base: Option<&'static TypeInfo>,
50    module_path: &'static str,
51    class_init: Option<fn()>,
52    constructor: Option<fn() -> Ref<FerroObject>>,
53    handles: Option<fn() -> [TypeId; 2]>,
54    handle_registration: Option<fn()>,
55    interfaces: &'static [TypeOf],
56    markup: Option<&'static MarkupType>,
57}
58
59impl TypeInfo {
60    pub const fn new(name: &'static str, base: Option<&'static TypeInfo>) -> Self {
61        Self {
62            name,
63            base,
64            module_path: "",
65            class_init: None,
66            constructor: None,
67            handles: None,
68            handle_registration: None,
69            interfaces: &[],
70            markup: None,
71        }
72    }
73
74    /// States the Rust module that declares the type (`module_path!()` at
75    /// the declaration). The markup-facing [`namespace`](Self::namespace) is
76    /// derived from it.
77    pub const fn with_module_path(mut self, module_path: &'static str) -> Self {
78        self.module_path = module_path;
79        self
80    }
81
82    /// Attaches the static initialisation of the type: a function that,
83    /// once per thread and after doing the same for the base type, registers
84    /// what the type declares (handle casts, property definitions) and runs
85    /// its static constructor.
86    ///
87    /// It is what lets code that only has the runtime type (a lookup of a
88    /// property by owner type and name) initialise a type that has no
89    /// instance yet.
90    pub const fn with_class_init(mut self, class_init: fn()) -> Self {
91        self.class_init = Some(class_init);
92        self
93    }
94
95    /// Attaches the default constructor of the class: the function that
96    /// creates an instance as its parameterless `new()` does.
97    pub const fn with_constructor(mut self, constructor: Option<fn() -> Ref<FerroObject>>) -> Self {
98        self.constructor = constructor;
99        self
100    }
101
102    /// States the Rust types of the handle of the class and of its nullable
103    /// form (`Ref<T>`, `Option<Ref<T>>`), which makes the class findable by
104    /// the type of a value ([`find_by_handle`](Self::find_by_handle)).
105    pub const fn with_handles(mut self, handles: fn() -> [TypeId; 2]) -> Self {
106        self.handles = Some(handles);
107        self
108    }
109
110    /// States the registration of the handle of the class with the untyped
111    /// value conversions
112    /// ([`ValueTypes::register_object`](crate::data::core::ValueTypes::register_object)
113    /// of the class): what makes `Ref<T>` an object handle and
114    /// `Option<Ref<T>>` its nullable form. The initialisation of the class
115    /// makes it on the thread that initialises the class; a class of a table
116    /// of types ([`register_all`](Self::register_all)) has it on every thread,
117    /// initialised or not, because a property of another class may hold the
118    /// null of its handle before anything creates an instance of it.
119    pub const fn with_handle_registration(mut self, handle_registration: fn()) -> Self {
120        self.handle_registration = Some(handle_registration);
121        self
122    }
123
124    /// States the interface handles the class declares
125    /// ([`ferro_class_info!`], `interfaces`).
126    pub const fn with_interfaces(mut self, interfaces: &'static [TypeOf]) -> Self {
127        self.interfaces = interfaces;
128        self
129    }
130
131    /// Attaches the markup metadata of the class ([`ferro_class_info!`],
132    /// `markup`).
133    pub const fn with_markup(mut self, markup: Option<&'static MarkupType>) -> Self {
134        self.markup = markup;
135        self
136    }
137
138    /// The class name, without namespace.
139    #[inline]
140    pub fn name(&self) -> &'static str {
141        self.name
142    }
143
144    /// The direct base class, if any.
145    #[inline]
146    pub fn base_type(&self) -> Option<&'static TypeInfo> {
147        self.base
148    }
149
150    /// The Rust module that declares the type, as `module_path!()` spells
151    /// it (`ferroui_base::media::solid_color_brush`). Empty for a type whose
152    /// runtime type was written by hand.
153    #[inline]
154    pub fn module_path(&self) -> &'static str {
155        self.module_path
156    }
157
158    /// The dotted, markup-facing namespace of the type (`FerroUI.Media`).
159    ///
160    /// Namespaces are declared once per module, not per class: a crate maps
161    /// its module paths to namespaces with [`TypeInfo::register_namespaces`]
162    /// (from its `register_types()` function), and the namespace of a type
163    /// is the one registered for the longest prefix of its
164    /// [`module_path`](Self::module_path). Empty when no prefix is
165    /// registered.
166    pub fn namespace(&self) -> &'static str {
167        let registry = read_registry();
168        registry.namespace_of(self.module_path)
169    }
170
171    /// The dotted namespace registered for a Rust module path; see
172    /// [`namespace`](Self::namespace).
173    pub fn namespace_of_module(module_path: &str) -> &'static str {
174        read_registry().namespace_of(module_path)
175    }
176
177    /// The namespace-qualified name of the type (`FerroUI.Media.Brush`).
178    pub fn full_name(&self) -> String {
179        match self.namespace() {
180            "" => self.name.to_string(),
181            namespace => format!("{namespace}.{}", self.name),
182        }
183    }
184
185    /// Whether the type has a static initialisation of its own
186    /// ([`with_class_init`](Self::with_class_init)).
187    #[cfg(feature = "compiler-metadata")]
188    pub(crate) fn has_class_init(&self) -> bool {
189        self.class_init.is_some()
190    }
191
192    /// Ensures the static initialisation of the type and of its base types
193    /// has run on the current thread: handle casts and property definitions
194    /// are registered (properties in declaration order) and the static
195    /// constructors have run, base types first. Does nothing after the first
196    /// call on a thread.
197    ///
198    /// Called when the first instance of a class is created, when a property
199    /// accessor of the type is first called and by the property registry when
200    /// it is asked about the type; call it directly where the static
201    /// constructor of a type must have run before none of these happened.
202    #[inline]
203    pub fn ensure_class_init(&self) {
204        let mut current = Some(self);
205        while let Some(type_) = current {
206            if let Some(class_init) = type_.class_init {
207                // An initialiser initialises its base types itself.
208                class_init();
209                return;
210            }
211            current = type_.base;
212        }
213    }
214
215    /// The default constructor of the class, if it declares one (see
216    /// [`ferro_class_info!`]): creates an instance as the parameterless
217    /// `new()` of the class does.
218    #[inline]
219    pub fn default_constructor(&self) -> Option<fn() -> Ref<FerroObject>> {
220        self.constructor
221    }
222
223    /// Creates an instance with the default constructor of the class.
224    /// `None` if the class has none (abstract classes, classes that need
225    /// constructor arguments, non-instantiable types).
226    pub fn create_instance(&self) -> Option<Ref<FerroObject>> {
227        self.constructor.map(|constructor| constructor())
228    }
229
230    /// The Rust type of the handle of the class (`Ref<T>`). `None` for types
231    /// that are not classes.
232    pub fn handle(&self) -> Option<TypeId> {
233        self.handles.map(|handles| handles()[0])
234    }
235
236    /// The Rust type of the nullable handle of the class (`Option<Ref<T>>`).
237    pub fn nullable_handle(&self) -> Option<TypeId> {
238        self.handles.map(|handles| handles()[1])
239    }
240
241    /// The interface handles the class itself declares with
242    /// [`ferro_class_info!`] (not the ones of its base classes).
243    #[inline]
244    pub fn interfaces(&self) -> &'static [TypeOf] {
245        self.interfaces
246    }
247
248    /// The markup metadata the class itself declares with
249    /// [`ferro_class_info!`]: its content property, plain properties,
250    /// methods, events and attributes. `None` for a class that declares
251    /// none; the metadata of its base classes still applies to it.
252    #[inline]
253    pub fn markup(&self) -> Option<&'static MarkupType> {
254        self.markup
255    }
256
257    /// The name of the content property of the class: the one it declares,
258    /// or else the one of the nearest base class that declares one.
259    pub fn content_property(&self) -> Option<&'static str> {
260        let mut current = Some(self);
261        while let Some(type_) = current {
262            if let Some(content) = type_.markup.and_then(|m| m.content_property) {
263                return Some(content);
264            }
265            current = type_.base;
266        }
267        None
268    }
269
270    /// The properties registered on the type and its base types (styled,
271    /// direct and the attached properties the type owns), each type's in
272    /// declaration order, most derived type first. Initialises the type if
273    /// needed, so no instance has to exist.
274    pub fn properties(&'static self) -> Rc<Vec<&'static FerroProperty>> {
275        crate::FerroPropertyRegistry::instance().get_registered(self)
276    }
277
278    /// Finds a property registered on the type or its base types by name.
279    /// Initialises the type if needed.
280    pub fn find_property(&'static self, name: &str) -> Option<&'static FerroProperty> {
281        crate::FerroPropertyRegistry::instance().find_registered(self, name)
282    }
283
284    /// Adds a type to the process-wide table of known types, making it
285    /// discoverable with [`find`](Self::find) and
286    /// [`find_by_name`](Self::find_by_name). Registering a type again does
287    /// nothing.
288    ///
289    /// Types register themselves when they are initialised on a thread; a
290    /// crate's `register_types()` function registers all of its types up
291    /// front so that types that were never used are known too.
292    pub fn register(type_: &'static TypeInfo) {
293        if read_registry().contains(type_) {
294            return;
295        }
296        write_registry().insert(type_);
297        // As for the types of a table: see `register_all`.
298        if let Some(handle_registration) = type_.handle_registration {
299            crate::data::core::ValueTypes::register_global(handle_registration);
300        }
301    }
302
303    /// Registers several types; see [`register`](Self::register).
304    ///
305    /// The handle of each class is registered with the untyped value
306    /// conversions of every thread as well
307    /// ([`with_handle_registration`](Self::with_handle_registration)), when
308    /// the thread next converts an untyped value: the nullable form of the
309    /// handle of a class of a table is known whether or not the class has
310    /// been initialised. A property typed with the handle of another class
311    /// holds its null from the start (`Control.ContextMenu`), and what reads
312    /// that value untyped (a binding, markup) must see null. The run-time
313    /// XAML loader initialises a class when it reads it, which hid the
314    /// difference; compiled markup names a class without initialising it.
315    pub fn register_all(types: &[&'static TypeInfo]) {
316        {
317            let mut registry = write_registry();
318            for type_ in types {
319                registry.insert(type_);
320            }
321        }
322        for type_ in types {
323            if let Some(handle_registration) = type_.handle_registration {
324                crate::data::core::ValueTypes::register_global(handle_registration);
325            }
326        }
327    }
328
329    /// Declares the namespaces of a crate's modules: pairs of a Rust module
330    /// path (`"ferroui_base::media"`) and the dotted namespace of the types
331    /// declared in that module and its submodules (`"FerroUI.Media"`). A
332    /// longer module path overrides a shorter one, down to a single file.
333    pub fn register_namespaces(namespaces: &[(&'static str, &'static str)]) {
334        let mut registry = write_registry();
335        for &(module_path, namespace) in namespaces {
336            match registry.namespaces.iter_mut().find(|(m, _)| *m == module_path) {
337                Some(entry) => entry.1 = namespace,
338                None => registry.namespaces.push((module_path, namespace)),
339            }
340        }
341    }
342
343    #[cfg(feature = "compiler-metadata")]
344    /// Declares the public Rust paths of classes: pairs of a class and the
345    /// path another crate names it by (`"ferroui_controls::Border"`). The
346    /// declaring module ([`module_path`](Self::module_path)) is often
347    /// private, so the path cannot be derived from it; a crate records the
348    /// table of its generated `rust_paths.rs` ([`ferro_rust_paths!`](crate::ferro_rust_paths))
349    /// in its `register_types()`. The emitter of Rust source reads them;
350    /// nothing else does.
351    pub fn register_rust_paths(paths: &[(&'static TypeInfo, &'static str)]) {
352        let mut registry = write_registry();
353        for &(type_, path) in paths {
354            registry.rust_paths.insert(type_ as *const TypeInfo as usize, (type_, path));
355        }
356    }
357
358    #[cfg(feature = "compiler-metadata")]
359    /// The public Rust path of the class
360    /// ([`register_rust_paths`](Self::register_rust_paths)), if its crate
361    /// recorded one.
362    pub fn rust_path(&'static self) -> Option<&'static str> {
363        read_registry().rust_paths.get(&(self as *const TypeInfo as usize)).map(|entry| entry.1)
364    }
365
366    #[cfg(feature = "compiler-metadata")]
367    /// Every class with a registered public Rust path, with the path, in no
368    /// particular order.
369    pub fn all_rust_paths() -> Vec<(&'static TypeInfo, &'static str)> {
370        read_registry().rust_paths.values().copied().collect()
371    }
372
373    /// Finds a known type by namespace and name.
374    pub fn find(namespace: &str, name: &str) -> Option<&'static TypeInfo> {
375        let registry = read_registry();
376        let candidates = registry.by_name.get(name)?;
377        candidates.iter().copied().find(|t| registry.namespace_of(t.module_path) == namespace)
378    }
379
380    /// Finds the known class whose handle (`Ref<T>`) or nullable handle
381    /// (`Option<Ref<T>>`) is the Rust type `handle`. The flag tells whether
382    /// it is the nullable handle.
383    pub fn find_by_handle(handle: TypeId) -> Option<(&'static TypeInfo, bool)> {
384        read_registry().by_handle.get(&handle).copied()
385    }
386
387    /// Finds a known type by name alone. `None` if no type or more than one
388    /// type (in different namespaces) has the name.
389    pub fn find_by_name(name: &str) -> Option<&'static TypeInfo> {
390        let registry = read_registry();
391        match registry.by_name.get(name)?.as_slice() {
392            [type_] => Some(type_),
393            _ => None,
394        }
395    }
396
397    /// Every known type, in registration order.
398    pub fn registered_types() -> Vec<&'static TypeInfo> {
399        read_registry().types.clone()
400    }
401
402    /// Returns true if `other` is this type or derives from it.
403    pub fn is_assignable_from(&self, other: &TypeInfo) -> bool {
404        let mut current = Some(other);
405        while let Some(t) = current {
406            if std::ptr::eq(self, t) {
407                return true;
408            }
409            current = t.base;
410        }
411        false
412    }
413
414    /// Returns true if this type is `other` or derives from it.
415    #[inline]
416    pub fn is_subclass_of(&self, other: &TypeInfo) -> bool {
417        other.is_assignable_from(self)
418    }
419}
420
421impl PartialEq for TypeInfo {
422    #[inline]
423    fn eq(&self, other: &Self) -> bool {
424        std::ptr::eq(self, other)
425    }
426}
427
428impl Eq for TypeInfo {}
429
430impl Hash for TypeInfo {
431    fn hash<H: Hasher>(&self, state: &mut H) {
432        (self as *const TypeInfo as usize).hash(state)
433    }
434}
435
436impl fmt::Debug for TypeInfo {
437    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
438        f.write_str(self.name)
439    }
440}
441
442impl fmt::Display for TypeInfo {
443    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444        f.write_str(self.name)
445    }
446}
447
448/// The process-wide table of known types. Runtime types are immutable
449/// statics, so unlike the property registry the table is not per thread.
450#[derive(Default)]
451struct TypeRegistry {
452    types: Vec<&'static TypeInfo>,
453    by_name: HashMap<&'static str, Vec<&'static TypeInfo>>,
454    by_handle: HashMap<TypeId, (&'static TypeInfo, bool)>,
455    namespaces: Vec<(&'static str, &'static str)>,
456    /// The public Rust paths of classes, by the address of their type.
457    #[cfg(feature = "compiler-metadata")]
458    rust_paths: HashMap<usize, (&'static TypeInfo, &'static str)>,
459}
460
461impl TypeRegistry {
462    fn contains(&self, type_: &'static TypeInfo) -> bool {
463        self.by_name.get(type_.name).is_some_and(|types| types.iter().any(|t| std::ptr::eq(*t, type_)))
464    }
465
466    fn insert(&mut self, type_: &'static TypeInfo) {
467        if !self.contains(type_) {
468            self.types.push(type_);
469            self.by_name.entry(type_.name).or_default().push(type_);
470            if let Some(handles) = type_.handles {
471                let [handle, nullable] = handles();
472                self.by_handle.insert(handle, (type_, false));
473                self.by_handle.insert(nullable, (type_, true));
474            }
475        }
476    }
477
478    fn namespace_of(&self, module_path: &str) -> &'static str {
479        let mut best: Option<(&'static str, &'static str)> = None;
480        for &(prefix, namespace) in &self.namespaces {
481            let matches = match module_path.strip_prefix(prefix) {
482                Some(rest) => rest.is_empty() || rest.starts_with("::"),
483                None => false,
484            };
485            if matches && best.is_none_or(|(b, _)| prefix.len() > b.len()) {
486                best = Some((prefix, namespace));
487            }
488        }
489        best.map_or("", |(_, namespace)| namespace)
490    }
491}
492
493fn type_registry() -> &'static RwLock<TypeRegistry> {
494    static REGISTRY: OnceLock<RwLock<TypeRegistry>> = OnceLock::new();
495    REGISTRY.get_or_init(Default::default)
496}
497
498fn read_registry() -> std::sync::RwLockReadGuard<'static, TypeRegistry> {
499    type_registry().read().unwrap_or_else(|e| e.into_inner())
500}
501
502fn write_registry() -> std::sync::RwLockWriteGuard<'static, TypeRegistry> {
503    type_registry().write().unwrap_or_else(|e| e.into_inner())
504}
505
506/// A Rust type with an associated runtime [`TypeInfo`].
507///
508/// Implemented by all classes ([`ferro_class!`]) and by non-instantiable
509/// types that own attached properties ([`ferro_static_type!`]).
510pub trait StaticType: 'static {
511    /// The runtime type.
512    const TYPE: &'static TypeInfo;
513}
514
515/// What a type declares when it declares nothing: no default constructor,
516/// no interface casts, no properties and an empty static constructor.
517///
518/// The class macros read the declarations of a type through the names below.
519/// A type that declares one of them does so with an inherent item of the
520/// same name (written by hand for [`static_constructor`](Self::static_constructor),
521/// generated by [`ferro_properties!`](crate::ferro_properties) and
522/// [`ferro_class_info!`] for the others), which takes precedence over this
523/// trait; every other type falls back to it.
524pub trait ClassDefaults {
525    #[doc(hidden)]
526    const __CONSTRUCTOR: Option<fn() -> Ref<FerroObject>> = None;
527
528    #[doc(hidden)]
529    const __INTERFACES: &'static [TypeOf] = &[];
530
531    #[doc(hidden)]
532    const __MARKUP: Option<&'static MarkupType> = None;
533
534    #[doc(hidden)]
535    #[inline]
536    fn __register_interfaces() {}
537
538    #[doc(hidden)]
539    #[inline]
540    fn __register_properties() {}
541
542    /// The static constructor of a type: work done once per thread, after
543    /// the properties of the type are registered and before its first
544    /// instance exists (class handlers, `affects_render`, metadata
545    /// overrides).
546    ///
547    /// A class declares it as an inherent function in the module of its
548    /// `ferro_class!`:
549    ///
550    /// ```ignore
551    /// impl Border {
552    ///     fn static_constructor() {
553    ///         Self::affects_render::<Border>(&[Self::background_property().as_property()]);
554    ///     }
555    /// }
556    /// ```
557    ///
558    /// It is never called by hand: the class initialisation calls it. Use
559    /// `Border::TYPE.ensure_class_init()` to force the initialisation.
560    #[inline]
561    fn static_constructor() {}
562}
563
564impl<T: ?Sized> ClassDefaults for T {}
565
566/// The part of a class initialisation that is the same for every class:
567/// makes the type known by name and registers its handle type `Ref<T>` with
568/// the untyped value conversions (as an object handle that casts to the
569/// handles of its base classes and to its nullable form). The conversions
570/// are registered when the thread first uses untyped conversions.
571#[doc(hidden)]
572#[cold]
573pub fn __register_class<T: ObjectType>() {
574    TypeInfo::register(T::TYPE);
575    crate::data::core::ValueTypes::register_deferred(crate::data::core::ValueTypes::register_object::<T>);
576}
577
578/// Access to the embedded base-class data of an object.
579///
580/// Implemented by [`ferro_class!`] for every ancestor of a class, so
581/// `T: Upcast<U>` reads as "`T` is `U` or derives from it".
582pub trait Upcast<T: ?Sized> {
583    fn upcast(&self) -> &T;
584}
585
586/// Implemented by every class.
587///
588/// # Safety
589///
590/// Implemented only by [`ferro_class!`] (and by hand for the root class).
591/// Implementors guarantee that:
592///
593/// * `Self` is `#[repr(C)]`-compatible with `Parent` at offset zero, i.e. a
594///   pointer to `Self` is a valid pointer to every class in its ancestor
595///   chain;
596/// * `VTable` likewise starts with `Parent::VTable` at offset zero;
597/// * values of `Self` are only created through [`instantiate`] (class structs
598///   have a private `base` field and `construct`-style constructors that are
599///   only meaningful inside `instantiate`).
600pub unsafe trait ObjectType: StaticType + Upcast<FerroObject> + Sized {
601    /// The base class. The root class is its own parent.
602    type Parent: ObjectType;
603
604    /// The virtual table of the class.
605    type VTable: Copy + 'static;
606
607    /// The virtual table used by instances whose most-derived class is `Self`.
608    fn vtable() -> &'static Self::VTable;
609
610    /// The static initialisation of the class. The first call on a thread,
611    /// after doing the same for the base class:
612    ///
613    /// 1. makes the type known by name ([`TypeInfo::find`]);
614    /// 2. registers the handle type `Ref<Self>` and the interface handles the
615    ///    class declares ([`ferro_class_info!`]) with the untyped value
616    ///    conversions;
617    /// 3. registers the properties of the class in declaration order
618    ///    ([`ferro_properties!`](crate::ferro_properties));
619    /// 4. runs the static constructor of the class
620    ///    ([`ClassDefaults::static_constructor`]).
621    ///
622    /// Later calls only read a thread-local flag.
623    ///
624    /// Generated by `ferro_class!`. Called by [`instantiate`], so a class
625    /// that has an instance on the thread is initialised, and through
626    /// [`TypeInfo::ensure_class_init`] by property accessors and the property
627    /// registry, for classes that have none.
628    fn register_class();
629}
630
631/// Implemented by a class `C` for every class `T` that can derive from it:
632/// builds `C`'s part of the virtual table with `T`'s overrides.
633pub trait Subclassable<T>: ObjectType {
634    #[doc(hidden)]
635    fn build_vtable() -> Self::VTable;
636}
637
638/// Reinterprets a reference to base class data as a reference to the derived
639/// class `T`.
640///
641/// # Safety
642///
643/// `base` must be the base-class part of an object whose most-derived class
644/// is `T` or derives from `T`.
645#[doc(hidden)]
646#[inline(always)]
647pub unsafe fn cast_this<B, T>(base: &B) -> &T {
648    &*(base as *const B as *const T)
649}
650
651/// Returns the virtual table of `T`'s parent class, viewed as the table type
652/// `V` of the class that introduced the member being called.
653///
654/// Panics if the parent class has no `V`, i.e. when the class that introduced
655/// a virtual member did not implement it itself.
656#[doc(hidden)]
657#[inline]
658pub fn parent_vtable<T: ObjectType, V>() -> &'static V {
659    // A parent class that is an ancestor of the class owning `V` has a
660    // strictly smaller table (the owner adds at least the member being
661    // called), so this check is exact. It is constant per instantiation.
662    assert!(
663        std::mem::size_of::<<T::Parent as ObjectType>::VTable>() >= std::mem::size_of::<V>(),
664        "virtual member has no base implementation"
665    );
666    let table: *const <T::Parent as ObjectType>::VTable = <T::Parent as ObjectType>::vtable();
667    // SAFETY: by the size argument above the parent class is the owner of `V`
668    // or derives from it, and `ObjectType` guarantees that a class's table
669    // starts with the tables of all of its ancestors.
670    unsafe { &*(table as *const V) }
671}
672
673/// Whether the slot of `member` in the table of `T` takes the slot of the
674/// table of `T`'s parent class, instead of a function of `T` that forwards
675/// to it. `V` is the table of the class that introduced the member.
676///
677/// `overrides` is what the implementation of `T` states about itself
678/// (`__OVERRIDES` of the implementation trait): `None` when it states
679/// nothing, else the names of the members it overrides. A member that is
680/// not among them has the default of the implementation trait, which calls
681/// the same slot of the parent table and does nothing else, so the slot of
682/// the parent is the same implementation with one call less.
683///
684/// The slot is not taken where the parent class has no table `V`: the class
685/// that introduced a member has to implement it, and its default panics
686/// when it is called (see [`parent_vtable`]), not when the table is built.
687///
688/// A constant function: the tables evaluate it when the class is compiled,
689/// so a table is built without comparing names and the forwarding function
690/// of a slot that is taken from the parent is not referenced.
691#[doc(hidden)]
692pub const fn __forwards_to_parent<T: ObjectType, V>(
693    overrides: Option<&'static [&'static str]>,
694    member: &str,
695) -> bool {
696    let overrides = match overrides {
697        Some(overrides) => overrides,
698        None => return false,
699    };
700    if std::mem::size_of::<<T::Parent as ObjectType>::VTable>() < std::mem::size_of::<V>() {
701        return false;
702    }
703    let member = member.as_bytes();
704    let mut index = 0;
705    while index < overrides.len() {
706        let name = overrides[index].as_bytes();
707        if name.len() == member.len() {
708            let mut at = 0;
709            while at < name.len() && name[at] == member[at] {
710                at += 1;
711            }
712            if at == name.len() {
713                return false;
714            }
715        }
716        index += 1;
717    }
718    true
719}
720
721/// A strong reference to an object of class `T` or a class derived from it.
722///
723/// Cloning the handle shares the object. Equality and hashing are by object
724/// identity.
725#[repr(transparent)]
726pub struct Ref<T: ObjectType> {
727    ptr: Rc<dyn Any>,
728    _marker: PhantomData<T>,
729}
730
731impl<T: ObjectType> Ref<T> {
732    /// Converts the handle to a handle of a base class.
733    #[inline]
734    pub fn upcast<U: ObjectType>(self) -> Ref<U>
735    where
736        T: Upcast<U>,
737    {
738        Ref { ptr: self.ptr, _marker: PhantomData }
739    }
740
741    /// Borrows the handle as a handle of a base class, without a copy of the
742    /// handle (the borrowing form of [`upcast`](Self::upcast)).
743    #[inline]
744    pub fn upcast_ref<U: ObjectType>(&self) -> &Ref<U>
745    where
746        T: Upcast<U>,
747    {
748        // SAFETY: `Ref` is `repr(transparent)` over its `Rc<dyn Any>`; the
749        // marker is zero-sized, so `Ref<T>` and `Ref<U>` have the same layout
750        // and the same valid values, and `T: Upcast<U>` makes the object a `U`,
751        // which is exactly what `upcast` asserts for an owned handle.
752        unsafe { &*(self as *const Ref<T> as *const Ref<U>) }
753    }
754
755    /// Returns a handle of class `U` if the object is a `U`.
756    #[inline]
757    pub fn cast<U: ObjectType>(&self) -> Option<Ref<U>> {
758        if self.is::<U>() {
759            Some(Ref { ptr: self.ptr.clone(), _marker: PhantomData })
760        } else {
761            None
762        }
763    }
764
765    /// Converts the handle to class `U` if the object is a `U`, otherwise
766    /// returns the handle unchanged.
767    #[inline]
768    pub fn downcast<U: ObjectType>(self) -> Result<Ref<U>, Self> {
769        if self.is::<U>() {
770            Ok(Ref { ptr: self.ptr, _marker: PhantomData })
771        } else {
772            Err(self)
773        }
774    }
775
776    /// Whether the object is of class `U` or a class derived from it.
777    #[inline]
778    pub fn is<U: ObjectType>(&self) -> bool {
779        let object: &FerroObject = (**self).upcast();
780        U::TYPE.is_assignable_from(object.get_type())
781    }
782
783    /// Creates a weak reference to the object.
784    #[inline]
785    pub fn downgrade(&self) -> WeakRef<T> {
786        WeakRef::of(Rc::downgrade(&self.ptr))
787    }
788
789    /// Whether two handles refer to the same object.
790    #[inline]
791    pub fn ptr_eq<U: ObjectType>(&self, other: &Ref<U>) -> bool {
792        std::ptr::addr_eq(Rc::as_ptr(&self.ptr), Rc::as_ptr(&other.ptr))
793    }
794
795    /// The number of handles to the object, the number of weak handles to it and its address:
796    /// what a leak test says of an object that survived its scenario. For tests only.
797    #[cfg(feature = "testing")]
798    #[doc(hidden)]
799    pub fn reference_counts(&self) -> (usize, usize, usize) {
800        (Rc::strong_count(&self.ptr), Rc::weak_count(&self.ptr), Rc::as_ptr(&self.ptr) as *const () as usize)
801    }
802
803    #[inline]
804    pub(crate) fn from_rc(ptr: Rc<dyn Any>) -> Self {
805        Ref { ptr, _marker: PhantomData }
806    }
807}
808
809impl<T: ObjectType> Deref for Ref<T> {
810    type Target = T;
811
812    #[inline]
813    fn deref(&self) -> &T {
814        // SAFETY: a `Ref<T>` is only created by `instantiate` (for the exact
815        // class), by `upcast` (statically an ancestor) and by `cast` /
816        // `downcast` / `FerroObject::to_ref` (after a runtime type check), so
817        // the allocation holds an object whose class is `T` or derives from
818        // it, and `ObjectType` guarantees `T` is at offset zero of it.
819        unsafe { &*(Rc::as_ptr(&self.ptr) as *const T) }
820    }
821}
822
823impl<T: ObjectType> Clone for Ref<T> {
824    #[inline]
825    fn clone(&self) -> Self {
826        Ref { ptr: self.ptr.clone(), _marker: PhantomData }
827    }
828}
829
830impl<T: ObjectType, U: ObjectType> PartialEq<Ref<U>> for Ref<T> {
831    #[inline]
832    fn eq(&self, other: &Ref<U>) -> bool {
833        self.ptr_eq(other)
834    }
835}
836
837impl<T: ObjectType> Eq for Ref<T> {}
838
839impl<T: ObjectType> Hash for Ref<T> {
840    fn hash<H: Hasher>(&self, state: &mut H) {
841        (Rc::as_ptr(&self.ptr) as *const () as usize).hash(state)
842    }
843}
844
845impl<T: ObjectType> fmt::Debug for Ref<T> {
846    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
847        let object: &FerroObject = (**self).upcast();
848        fmt::Debug::fmt(object, f)
849    }
850}
851
852/// The word that follows the pointer of every [`WeakRef`] in a build with the
853/// feature `tagged-weak-references`: a reader of the memory of the process
854/// (the allocation trace of the tests of the ControlCatalog) tells a weak
855/// reference to an object from a strong one by it.
856#[cfg(feature = "tagged-weak-references")]
857pub const WEAK_REFERENCE_TAG: usize = 0x5745_414B_5245_4631_u64 as usize;
858
859/// A weak reference to an object of class `T` or a class derived from it.
860#[cfg_attr(feature = "tagged-weak-references", repr(C))]
861pub struct WeakRef<T: ObjectType> {
862    ptr: Weak<dyn Any>,
863    #[cfg(feature = "tagged-weak-references")]
864    tag: usize,
865    _marker: PhantomData<T>,
866}
867
868impl<T: ObjectType> WeakRef<T> {
869    #[inline]
870    fn of(ptr: Weak<dyn Any>) -> Self {
871        WeakRef {
872            ptr,
873            #[cfg(feature = "tagged-weak-references")]
874            tag: WEAK_REFERENCE_TAG,
875            _marker: PhantomData,
876        }
877    }
878}
879
880impl<T: ObjectType> WeakRef<T> {
881    /// Returns a strong reference if the object is still alive.
882    #[inline]
883    pub fn upgrade(&self) -> Option<Ref<T>> {
884        self.ptr.upgrade().map(|ptr| Ref { ptr, _marker: PhantomData })
885    }
886
887    /// Converts the handle to a handle of a base class.
888    #[inline]
889    pub fn upcast<U: ObjectType>(self) -> WeakRef<U>
890    where
891        T: Upcast<U>,
892    {
893        WeakRef::of(self.ptr)
894    }
895
896    /// Whether the weak reference points at `object`.
897    #[inline]
898    pub fn points_to<U: ObjectType>(&self, object: &Ref<U>) -> bool {
899        std::ptr::addr_eq(self.ptr.as_ptr(), Rc::as_ptr(&object.ptr))
900    }
901
902    /// Whether the weak reference points at `object` (which, being borrowed, is alive).
903    #[inline]
904    pub(crate) fn points_at(&self, object: &T) -> bool {
905        std::ptr::addr_eq(self.ptr.as_ptr(), object as *const T)
906    }
907
908    /// Whether two weak references point at the same object, alive or not.
909    #[inline]
910    pub fn ptr_eq<U: ObjectType>(&self, other: &WeakRef<U>) -> bool {
911        std::ptr::addr_eq(self.ptr.as_ptr(), other.ptr.as_ptr())
912    }
913
914    #[inline]
915    pub(crate) fn from_weak(ptr: Weak<dyn Any>) -> Self {
916        WeakRef::of(ptr)
917    }
918}
919
920impl<T: ObjectType> Clone for WeakRef<T> {
921    #[inline]
922    fn clone(&self) -> Self {
923        WeakRef::of(self.ptr.clone())
924    }
925}
926
927/// An optional object reference accepted by setters, convertible from a
928/// handle (or a borrowed handle) of any derived class and from `None`.
929pub struct Nullable<T: ObjectType>(pub Option<Ref<T>>);
930
931impl<T: ObjectType + Upcast<U>, U: ObjectType> From<Ref<T>> for Nullable<U> {
932    #[inline]
933    fn from(value: Ref<T>) -> Self {
934        Nullable(Some(value.upcast()))
935    }
936}
937
938impl<T: ObjectType + Upcast<U>, U: ObjectType> From<&Ref<T>> for Nullable<U> {
939    #[inline]
940    fn from(value: &Ref<T>) -> Self {
941        Nullable(Some(value.clone().upcast()))
942    }
943}
944
945impl<U: ObjectType> From<Option<Ref<U>>> for Nullable<U> {
946    #[inline]
947    fn from(value: Option<Ref<U>>) -> Self {
948        Nullable(value)
949    }
950}
951
952/// A non-optional object reference accepted by methods, convertible from a
953/// handle (or a borrowed handle) of any derived class.
954pub trait IntoRef<U: ObjectType> {
955    fn into_ref(self) -> Ref<U>;
956}
957
958impl<T: ObjectType + Upcast<U>, U: ObjectType> IntoRef<U> for Ref<T> {
959    #[inline]
960    fn into_ref(self) -> Ref<U> {
961        self.upcast()
962    }
963}
964
965impl<T: ObjectType + Upcast<U>, U: ObjectType> IntoRef<U> for &Ref<T> {
966    #[inline]
967    fn into_ref(self) -> Ref<U> {
968        self.clone().upcast()
969    }
970}
971
972/// Moves a constructed class value to the heap, attaches the virtual table of
973/// its class and runs the `constructed` virtual member. The class (and its
974/// base classes) are initialised first if this is the first instance on the
975/// thread; see [`ObjectType::register_class`].
976pub fn instantiate<T: ObjectType>(value: T) -> Ref<T> {
977    T::register_class();
978    let ptr: Rc<dyn Any> = Rc::new(value);
979    let result: Ref<T> = Ref { ptr, _marker: PhantomData };
980    let object: &FerroObject = (*result).upcast();
981    let table: *const T::VTable = T::vtable();
982    // SAFETY: `T::VTable` starts with the root class's table (`ObjectType`
983    // invariant), and the object's most-derived class is `T`.
984    unsafe { object.attach(Rc::downgrade(&result.ptr), table as *const ()) };
985    object.constructed();
986    result
987}
988
989/// Declares a class.
990///
991/// ```ignore
992/// #[repr(C)]
993/// pub struct Decorator { base: Control, /* fields */ }
994///
995/// // A class without new virtual members:
996/// ferro_class!(Decorator: Control);
997///
998/// // A class that introduces virtual members:
999/// ferro_class! {
1000///     Layoutable: Visual, virtuals LayoutableImpl: VisualImpl {
1001///         /// Measures the control.
1002///         fn measure_override(this, available_size: Size) -> Size;
1003///         fn arrange_override(this, final_size: Size) -> Size;
1004///     }
1005/// }
1006/// ```
1007///
1008/// Both forms generate `Deref<Target = Base>`, [`Upcast`] to every ancestor,
1009/// the `TYPE` runtime type and [`ObjectType`], including the static
1010/// initialisation of the class ([`ObjectType::register_class`]). What the
1011/// initialisation does is taken from the other declarations of the class,
1012/// each optional and found by the macro without being named here:
1013///
1014/// * `ferro_properties! { impl Decorator { .. } }`, the property definitions;
1015/// * `fn static_constructor()`, an inherent function declared in the same
1016///   module ([`ClassDefaults::static_constructor`]);
1017/// * `ferro_class_info!(Decorator { new: Decorator::new, interfaces: [..] })`,
1018///   the default constructor and the interface handles the class converts
1019///   to.
1020///
1021/// The second form also generates:
1022///
1023/// * `LayoutableVTable`, the table of the new members;
1024/// * `trait LayoutableImpl`, with one associated function per member taking
1025///   `this: &Self`. Every class deriving from `Layoutable` implements it
1026///   (`impl LayoutableImpl for Border {}`) and overrides what it needs
1027///   ([`ferro_impl_classes!`] and [`ferro_overrides!`] write the same
1028///   implementation and state what it overrides, which shortens the calls);
1029/// * `LayoutableImplExt::parent_<member>`, to call the base implementation
1030///   from an override;
1031/// * `Layoutable::<member>(&self, ..)`, which performs the virtual call.
1032///
1033/// The declaring class must implement every member itself; these are the
1034/// base implementations.
1035#[macro_export]
1036macro_rules! ferro_class {
1037    // What the type declares, in the order of a static initialisation:
1038    // interface casts, properties (field initialisers), static constructor.
1039    // Inherent items of the type win over the `ClassDefaults` fallbacks.
1040    (@class_members $name:ident) => {{
1041        #[allow(unused_imports)]
1042        use $crate::ClassDefaults as _;
1043        $crate::data::core::ValueTypes::register_deferred(<$name>::__register_interfaces);
1044        <$name>::__register_properties();
1045        <$name>::static_constructor();
1046    }};
1047
1048    (@register_class $name:ident : $base:ident) => {
1049        #[inline]
1050        fn register_class() {
1051            $crate::ferro_thread_local! {
1052                static REGISTERED: ::std::cell::Cell<bool> = const { ::std::cell::Cell::new(false) };
1053            }
1054            #[cold]
1055            #[inline(never)]
1056            fn init() {
1057                <$base as $crate::ObjectType>::register_class();
1058                $crate::__register_class::<$name>();
1059                $crate::ferro_class!(@class_members $name);
1060            }
1061            if !REGISTERED.get() {
1062                // Set first: the initialisation may create instances of the
1063                // class or call its property accessors.
1064                REGISTERED.set(true);
1065                init();
1066            }
1067        }
1068    };
1069
1070    (@common $name:ident : $base:ident) => {
1071        const _: () = assert!(
1072            ::std::mem::offset_of!($name, base) == 0,
1073            "class structs must be #[repr(C)] with `base` as their first field"
1074        );
1075
1076        impl ::std::ops::Deref for $name {
1077            type Target = $base;
1078            #[inline]
1079            fn deref(&self) -> &$base {
1080                &self.base
1081            }
1082        }
1083
1084        impl<T: ?Sized> $crate::Upcast<T> for $name
1085        where
1086            $base: $crate::Upcast<T>,
1087        {
1088            #[inline]
1089            fn upcast(&self) -> &T {
1090                $crate::Upcast::upcast(&self.base)
1091            }
1092        }
1093
1094        impl $crate::Upcast<$name> for $name {
1095            #[inline]
1096            fn upcast(&self) -> &$name {
1097                self
1098            }
1099        }
1100
1101        impl $crate::StaticType for $name {
1102            const TYPE: &'static $crate::TypeInfo = {
1103                static TYPE: $crate::TypeInfo = $crate::TypeInfo::new(
1104                    stringify!($name),
1105                    Some(<$base as $crate::StaticType>::TYPE),
1106                )
1107                .with_module_path(::std::module_path!())
1108                .with_class_init(<$name as $crate::ObjectType>::register_class)
1109                .with_constructor({
1110                    #[allow(unused_imports)]
1111                    use $crate::ClassDefaults as _;
1112                    <$name>::__CONSTRUCTOR
1113                })
1114                .with_handles(|| {
1115                    [
1116                        ::std::any::TypeId::of::<$crate::Ref<$name>>(),
1117                        ::std::any::TypeId::of::<::std::option::Option<$crate::Ref<$name>>>(),
1118                    ]
1119                })
1120                .with_handle_registration($crate::data::core::ValueTypes::register_object::<$name>)
1121                .with_interfaces({
1122                    #[allow(unused_imports)]
1123                    use $crate::ClassDefaults as _;
1124                    <$name>::__INTERFACES
1125                })
1126                .with_markup({
1127                    #[allow(unused_imports)]
1128                    use $crate::ClassDefaults as _;
1129                    <$name>::__MARKUP
1130                });
1131                &TYPE
1132            };
1133        }
1134
1135        impl $name {
1136            /// The runtime type of this class.
1137            pub const TYPE: &'static $crate::TypeInfo = <$name as $crate::StaticType>::TYPE;
1138
1139            /// Returns a strong reference to this object.
1140            #[inline]
1141            pub fn to_ref(&self) -> $crate::Ref<$name> {
1142                $crate::FerroObject::ref_of(self)
1143            }
1144        }
1145    };
1146
1147    ($name:ident : $base:ident) => {
1148        $crate::ferro_class!(@common $name: $base);
1149
1150        // SAFETY: the offset assertion above proves the layout requirement;
1151        // the table type is the parent's.
1152        unsafe impl $crate::ObjectType for $name {
1153            type Parent = $base;
1154            type VTable = <$base as $crate::ObjectType>::VTable;
1155
1156            fn vtable() -> &'static Self::VTable {
1157                static VTABLE: ::std::sync::OnceLock<<$base as $crate::ObjectType>::VTable> =
1158                    ::std::sync::OnceLock::new();
1159                VTABLE.get_or_init(<$name as $crate::Subclassable<$name>>::build_vtable)
1160            }
1161
1162            $crate::ferro_class!(@register_class $name: $base);
1163        }
1164
1165        impl<T> $crate::Subclassable<T> for $name
1166        where
1167            $base: $crate::Subclassable<T>,
1168        {
1169            #[inline]
1170            fn build_vtable() -> Self::VTable {
1171                <$base as $crate::Subclassable<T>>::build_vtable()
1172            }
1173        }
1174    };
1175
1176    (
1177        $name:ident : $base:ident, virtuals $impl_trait:ident : $parent_impl:path {
1178            $(
1179                $(#[$meta:meta])*
1180                fn $method:ident(this $(, $arg:ident : $arg_ty:ty)* $(,)?) $(-> $ret:ty)?;
1181            )*
1182        }
1183    ) => {
1184        $crate::ferro_class!(@common $name: $base);
1185
1186        $crate::__paste! {
1187            /// The virtual table of the class.
1188            #[derive(Clone, Copy)]
1189            #[repr(C)]
1190            pub struct [<$name VTable>] {
1191                pub base: <$base as $crate::ObjectType>::VTable,
1192                $(pub $method: fn(&$name $(, $arg_ty)*) $(-> $ret)?,)*
1193            }
1194
1195            // SAFETY: the offset assertion above proves the layout
1196            // requirement; the table is `#[repr(C)]` and starts with the
1197            // parent's table.
1198            unsafe impl $crate::ObjectType for $name {
1199                type Parent = $base;
1200                type VTable = [<$name VTable>];
1201
1202                fn vtable() -> &'static Self::VTable {
1203                    static VTABLE: ::std::sync::OnceLock<[<$name VTable>]> = ::std::sync::OnceLock::new();
1204                    VTABLE.get_or_init(<$name as $crate::Subclassable<$name>>::build_vtable)
1205                }
1206
1207                $crate::ferro_class!(@register_class $name: $base);
1208            }
1209
1210            /// The overridable members introduced by the class.
1211            pub trait $impl_trait: $parent_impl + $crate::Upcast<$name> {
1212                /// The names of the members this implementation overrides,
1213                /// where it states them: `None` for an implementation
1214                /// written as a plain `impl`. Set by `ferro_impl_classes!`
1215                /// and `ferro_overrides!`, never by hand: the table of the
1216                /// class is built from it.
1217                #[doc(hidden)]
1218                const __OVERRIDES: ::std::option::Option<&'static [&'static str]> = ::std::option::Option::None;
1219
1220                $(
1221                    $(#[$meta])*
1222                    #[allow(unused_variables)]
1223                    fn $method(this: &Self $(, $arg: $arg_ty)*) $(-> $ret)? {
1224                        <Self as [<$impl_trait Ext>]>::[<parent_ $method>](this $(, $arg)*)
1225                    }
1226                )*
1227            }
1228
1229            /// Access to the base implementations of the overridable members.
1230            pub trait [<$impl_trait Ext>]: $impl_trait {
1231                $(
1232                    /// Calls the base class implementation of the member.
1233                    #[inline]
1234                    fn [<parent_ $method>](this: &Self $(, $arg: $arg_ty)*) $(-> $ret)? {
1235                        let table = $crate::parent_vtable::<Self, [<$name VTable>]>();
1236                        (table.$method)($crate::Upcast::<$name>::upcast(this) $(, $arg)*)
1237                    }
1238                )*
1239            }
1240
1241            impl<T: $impl_trait> [<$impl_trait Ext>] for T {}
1242
1243            impl<T: $impl_trait> $crate::Subclassable<T> for $name
1244            where
1245                $base: $crate::Subclassable<T>,
1246            {
1247                fn build_vtable() -> [<$name VTable>] {
1248                    [<$name VTable>] {
1249                        base: <$base as $crate::Subclassable<T>>::build_vtable(),
1250                        $(
1251                            $method: {
1252                                // SAFETY: this table is only attached to objects
1253                                // whose most-derived class is `T`.
1254                                let own: fn(&$name $(, $arg_ty)*) $(-> $ret)? =
1255                                    |this $(, $arg)*| T::$method(unsafe { $crate::cast_this::<$name, T>(this) } $(, $arg)*);
1256                                // A member `T` states it does not override is
1257                                // the default, which calls this slot of the
1258                                // parent table: the slot itself is taken.
1259                                let forwards: bool = const {
1260                                    $crate::__forwards_to_parent::<T, [<$name VTable>]>(
1261                                        <T as $impl_trait>::__OVERRIDES,
1262                                        ::std::stringify!($method),
1263                                    )
1264                                };
1265                                if forwards {
1266                                    $crate::parent_vtable::<T, [<$name VTable>]>().$method
1267                                } else {
1268                                    own
1269                                }
1270                            },
1271                        )*
1272                    }
1273                }
1274            }
1275
1276            impl $name {
1277                $(
1278                    $(#[$meta])*
1279                    #[inline]
1280                    pub fn $method(&self $(, $arg: $arg_ty)*) $(-> $ret)? {
1281                        $crate::perf_count_virtual!(concat!(stringify!($name), "::", stringify!($method)));
1282                        let table = $crate::FerroObject::vtable_of::<$name>(self);
1283                        (table.$method)(self $(, $arg)*)
1284                    }
1285                )*
1286            }
1287        }
1288    };
1289}
1290
1291/// Declares the facts about a class that untyped code (markup, untyped
1292/// bindings) needs and cannot derive: its default constructor, the
1293/// interface handles its handle converts to and its markup metadata. Every
1294/// part is optional; the parts may be written in any order.
1295///
1296/// ```ignore
1297/// ferro_class!(SolidColorBrush: Brush);
1298/// ferro_class_info!(SolidColorBrush {
1299///     new: SolidColorBrush::new,
1300///     interfaces: [Rc<dyn IBrush>],
1301/// });
1302///
1303/// ferro_class!(Panel: Control);
1304/// ferro_class_info!(Panel {
1305///     new: Panel::new,
1306///     markup: {
1307///         content: Children,
1308///         properties: [
1309///             Children: Rc<Controls> { get: Panel::children },
1310///         ],
1311///     },
1312/// });
1313/// ```
1314///
1315/// * `new` is a function without parameters that returns the handle of a new
1316///   instance. It becomes [`TypeInfo::default_constructor`].
1317/// * `interfaces` lists the handle types `I` that `Ref<Class>` converts to
1318///   with `Into<I>`, or, as `I => function`, with the given
1319///   `fn(Ref<Class>) -> I` (for an interface of another crate, for which
1320///   the conversion trait cannot be implemented). They are registered with the untyped value conversions
1321///   when the class is initialised, for the class and every class deriving
1322///   from it (a more derived class that lists the same interface takes
1323///   precedence for its own instances), and are listed by
1324///   [`TypeInfo::interfaces`].
1325/// * `markup` states what markup needs beyond the registered properties of
1326///   the class, which need no declaration: the content property, plain
1327///   (non-registered) properties and collections, constructors with
1328///   arguments, methods, static values, events and attributes. The parts are
1329///   the ones of [`ferro_markup_type!`](crate::ferro_markup_type) (without
1330///   `handles`, `this` and `base`, which follow from the class); instance
1331///   members are called with `&Ref<Class>`, so `Class::method` paths work as
1332///   callables. It becomes [`TypeInfo::markup`]: constant data that costs
1333///   nothing until it is read.
1334#[macro_export]
1335macro_rules! ferro_class_info {
1336    (@new $name:ident $constructor:expr) => {
1337        impl $name {
1338            #[doc(hidden)]
1339            pub const __CONSTRUCTOR: ::std::option::Option<fn() -> $crate::Ref<$crate::FerroObject>> =
1340                ::std::option::Option::Some(|| $crate::Ref::<$name>::upcast($constructor()));
1341        }
1342    };
1343
1344    (@cast) => {
1345        |object| ::std::convert::Into::into(object)
1346    };
1347
1348    (@cast $cast:expr) => {
1349        $cast
1350    };
1351
1352    (@interfaces $name:ident [$($interface:ty $(=> $cast:expr)?),* $(,)?]) => {
1353        impl $name {
1354            #[doc(hidden)]
1355            pub const __INTERFACES: &'static [$crate::metadata::TypeOf] =
1356                &[$(|| $crate::data::core::ValueType::of::<$interface>()),*];
1357
1358            #[doc(hidden)]
1359            pub fn __register_interfaces() {
1360                $(
1361                    $crate::data::core::ValueTypes::register_interface::<$name, $interface>(
1362                        $crate::ferro_class_info!(@cast $($cast)?),
1363                    );
1364                )*
1365            }
1366        }
1367    };
1368
1369    (@markup $name:ident { $($body:tt)* }) => {
1370        impl $name {
1371            $crate::__ferro_markup_functions!($crate::__ferro_markup_fns!($crate::Ref<$name>, $crate::Ref<$name>; $($body)*););
1372
1373            #[doc(hidden)]
1374            pub const __MARKUP: ::std::option::Option<&'static $crate::metadata::MarkupType> = {
1375                static MARKUP: $crate::metadata::MarkupType = {
1376                    #[allow(unused_mut)]
1377                    let mut markup = $crate::metadata::MarkupType::new(
1378                        ::std::stringify!($name),
1379                        $crate::metadata::MarkupTypeKind::Class,
1380                        ::std::module_path!(),
1381                    );
1382                    markup.handles = &[
1383                        || $crate::data::core::ValueType::of::<$crate::Ref<$name>>(),
1384                        || $crate::data::core::ValueType::of::<::std::option::Option<$crate::Ref<$name>>>(),
1385                    ];
1386                    markup.type_info = ::std::option::Option::Some(|| <$name as $crate::StaticType>::TYPE);
1387                    markup.interfaces = {
1388                        #[allow(unused_imports)]
1389                        use $crate::ClassDefaults as _;
1390                        <$name>::__INTERFACES
1391                    };
1392                    $crate::__ferro_compiler_metadata!(
1393                        markup.this = ::std::option::Option::Some(|| $crate::data::core::ValueType::of::<$crate::Ref<$name>>());
1394                        markup.value = ::std::option::Option::Some(|| $crate::data::core::ValueType::of::<$crate::Ref<$name>>());
1395                    );
1396                    $crate::__ferro_markup_items!(markup, $crate::Ref<$name>; $($body)*);
1397                    markup
1398                };
1399                ::std::option::Option::Some(&MARKUP)
1400            };
1401        }
1402    };
1403
1404    (@parts $name:ident;) => {};
1405
1406    (@parts $name:ident; new: $constructor:expr $(, $($rest:tt)*)?) => {
1407        $crate::ferro_class_info!(@new $name $constructor);
1408        $crate::ferro_class_info!(@parts $name; $($($rest)*)?);
1409    };
1410
1411    (@parts $name:ident; interfaces: $interfaces:tt $(, $($rest:tt)*)?) => {
1412        $crate::ferro_class_info!(@interfaces $name $interfaces);
1413        $crate::ferro_class_info!(@parts $name; $($($rest)*)?);
1414    };
1415
1416    (@parts $name:ident; markup: $markup:tt $(, $($rest:tt)*)?) => {
1417        $crate::ferro_class_info!(@markup $name $markup);
1418        $crate::ferro_class_info!(@parts $name; $($($rest)*)?);
1419    };
1420
1421    ($name:ident { $($parts:tt)* }) => {
1422        $crate::ferro_class_info!(@parts $name; $($parts)*);
1423    };
1424}
1425
1426/// Declares the runtime type of a type that is not a class: a type that
1427/// owns attached properties and cannot be instantiated as an object.
1428///
1429/// ```ignore
1430/// pub struct KeyboardNavigation;
1431/// ferro_static_type!(KeyboardNavigation);
1432///
1433/// ferro_properties! {
1434///     impl KeyboardNavigation {
1435///         pub fn tab_index_property() -> AttachedProperty<i32> { .. }
1436///     }
1437/// }
1438/// ```
1439///
1440/// Unlike a hand-written `impl StaticType`, the runtime type carries the
1441/// static initialisation of the type (its `ferro_properties!` block and its
1442/// `fn static_constructor()`, as for a class), so its properties are found
1443/// by owner type and name before any accessor was called, and it knows its
1444/// module, hence its namespace.
1445#[macro_export]
1446macro_rules! ferro_static_type {
1447    ($name:ident) => {
1448        impl $crate::StaticType for $name {
1449            const TYPE: &'static $crate::TypeInfo = {
1450                fn class_init() {
1451                    $crate::ferro_thread_local! {
1452                        static REGISTERED: ::std::cell::Cell<bool> = const { ::std::cell::Cell::new(false) };
1453                    }
1454                    if !REGISTERED.replace(true) {
1455                        $crate::TypeInfo::register(<$name as $crate::StaticType>::TYPE);
1456                        $crate::ferro_class!(@class_members $name);
1457                    }
1458                }
1459                static TYPE: $crate::TypeInfo = $crate::TypeInfo::new(stringify!($name), None)
1460                    .with_module_path(::std::module_path!())
1461                    .with_class_init(class_init);
1462                &TYPE
1463            };
1464        }
1465
1466        impl $name {
1467            /// The runtime type of this type.
1468            #[allow(dead_code)]
1469            pub const TYPE: &'static $crate::TypeInfo = <$name as $crate::StaticType>::TYPE;
1470        }
1471    };
1472}
1473
1474/// Implements class `Impl` traits with no overrides.
1475///
1476/// ```ignore
1477/// ferro_impl_classes!(Border: FerroObjectImpl, StyledElementImpl, VisualImpl);
1478/// ```
1479///
1480/// Unlike `impl VisualImpl for Border {}`, which means the same, this form
1481/// states that nothing is overridden, and the table of the class is built
1482/// from that: every slot of the members of these traits is the slot of the
1483/// base class, so a call reaches the implementation without passing through
1484/// a forwarding function of this class.
1485#[macro_export]
1486macro_rules! ferro_impl_classes {
1487    ($name:ty : $($trait_:path),+ $(,)?) => {
1488        $(
1489            impl $trait_ for $name {
1490                const __OVERRIDES: ::std::option::Option<&'static [&'static str]> = ::std::option::Option::Some(&[]);
1491            }
1492        )+
1493    };
1494}
1495
1496/// Implements a class `Impl` trait and states which of its members the
1497/// implementation overrides: the ones written in the block.
1498///
1499/// ```ignore
1500/// ferro_overrides! { impl FerroObjectImpl for Border {
1501///     fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
1502///         Self::parent_on_property_changed(this, change);
1503///         // ..
1504///     }
1505/// } }
1506/// ```
1507///
1508/// The implementation is the one a plain `impl FerroObjectImpl for Border`
1509/// with the same functions gives. What the macro adds is the list of their
1510/// names, from which the table of the class is built: the slot of a member
1511/// that is not in the block is the slot of the base class, so a call of it
1512/// reaches the implementation without passing through a forwarding function
1513/// of this class. The list is taken from the functions themselves and cannot
1514/// differ from them.
1515///
1516/// The block holds functions only, each with its attributes and
1517/// documentation, as the members of an `Impl` trait are.
1518#[macro_export]
1519macro_rules! ferro_overrides {
1520    (
1521        impl $trait_:ident for $name:ident {
1522            $(
1523                $(#[$meta:meta])*
1524                fn $method:ident ( $($params:tt)* ) $(-> $ret:ty)? $body:block
1525            )*
1526        }
1527    ) => {
1528        impl $trait_ for $name {
1529            const __OVERRIDES: ::std::option::Option<&'static [&'static str]> =
1530                ::std::option::Option::Some(&[$(::std::stringify!($method)),*]);
1531
1532            $(
1533                $(#[$meta])*
1534                fn $method($($params)*) $(-> $ret)? $body
1535            )*
1536        }
1537    };
1538}