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 two weak references point at the same object, alive or not.
903    #[inline]
904    pub fn ptr_eq<U: ObjectType>(&self, other: &WeakRef<U>) -> bool {
905        std::ptr::addr_eq(self.ptr.as_ptr(), other.ptr.as_ptr())
906    }
907
908    #[inline]
909    pub(crate) fn from_weak(ptr: Weak<dyn Any>) -> Self {
910        WeakRef::of(ptr)
911    }
912}
913
914impl<T: ObjectType> Clone for WeakRef<T> {
915    #[inline]
916    fn clone(&self) -> Self {
917        WeakRef::of(self.ptr.clone())
918    }
919}
920
921/// An optional object reference accepted by setters, convertible from a
922/// handle (or a borrowed handle) of any derived class and from `None`.
923pub struct Nullable<T: ObjectType>(pub Option<Ref<T>>);
924
925impl<T: ObjectType + Upcast<U>, U: ObjectType> From<Ref<T>> for Nullable<U> {
926    #[inline]
927    fn from(value: Ref<T>) -> Self {
928        Nullable(Some(value.upcast()))
929    }
930}
931
932impl<T: ObjectType + Upcast<U>, U: ObjectType> From<&Ref<T>> for Nullable<U> {
933    #[inline]
934    fn from(value: &Ref<T>) -> Self {
935        Nullable(Some(value.clone().upcast()))
936    }
937}
938
939impl<U: ObjectType> From<Option<Ref<U>>> for Nullable<U> {
940    #[inline]
941    fn from(value: Option<Ref<U>>) -> Self {
942        Nullable(value)
943    }
944}
945
946/// A non-optional object reference accepted by methods, convertible from a
947/// handle (or a borrowed handle) of any derived class.
948pub trait IntoRef<U: ObjectType> {
949    fn into_ref(self) -> Ref<U>;
950}
951
952impl<T: ObjectType + Upcast<U>, U: ObjectType> IntoRef<U> for Ref<T> {
953    #[inline]
954    fn into_ref(self) -> Ref<U> {
955        self.upcast()
956    }
957}
958
959impl<T: ObjectType + Upcast<U>, U: ObjectType> IntoRef<U> for &Ref<T> {
960    #[inline]
961    fn into_ref(self) -> Ref<U> {
962        self.clone().upcast()
963    }
964}
965
966/// Moves a constructed class value to the heap, attaches the virtual table of
967/// its class and runs the `constructed` virtual member. The class (and its
968/// base classes) are initialised first if this is the first instance on the
969/// thread; see [`ObjectType::register_class`].
970pub fn instantiate<T: ObjectType>(value: T) -> Ref<T> {
971    T::register_class();
972    let ptr: Rc<dyn Any> = Rc::new(value);
973    let result: Ref<T> = Ref { ptr, _marker: PhantomData };
974    let object: &FerroObject = (*result).upcast();
975    let table: *const T::VTable = T::vtable();
976    // SAFETY: `T::VTable` starts with the root class's table (`ObjectType`
977    // invariant), and the object's most-derived class is `T`.
978    unsafe { object.attach(Rc::downgrade(&result.ptr), table as *const ()) };
979    object.constructed();
980    result
981}
982
983/// Declares a class.
984///
985/// ```ignore
986/// #[repr(C)]
987/// pub struct Decorator { base: Control, /* fields */ }
988///
989/// // A class without new virtual members:
990/// ferro_class!(Decorator: Control);
991///
992/// // A class that introduces virtual members:
993/// ferro_class! {
994///     Layoutable: Visual, virtuals LayoutableImpl: VisualImpl {
995///         /// Measures the control.
996///         fn measure_override(this, available_size: Size) -> Size;
997///         fn arrange_override(this, final_size: Size) -> Size;
998///     }
999/// }
1000/// ```
1001///
1002/// Both forms generate `Deref<Target = Base>`, [`Upcast`] to every ancestor,
1003/// the `TYPE` runtime type and [`ObjectType`], including the static
1004/// initialisation of the class ([`ObjectType::register_class`]). What the
1005/// initialisation does is taken from the other declarations of the class,
1006/// each optional and found by the macro without being named here:
1007///
1008/// * `ferro_properties! { impl Decorator { .. } }`, the property definitions;
1009/// * `fn static_constructor()`, an inherent function declared in the same
1010///   module ([`ClassDefaults::static_constructor`]);
1011/// * `ferro_class_info!(Decorator { new: Decorator::new, interfaces: [..] })`,
1012///   the default constructor and the interface handles the class converts
1013///   to.
1014///
1015/// The second form also generates:
1016///
1017/// * `LayoutableVTable`, the table of the new members;
1018/// * `trait LayoutableImpl`, with one associated function per member taking
1019///   `this: &Self`. Every class deriving from `Layoutable` implements it
1020///   (`impl LayoutableImpl for Border {}`) and overrides what it needs
1021///   ([`ferro_impl_classes!`] and [`ferro_overrides!`] write the same
1022///   implementation and state what it overrides, which shortens the calls);
1023/// * `LayoutableImplExt::parent_<member>`, to call the base implementation
1024///   from an override;
1025/// * `Layoutable::<member>(&self, ..)`, which performs the virtual call.
1026///
1027/// The declaring class must implement every member itself; these are the
1028/// base implementations.
1029#[macro_export]
1030macro_rules! ferro_class {
1031    // What the type declares, in the order of a static initialisation:
1032    // interface casts, properties (field initialisers), static constructor.
1033    // Inherent items of the type win over the `ClassDefaults` fallbacks.
1034    (@class_members $name:ident) => {{
1035        #[allow(unused_imports)]
1036        use $crate::ClassDefaults as _;
1037        $crate::data::core::ValueTypes::register_deferred(<$name>::__register_interfaces);
1038        <$name>::__register_properties();
1039        <$name>::static_constructor();
1040    }};
1041
1042    (@register_class $name:ident : $base:ident) => {
1043        #[inline]
1044        fn register_class() {
1045            $crate::ferro_thread_local! {
1046                static REGISTERED: ::std::cell::Cell<bool> = const { ::std::cell::Cell::new(false) };
1047            }
1048            #[cold]
1049            #[inline(never)]
1050            fn init() {
1051                <$base as $crate::ObjectType>::register_class();
1052                $crate::__register_class::<$name>();
1053                $crate::ferro_class!(@class_members $name);
1054            }
1055            if !REGISTERED.get() {
1056                // Set first: the initialisation may create instances of the
1057                // class or call its property accessors.
1058                REGISTERED.set(true);
1059                init();
1060            }
1061        }
1062    };
1063
1064    (@common $name:ident : $base:ident) => {
1065        const _: () = assert!(
1066            ::std::mem::offset_of!($name, base) == 0,
1067            "class structs must be #[repr(C)] with `base` as their first field"
1068        );
1069
1070        impl ::std::ops::Deref for $name {
1071            type Target = $base;
1072            #[inline]
1073            fn deref(&self) -> &$base {
1074                &self.base
1075            }
1076        }
1077
1078        impl<T: ?Sized> $crate::Upcast<T> for $name
1079        where
1080            $base: $crate::Upcast<T>,
1081        {
1082            #[inline]
1083            fn upcast(&self) -> &T {
1084                $crate::Upcast::upcast(&self.base)
1085            }
1086        }
1087
1088        impl $crate::Upcast<$name> for $name {
1089            #[inline]
1090            fn upcast(&self) -> &$name {
1091                self
1092            }
1093        }
1094
1095        impl $crate::StaticType for $name {
1096            const TYPE: &'static $crate::TypeInfo = {
1097                static TYPE: $crate::TypeInfo = $crate::TypeInfo::new(
1098                    stringify!($name),
1099                    Some(<$base as $crate::StaticType>::TYPE),
1100                )
1101                .with_module_path(::std::module_path!())
1102                .with_class_init(<$name as $crate::ObjectType>::register_class)
1103                .with_constructor({
1104                    #[allow(unused_imports)]
1105                    use $crate::ClassDefaults as _;
1106                    <$name>::__CONSTRUCTOR
1107                })
1108                .with_handles(|| {
1109                    [
1110                        ::std::any::TypeId::of::<$crate::Ref<$name>>(),
1111                        ::std::any::TypeId::of::<::std::option::Option<$crate::Ref<$name>>>(),
1112                    ]
1113                })
1114                .with_handle_registration($crate::data::core::ValueTypes::register_object::<$name>)
1115                .with_interfaces({
1116                    #[allow(unused_imports)]
1117                    use $crate::ClassDefaults as _;
1118                    <$name>::__INTERFACES
1119                })
1120                .with_markup({
1121                    #[allow(unused_imports)]
1122                    use $crate::ClassDefaults as _;
1123                    <$name>::__MARKUP
1124                });
1125                &TYPE
1126            };
1127        }
1128
1129        impl $name {
1130            /// The runtime type of this class.
1131            pub const TYPE: &'static $crate::TypeInfo = <$name as $crate::StaticType>::TYPE;
1132
1133            /// Returns a strong reference to this object.
1134            #[inline]
1135            pub fn to_ref(&self) -> $crate::Ref<$name> {
1136                $crate::FerroObject::ref_of(self)
1137            }
1138        }
1139    };
1140
1141    ($name:ident : $base:ident) => {
1142        $crate::ferro_class!(@common $name: $base);
1143
1144        // SAFETY: the offset assertion above proves the layout requirement;
1145        // the table type is the parent's.
1146        unsafe impl $crate::ObjectType for $name {
1147            type Parent = $base;
1148            type VTable = <$base as $crate::ObjectType>::VTable;
1149
1150            fn vtable() -> &'static Self::VTable {
1151                static VTABLE: ::std::sync::OnceLock<<$base as $crate::ObjectType>::VTable> =
1152                    ::std::sync::OnceLock::new();
1153                VTABLE.get_or_init(<$name as $crate::Subclassable<$name>>::build_vtable)
1154            }
1155
1156            $crate::ferro_class!(@register_class $name: $base);
1157        }
1158
1159        impl<T> $crate::Subclassable<T> for $name
1160        where
1161            $base: $crate::Subclassable<T>,
1162        {
1163            #[inline]
1164            fn build_vtable() -> Self::VTable {
1165                <$base as $crate::Subclassable<T>>::build_vtable()
1166            }
1167        }
1168    };
1169
1170    (
1171        $name:ident : $base:ident, virtuals $impl_trait:ident : $parent_impl:path {
1172            $(
1173                $(#[$meta:meta])*
1174                fn $method:ident(this $(, $arg:ident : $arg_ty:ty)* $(,)?) $(-> $ret:ty)?;
1175            )*
1176        }
1177    ) => {
1178        $crate::ferro_class!(@common $name: $base);
1179
1180        $crate::__paste! {
1181            /// The virtual table of the class.
1182            #[derive(Clone, Copy)]
1183            #[repr(C)]
1184            pub struct [<$name VTable>] {
1185                pub base: <$base as $crate::ObjectType>::VTable,
1186                $(pub $method: fn(&$name $(, $arg_ty)*) $(-> $ret)?,)*
1187            }
1188
1189            // SAFETY: the offset assertion above proves the layout
1190            // requirement; the table is `#[repr(C)]` and starts with the
1191            // parent's table.
1192            unsafe impl $crate::ObjectType for $name {
1193                type Parent = $base;
1194                type VTable = [<$name VTable>];
1195
1196                fn vtable() -> &'static Self::VTable {
1197                    static VTABLE: ::std::sync::OnceLock<[<$name VTable>]> = ::std::sync::OnceLock::new();
1198                    VTABLE.get_or_init(<$name as $crate::Subclassable<$name>>::build_vtable)
1199                }
1200
1201                $crate::ferro_class!(@register_class $name: $base);
1202            }
1203
1204            /// The overridable members introduced by the class.
1205            pub trait $impl_trait: $parent_impl + $crate::Upcast<$name> {
1206                /// The names of the members this implementation overrides,
1207                /// where it states them: `None` for an implementation
1208                /// written as a plain `impl`. Set by `ferro_impl_classes!`
1209                /// and `ferro_overrides!`, never by hand: the table of the
1210                /// class is built from it.
1211                #[doc(hidden)]
1212                const __OVERRIDES: ::std::option::Option<&'static [&'static str]> = ::std::option::Option::None;
1213
1214                $(
1215                    $(#[$meta])*
1216                    #[allow(unused_variables)]
1217                    fn $method(this: &Self $(, $arg: $arg_ty)*) $(-> $ret)? {
1218                        <Self as [<$impl_trait Ext>]>::[<parent_ $method>](this $(, $arg)*)
1219                    }
1220                )*
1221            }
1222
1223            /// Access to the base implementations of the overridable members.
1224            pub trait [<$impl_trait Ext>]: $impl_trait {
1225                $(
1226                    /// Calls the base class implementation of the member.
1227                    #[inline]
1228                    fn [<parent_ $method>](this: &Self $(, $arg: $arg_ty)*) $(-> $ret)? {
1229                        let table = $crate::parent_vtable::<Self, [<$name VTable>]>();
1230                        (table.$method)($crate::Upcast::<$name>::upcast(this) $(, $arg)*)
1231                    }
1232                )*
1233            }
1234
1235            impl<T: $impl_trait> [<$impl_trait Ext>] for T {}
1236
1237            impl<T: $impl_trait> $crate::Subclassable<T> for $name
1238            where
1239                $base: $crate::Subclassable<T>,
1240            {
1241                fn build_vtable() -> [<$name VTable>] {
1242                    [<$name VTable>] {
1243                        base: <$base as $crate::Subclassable<T>>::build_vtable(),
1244                        $(
1245                            $method: {
1246                                // SAFETY: this table is only attached to objects
1247                                // whose most-derived class is `T`.
1248                                let own: fn(&$name $(, $arg_ty)*) $(-> $ret)? =
1249                                    |this $(, $arg)*| T::$method(unsafe { $crate::cast_this::<$name, T>(this) } $(, $arg)*);
1250                                // A member `T` states it does not override is
1251                                // the default, which calls this slot of the
1252                                // parent table: the slot itself is taken.
1253                                let forwards: bool = const {
1254                                    $crate::__forwards_to_parent::<T, [<$name VTable>]>(
1255                                        <T as $impl_trait>::__OVERRIDES,
1256                                        ::std::stringify!($method),
1257                                    )
1258                                };
1259                                if forwards {
1260                                    $crate::parent_vtable::<T, [<$name VTable>]>().$method
1261                                } else {
1262                                    own
1263                                }
1264                            },
1265                        )*
1266                    }
1267                }
1268            }
1269
1270            impl $name {
1271                $(
1272                    $(#[$meta])*
1273                    #[inline]
1274                    pub fn $method(&self $(, $arg: $arg_ty)*) $(-> $ret)? {
1275                        $crate::perf_count_virtual!(concat!(stringify!($name), "::", stringify!($method)));
1276                        let table = $crate::FerroObject::vtable_of::<$name>(self);
1277                        (table.$method)(self $(, $arg)*)
1278                    }
1279                )*
1280            }
1281        }
1282    };
1283}
1284
1285/// Declares the facts about a class that untyped code (markup, untyped
1286/// bindings) needs and cannot derive: its default constructor, the
1287/// interface handles its handle converts to and its markup metadata. Every
1288/// part is optional; the parts may be written in any order.
1289///
1290/// ```ignore
1291/// ferro_class!(SolidColorBrush: Brush);
1292/// ferro_class_info!(SolidColorBrush {
1293///     new: SolidColorBrush::new,
1294///     interfaces: [Rc<dyn IBrush>],
1295/// });
1296///
1297/// ferro_class!(Panel: Control);
1298/// ferro_class_info!(Panel {
1299///     new: Panel::new,
1300///     markup: {
1301///         content: Children,
1302///         properties: [
1303///             Children: Rc<Controls> { get: Panel::children },
1304///         ],
1305///     },
1306/// });
1307/// ```
1308///
1309/// * `new` is a function without parameters that returns the handle of a new
1310///   instance. It becomes [`TypeInfo::default_constructor`].
1311/// * `interfaces` lists the handle types `I` that `Ref<Class>` converts to
1312///   with `Into<I>`, or, as `I => function`, with the given
1313///   `fn(Ref<Class>) -> I` (for an interface of another crate, for which
1314///   the conversion trait cannot be implemented). They are registered with the untyped value conversions
1315///   when the class is initialised, for the class and every class deriving
1316///   from it (a more derived class that lists the same interface takes
1317///   precedence for its own instances), and are listed by
1318///   [`TypeInfo::interfaces`].
1319/// * `markup` states what markup needs beyond the registered properties of
1320///   the class, which need no declaration: the content property, plain
1321///   (non-registered) properties and collections, constructors with
1322///   arguments, methods, static values, events and attributes. The parts are
1323///   the ones of [`ferro_markup_type!`](crate::ferro_markup_type) (without
1324///   `handles`, `this` and `base`, which follow from the class); instance
1325///   members are called with `&Ref<Class>`, so `Class::method` paths work as
1326///   callables. It becomes [`TypeInfo::markup`]: constant data that costs
1327///   nothing until it is read.
1328#[macro_export]
1329macro_rules! ferro_class_info {
1330    (@new $name:ident $constructor:expr) => {
1331        impl $name {
1332            #[doc(hidden)]
1333            pub const __CONSTRUCTOR: ::std::option::Option<fn() -> $crate::Ref<$crate::FerroObject>> =
1334                ::std::option::Option::Some(|| $crate::Ref::<$name>::upcast($constructor()));
1335        }
1336    };
1337
1338    (@cast) => {
1339        |object| ::std::convert::Into::into(object)
1340    };
1341
1342    (@cast $cast:expr) => {
1343        $cast
1344    };
1345
1346    (@interfaces $name:ident [$($interface:ty $(=> $cast:expr)?),* $(,)?]) => {
1347        impl $name {
1348            #[doc(hidden)]
1349            pub const __INTERFACES: &'static [$crate::metadata::TypeOf] =
1350                &[$(|| $crate::data::core::ValueType::of::<$interface>()),*];
1351
1352            #[doc(hidden)]
1353            pub fn __register_interfaces() {
1354                $(
1355                    $crate::data::core::ValueTypes::register_interface::<$name, $interface>(
1356                        $crate::ferro_class_info!(@cast $($cast)?),
1357                    );
1358                )*
1359            }
1360        }
1361    };
1362
1363    (@markup $name:ident { $($body:tt)* }) => {
1364        impl $name {
1365            $crate::__ferro_markup_functions!($crate::__ferro_markup_fns!($crate::Ref<$name>, $crate::Ref<$name>; $($body)*););
1366
1367            #[doc(hidden)]
1368            pub const __MARKUP: ::std::option::Option<&'static $crate::metadata::MarkupType> = {
1369                static MARKUP: $crate::metadata::MarkupType = {
1370                    #[allow(unused_mut)]
1371                    let mut markup = $crate::metadata::MarkupType::new(
1372                        ::std::stringify!($name),
1373                        $crate::metadata::MarkupTypeKind::Class,
1374                        ::std::module_path!(),
1375                    );
1376                    markup.handles = &[
1377                        || $crate::data::core::ValueType::of::<$crate::Ref<$name>>(),
1378                        || $crate::data::core::ValueType::of::<::std::option::Option<$crate::Ref<$name>>>(),
1379                    ];
1380                    markup.type_info = ::std::option::Option::Some(|| <$name as $crate::StaticType>::TYPE);
1381                    markup.interfaces = {
1382                        #[allow(unused_imports)]
1383                        use $crate::ClassDefaults as _;
1384                        <$name>::__INTERFACES
1385                    };
1386                    $crate::__ferro_compiler_metadata!(
1387                        markup.this = ::std::option::Option::Some(|| $crate::data::core::ValueType::of::<$crate::Ref<$name>>());
1388                        markup.value = ::std::option::Option::Some(|| $crate::data::core::ValueType::of::<$crate::Ref<$name>>());
1389                    );
1390                    $crate::__ferro_markup_items!(markup, $crate::Ref<$name>; $($body)*);
1391                    markup
1392                };
1393                ::std::option::Option::Some(&MARKUP)
1394            };
1395        }
1396    };
1397
1398    (@parts $name:ident;) => {};
1399
1400    (@parts $name:ident; new: $constructor:expr $(, $($rest:tt)*)?) => {
1401        $crate::ferro_class_info!(@new $name $constructor);
1402        $crate::ferro_class_info!(@parts $name; $($($rest)*)?);
1403    };
1404
1405    (@parts $name:ident; interfaces: $interfaces:tt $(, $($rest:tt)*)?) => {
1406        $crate::ferro_class_info!(@interfaces $name $interfaces);
1407        $crate::ferro_class_info!(@parts $name; $($($rest)*)?);
1408    };
1409
1410    (@parts $name:ident; markup: $markup:tt $(, $($rest:tt)*)?) => {
1411        $crate::ferro_class_info!(@markup $name $markup);
1412        $crate::ferro_class_info!(@parts $name; $($($rest)*)?);
1413    };
1414
1415    ($name:ident { $($parts:tt)* }) => {
1416        $crate::ferro_class_info!(@parts $name; $($parts)*);
1417    };
1418}
1419
1420/// Declares the runtime type of a type that is not a class: a type that
1421/// owns attached properties and cannot be instantiated as an object.
1422///
1423/// ```ignore
1424/// pub struct KeyboardNavigation;
1425/// ferro_static_type!(KeyboardNavigation);
1426///
1427/// ferro_properties! {
1428///     impl KeyboardNavigation {
1429///         pub fn tab_index_property() -> AttachedProperty<i32> { .. }
1430///     }
1431/// }
1432/// ```
1433///
1434/// Unlike a hand-written `impl StaticType`, the runtime type carries the
1435/// static initialisation of the type (its `ferro_properties!` block and its
1436/// `fn static_constructor()`, as for a class), so its properties are found
1437/// by owner type and name before any accessor was called, and it knows its
1438/// module, hence its namespace.
1439#[macro_export]
1440macro_rules! ferro_static_type {
1441    ($name:ident) => {
1442        impl $crate::StaticType for $name {
1443            const TYPE: &'static $crate::TypeInfo = {
1444                fn class_init() {
1445                    $crate::ferro_thread_local! {
1446                        static REGISTERED: ::std::cell::Cell<bool> = const { ::std::cell::Cell::new(false) };
1447                    }
1448                    if !REGISTERED.replace(true) {
1449                        $crate::TypeInfo::register(<$name as $crate::StaticType>::TYPE);
1450                        $crate::ferro_class!(@class_members $name);
1451                    }
1452                }
1453                static TYPE: $crate::TypeInfo = $crate::TypeInfo::new(stringify!($name), None)
1454                    .with_module_path(::std::module_path!())
1455                    .with_class_init(class_init);
1456                &TYPE
1457            };
1458        }
1459
1460        impl $name {
1461            /// The runtime type of this type.
1462            #[allow(dead_code)]
1463            pub const TYPE: &'static $crate::TypeInfo = <$name as $crate::StaticType>::TYPE;
1464        }
1465    };
1466}
1467
1468/// Implements class `Impl` traits with no overrides.
1469///
1470/// ```ignore
1471/// ferro_impl_classes!(Border: FerroObjectImpl, StyledElementImpl, VisualImpl);
1472/// ```
1473///
1474/// Unlike `impl VisualImpl for Border {}`, which means the same, this form
1475/// states that nothing is overridden, and the table of the class is built
1476/// from that: every slot of the members of these traits is the slot of the
1477/// base class, so a call reaches the implementation without passing through
1478/// a forwarding function of this class.
1479#[macro_export]
1480macro_rules! ferro_impl_classes {
1481    ($name:ty : $($trait_:path),+ $(,)?) => {
1482        $(
1483            impl $trait_ for $name {
1484                const __OVERRIDES: ::std::option::Option<&'static [&'static str]> = ::std::option::Option::Some(&[]);
1485            }
1486        )+
1487    };
1488}
1489
1490/// Implements a class `Impl` trait and states which of its members the
1491/// implementation overrides: the ones written in the block.
1492///
1493/// ```ignore
1494/// ferro_overrides! { impl FerroObjectImpl for Border {
1495///     fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
1496///         Self::parent_on_property_changed(this, change);
1497///         // ..
1498///     }
1499/// } }
1500/// ```
1501///
1502/// The implementation is the one a plain `impl FerroObjectImpl for Border`
1503/// with the same functions gives. What the macro adds is the list of their
1504/// names, from which the table of the class is built: the slot of a member
1505/// that is not in the block is the slot of the base class, so a call of it
1506/// reaches the implementation without passing through a forwarding function
1507/// of this class. The list is taken from the functions themselves and cannot
1508/// differ from them.
1509///
1510/// The block holds functions only, each with its attributes and
1511/// documentation, as the members of an `Impl` trait are.
1512#[macro_export]
1513macro_rules! ferro_overrides {
1514    (
1515        impl $trait_:ident for $name:ident {
1516            $(
1517                $(#[$meta:meta])*
1518                fn $method:ident ( $($params:tt)* ) $(-> $ret:ty)? $body:block
1519            )*
1520        }
1521    ) => {
1522        impl $trait_ for $name {
1523            const __OVERRIDES: ::std::option::Option<&'static [&'static str]> =
1524                ::std::option::Option::Some(&[$(::std::stringify!($method)),*]);
1525
1526            $(
1527                $(#[$meta])*
1528                fn $method($($params)*) $(-> $ret)? $body
1529            )*
1530        }
1531    };
1532}