Skip to main content

ferroui_base/metadata/
markup_type.rs

1//! Markup metadata: what markup (and other untyped code) needs to know
2//! about a type and cannot derive from the property system.
3//!
4//! The managed original answers these questions with reflection: which
5//! property holds the content of an element, which plain (non-registered)
6//! properties, collections and events a type has, how to construct it with
7//! arguments, how to parse it from text, which attributes it carries. Here a
8//! type states them once, as constant data, with the declaration forms of
9//! [`ferro_class_info!`](crate::ferro_class_info) (classes),
10//! [`ferro_markup_type!`](crate::ferro_markup_type) (every other type) and
11//! [`ferro_markup_enum!`](crate::ferro_markup_enum) (enumerations).
12//!
13//! Everything in this module is plain `'static` data and function pointers:
14//! declaring metadata costs nothing at run time until something reads it,
15//! and nothing is registered before `main`.
16//!
17//! # Values
18//!
19//! Members are invoked with untyped values ([`MarkupValue`]): `None` is
20//! null, `Some(box)` holds a value in its untyped form, the form
21//! [`ValueTypes`] produces for bindings (the contents of a nullable, the
22//! object itself for a reference type, the handle for a class instance).
23//! An invoker converts each argument to the declared Rust parameter type
24//! with the assignability casts of [`ValueTypes`] (identity, base class and
25//! interface handles, wrapping into `Option<T>`, boxing into the "any value"
26//! type); conversions that change the value (parsing, numeric conversion)
27//! are the caller's business.
28
29use crate::data::core::{ValueType, ValueTypes, WeakValue};
30use crate::{BoxedValue, TypeInfo};
31use std::any::{Any, TypeId};
32use std::collections::HashMap;
33use std::fmt;
34use std::rc::Rc;
35use std::sync::{OnceLock, RwLock};
36
37/// Names a Rust type lazily. Type identities cannot be computed in constant
38/// data, so metadata stores a function that returns them.
39pub type TypeOf = fn() -> ValueType;
40
41/// An untyped value passed to and returned from an invoker: `None` is null.
42pub type MarkupValue = Option<BoxedValue>;
43
44/// An untyped member: a constructor, method, property accessor or event
45/// subscription. For instance members the first argument is the instance.
46pub type MarkupInvoke = fn(&[MarkupValue]) -> Result<MarkupValue, MarkupInvokeError>;
47
48/// Why an untyped member could not be invoked.
49#[derive(Clone, Debug, PartialEq)]
50pub enum MarkupInvokeError {
51    /// The member was called with the wrong number of arguments (including
52    /// the instance).
53    ArgumentCount { expected: usize, actual: usize },
54    /// An argument is not assignable to the declared parameter type.
55    Argument { index: usize, expected: &'static str, actual: String },
56    /// The member itself failed (the equivalent of an exception thrown by
57    /// the member, for example a parse error).
58    Failed(String),
59}
60
61impl fmt::Display for MarkupInvokeError {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        match self {
64            Self::ArgumentCount { expected, actual } => {
65                write!(f, "Expected {expected} argument(s), got {actual}.")
66            }
67            Self::Argument { index, expected, actual } => {
68                write!(f, "Argument {index}: a value of type '{actual}' is not assignable to '{expected}'.")
69            }
70            Self::Failed(message) => f.write_str(message),
71        }
72    }
73}
74
75impl std::error::Error for MarkupInvokeError {}
76
77/// The declared method a [`MarkupDelegate`] was created from: what the
78/// `Target` and `Method` of a delegate are in the managed original.
79struct MarkupDelegateMethod {
80    target: DelegateTarget,
81    declaring_type: &'static MarkupType,
82    method: &'static MarkupMethod,
83}
84
85/// The instance the delegate of a declared method is bound to.
86#[derive(Clone)]
87enum DelegateTarget {
88    /// The instance, kept alive by the delegate; `None` for a static method.
89    Strong(MarkupValue),
90    /// The instance of the delegate of a binding source
91    /// ([`MarkupDelegate::for_method_of_source`]).
92    Weak(WeakValue),
93}
94
95impl DelegateTarget {
96    /// The instance; `Err` once an instance that is held weakly is gone.
97    fn get(&self) -> Result<MarkupValue, ()> {
98        match self {
99            DelegateTarget::Strong(target) => Ok(target.clone()),
100            DelegateTarget::Weak(target) => target.upgrade().map(Some).ok_or(()),
101        }
102    }
103}
104
105/// An untyped callback (the equivalent of a delegate instance): what an
106/// event subscription declared in metadata receives as its handler, and what
107/// a binding to a method produces.
108#[derive(Clone)]
109pub struct MarkupDelegate {
110    call: Rc<dyn Fn(&[MarkupValue]) -> MarkupValue>,
111    method: Option<Rc<MarkupDelegateMethod>>,
112}
113
114impl MarkupDelegate {
115    pub fn new(f: impl Fn(&[MarkupValue]) -> MarkupValue + 'static) -> Self {
116        Self { call: Rc::new(f), method: None }
117    }
118
119    /// The delegate of a method declared in metadata, bound to `target`
120    /// (`method.CreateDelegate(type, target)` in the managed original).
121    /// `target` is the instance for an instance method and ignored for a
122    /// static one; `declaring_type` is the type whose metadata lists
123    /// `method`. The delegate keeps the target alive.
124    ///
125    /// [`invoke`](Self::invoke) calls the method with the arguments given
126    /// (after the instance) and discards a failure;
127    /// [`try_invoke`](Self::try_invoke) reports it.
128    pub fn for_method(target: MarkupValue, declaring_type: &'static MarkupType, method: &'static MarkupMethod) -> Self {
129        let target = DelegateTarget::Strong(if method.is_static { None } else { target });
130        Self::bound(target, declaring_type, method)
131    }
132
133    /// The delegate of a method of a binding source: what a binding to a
134    /// method reads. As [`for_method`](Self::for_method), but the delegate
135    /// does not keep `target` alive (a source that is a reference; a plain
136    /// value is held as a binding holds it, by value). Once the target is
137    /// gone [`target`](Self::target) is `None`,
138    /// [`is_target_alive`](Self::is_target_alive) is false and invoking the
139    /// delegate does nothing.
140    ///
141    /// Deviation (DEVIATIONS.md, Bindings): the managed delegate has its
142    /// target strongly, and so has the command made from it. A template that
143    /// binds a command of one of its parts to a method of the templated
144    /// control is a cycle there (the control, its template, the part, the
145    /// value of its command property, the control), which the collector
146    /// frees; without one it would never be freed.
147    pub fn for_method_of_source(
148        target: &BoxedValue,
149        declaring_type: &'static MarkupType,
150        method: &'static MarkupMethod,
151    ) -> Self {
152        let target = match method.is_static {
153            true => DelegateTarget::Strong(None),
154            false => DelegateTarget::Weak(WeakValue::new(target)),
155        };
156        Self::bound(target, declaring_type, method)
157    }
158
159    fn bound(target: DelegateTarget, declaring_type: &'static MarkupType, method: &'static MarkupMethod) -> Self {
160        let bound = target.clone();
161        Self {
162            call: Rc::new(move |arguments| match bound.get() {
163                Ok(target) => invoke_method(method, &target, arguments).ok().flatten(),
164                Err(()) => None,
165            }),
166            method: Some(Rc::new(MarkupDelegateMethod { target, declaring_type, method })),
167        }
168    }
169
170    /// Calls the callback.
171    pub fn invoke(&self, arguments: &[MarkupValue]) -> MarkupValue {
172        (self.call)(arguments)
173    }
174
175    /// Calls the callback. For the delegate of a declared method
176    /// ([`for_method`](Self::for_method)) a failure of the call (wrong
177    /// arguments, a failing member) is returned.
178    pub fn try_invoke(&self, arguments: &[MarkupValue]) -> Result<MarkupValue, MarkupInvokeError> {
179        match &self.method {
180            Some(bound) => match bound.target.get() {
181                Ok(target) => invoke_method(bound.method, &target, arguments),
182                Err(()) => Ok(None),
183            },
184            None => Ok((self.call)(arguments)),
185        }
186    }
187
188    /// The instance the delegate of a declared instance method is bound to
189    /// (the `Target` of the managed original). `None` for a static method
190    /// and for a delegate that was not created from a declared method.
191    pub fn target(&self) -> MarkupValue {
192        self.method.as_ref().and_then(|bound| bound.target.get().ok().flatten())
193    }
194
195    /// Whether the delegate can still call what it was created for: false
196    /// once the target of the delegate of a binding source
197    /// ([`for_method_of_source`](Self::for_method_of_source)) is gone.
198    pub fn is_target_alive(&self) -> bool {
199        self.method.as_ref().is_none_or(|bound| bound.target.get().is_ok())
200    }
201
202    /// The declared method the delegate was created from (the `Method` of
203    /// the managed original), if it was created with
204    /// [`for_method`](Self::for_method).
205    pub fn method(&self) -> Option<&'static MarkupMethod> {
206        self.method.as_ref().map(|bound| bound.method)
207    }
208
209    /// The type whose metadata declares [`method`](Self::method).
210    pub fn declaring_type(&self) -> Option<&'static MarkupType> {
211        self.method.as_ref().map(|bound| bound.declaring_type)
212    }
213}
214
215fn invoke_method(
216    method: &'static MarkupMethod,
217    target: &MarkupValue,
218    arguments: &[MarkupValue],
219) -> Result<MarkupValue, MarkupInvokeError> {
220    if method.is_static {
221        return (method.invoke)(arguments);
222    }
223    let mut all = Vec::with_capacity(arguments.len() + 1);
224    all.push(target.clone());
225    all.extend(arguments.iter().cloned());
226    (method.invoke)(&all)
227}
228
229impl PartialEq for MarkupDelegate {
230    fn eq(&self, other: &Self) -> bool {
231        Rc::ptr_eq(&self.call, &other.call)
232    }
233}
234
235impl fmt::Debug for MarkupDelegate {
236    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237        f.write_str("MarkupDelegate")
238    }
239}
240
241/// The name of the delegate type, as the managed original prints a delegate
242/// (`System.Action`, ``System.Action`1[System.Int32]``,
243/// ``System.Func`2[System.Object,System.Boolean]``) for the delegate of a
244/// declared method; `System.Delegate` otherwise.
245impl fmt::Display for MarkupDelegate {
246    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247        let Some(method) = self.method() else {
248            return f.write_str("System.Delegate");
249        };
250        let mut types: Vec<String> =
251            method.parameters.iter().map(|parameter| ValueTypes::type_full_name(parameter())).collect();
252        let definition = match method.return_type {
253            Some(return_type) => {
254                types.push(ValueTypes::type_full_name(return_type()));
255                "System.Func"
256            }
257            None => "System.Action",
258        };
259        match types.len() {
260            0 => f.write_str(definition),
261            count => write!(f, "{definition}`{count}[{}]", types.join(",")),
262        }
263    }
264}
265
266/// Converts a typed value to its untyped form: null for `()` and for an
267/// empty nullable, the contents of a nullable, the object itself for a
268/// reference type, the value unchanged if it is already untyped.
269pub fn into_markup_value<T: PartialEq + 'static>(value: T) -> MarkupValue {
270    {
271        let any: &dyn Any = &value;
272        if let Some(untyped) = any.downcast_ref::<BoxedValue>() {
273            return Some(untyped.clone());
274        }
275        if let Some(untyped) = any.downcast_ref::<Option<BoxedValue>>() {
276            return untyped.clone();
277        }
278        if any.is::<()>() {
279            return None;
280        }
281    }
282    untyped_markup_value(Rc::new(value))
283}
284
285/// The untyped form of a boxed typed value (the part of
286/// [`into_markup_value`] that does not depend on the type of the value).
287fn untyped_markup_value(boxed: BoxedValue) -> MarkupValue {
288    match ValueTypes::try_cast(&boxed, ValueType::of::<Option<BoxedValue>>()) {
289        Some(untyped) => untyped.downcast_ref::<Option<BoxedValue>>().cloned().flatten(),
290        None => Some(boxed),
291    }
292}
293
294/// Converts an untyped value to the Rust type `T` with the assignability
295/// casts of [`ValueTypes`]. `None` if the value is not assignable to `T`.
296pub fn from_markup_value<T: Clone + 'static>(value: &MarkupValue) -> Option<T> {
297    let target = TypeId::of::<T>();
298    if target == TypeId::of::<Option<BoxedValue>>() {
299        let any: &dyn Any = value;
300        return any.downcast_ref::<T>().cloned();
301    }
302    match value {
303        Some(boxed) => {
304            if let Some(exact) = boxed.downcast_ref::<T>() {
305                return Some(exact.clone());
306            }
307            if target == TypeId::of::<BoxedValue>() {
308                let any: &dyn Any = boxed;
309                return any.downcast_ref::<T>().cloned();
310            }
311            if let Some(cast) = ValueTypes::try_cast(boxed, ValueType::of::<T>()) {
312                return cast.downcast_ref::<T>().cloned();
313            }
314            // A handle of a base class whose object is an instance of the class `T` names:
315            // an untyped call checks its arguments against the run-time class of the object
316            // (a binding reads a member of the class of the element it found through a
317            // handle of `Control` or of the root class).
318            let object = ValueTypes::as_object(&**boxed)?;
319            let cast = match ValueTypes::from_object(target, object.clone()) {
320                Some(cast) => cast,
321                None => ValueTypes::try_convert_registered(&(Rc::new(object) as BoxedValue), ValueType::of::<T>())?,
322            };
323            cast.downcast_ref::<T>().cloned()
324        }
325        None => {
326            let null = ValueTypes::try_convert(None, ValueType::of::<T>())??;
327            null.downcast_ref::<T>().cloned()
328        }
329    }
330}
331
332/// Maps the error of a fallible member to [`MarkupInvokeError::Failed`]; see
333/// the `try` forms of [`ferro_markup_type!`](crate::ferro_markup_type).
334pub fn markup_result<T, E: fmt::Display>(result: Result<T, E>) -> Result<T, MarkupInvokeError> {
335    result.map_err(|error| MarkupInvokeError::Failed(error.to_string()))
336}
337
338/// The arguments of an untyped call, read in order by a generated invoker.
339pub struct MarkupArguments<'a> {
340    arguments: &'a [MarkupValue],
341    next: usize,
342}
343
344impl<'a> MarkupArguments<'a> {
345    /// Checks the number of arguments.
346    pub fn new(arguments: &'a [MarkupValue], expected: usize) -> Result<Self, MarkupInvokeError> {
347        if arguments.len() != expected {
348            return Err(MarkupInvokeError::ArgumentCount { expected, actual: arguments.len() });
349        }
350        Ok(Self { arguments, next: 0 })
351    }
352
353    /// The next argument, as a `T`.
354    pub fn next<T: Clone + 'static>(&mut self) -> Result<T, MarkupInvokeError> {
355        let index = self.next;
356        self.next += 1;
357        let value = &self.arguments[index];
358        from_markup_value::<T>(value).ok_or_else(|| Self::argument_error(index, std::any::type_name::<T>(), value))
359    }
360
361    /// The error of an argument that is not assignable to the type asked for.
362    #[cold]
363    fn argument_error(index: usize, expected: &'static str, value: &MarkupValue) -> MarkupInvokeError {
364        MarkupInvokeError::Argument {
365            index,
366            expected,
367            actual: match value {
368                Some(value) => value.type_name().to_string(),
369                None => "null".to_string(),
370            },
371        }
372    }
373}
374
375/// What kind of type a [`MarkupType`] describes.
376#[derive(Clone, Copy, Debug, PartialEq, Eq)]
377pub enum MarkupTypeKind {
378    /// A reference type: a class of the object model or a plain shared type.
379    Class,
380    /// A value type.
381    Struct,
382    /// An enumeration; [`MarkupType::enum_members`] lists its members.
383    Enum,
384    /// A contract (a trait used through a handle).
385    Interface,
386    /// A type that cannot be instantiated and only owns static members.
387    Static,
388}
389
390/// A constant argument of a [`MarkupAttribute`].
391#[derive(Clone, Copy)]
392pub enum MarkupAttributeValue {
393    Null,
394    Bool(bool),
395    Int(i64),
396    Float(f64),
397    Str(&'static str),
398    Type(TypeOf),
399    /// An array argument (`new[] { ",", " " }` of the managed original).
400    Array(&'static [MarkupAttributeValue]),
401}
402
403impl fmt::Debug for MarkupAttributeValue {
404    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
405        match self {
406            Self::Null => f.write_str("null"),
407            Self::Bool(value) => write!(f, "{value}"),
408            Self::Int(value) => write!(f, "{value}"),
409            Self::Float(value) => write!(f, "{value:?}"),
410            Self::Str(value) => write!(f, "{value:?}"),
411            Self::Type(type_) => write!(f, "type({})", type_()),
412            Self::Array(items) => f.debug_list().entries(items.iter()).finish(),
413        }
414    }
415}
416
417impl PartialEq for MarkupAttributeValue {
418    fn eq(&self, other: &Self) -> bool {
419        match (self, other) {
420            (Self::Null, Self::Null) => true,
421            (Self::Bool(a), Self::Bool(b)) => a == b,
422            (Self::Int(a), Self::Int(b)) => a == b,
423            (Self::Float(a), Self::Float(b)) => a == b,
424            (Self::Str(a), Self::Str(b)) => a == b,
425            (Self::Type(a), Self::Type(b)) => a() == b(),
426            (Self::Array(a), Self::Array(b)) => a == b,
427            _ => false,
428        }
429    }
430}
431
432/// Turns a literal of an attribute declaration into a
433/// [`MarkupAttributeValue`] in constant context; see
434/// [`ferro_markup_type!`](crate::ferro_markup_type).
435#[doc(hidden)]
436pub struct MarkupLiteral<T>(pub T);
437
438impl MarkupLiteral<&'static str> {
439    pub const fn value(self) -> MarkupAttributeValue {
440        MarkupAttributeValue::Str(self.0)
441    }
442}
443
444impl MarkupLiteral<bool> {
445    pub const fn value(self) -> MarkupAttributeValue {
446        MarkupAttributeValue::Bool(self.0)
447    }
448}
449
450impl MarkupLiteral<i64> {
451    pub const fn value(self) -> MarkupAttributeValue {
452        MarkupAttributeValue::Int(self.0)
453    }
454}
455
456impl MarkupLiteral<f64> {
457    pub const fn value(self) -> MarkupAttributeValue {
458        MarkupAttributeValue::Float(self.0)
459    }
460}
461
462impl MarkupLiteral<char> {
463    pub const fn value(self) -> MarkupAttributeValue {
464        MarkupAttributeValue::Int(self.0 as i64)
465    }
466}
467
468/// An attribute of a type or member: the data of a custom attribute of the
469/// managed original (`[DependsOn("Property")]`,
470/// `[TemplateContent(TemplateResultType = typeof(..))]`).
471///
472/// `name` is the attribute name without the `Attribute` suffix; the names of
473/// the attributes the framework itself understands are the constants of
474/// [`attributes`](super::attributes).
475#[derive(Clone, Copy, Debug, PartialEq)]
476pub struct MarkupAttribute {
477    pub name: &'static str,
478    /// The constructor arguments.
479    pub arguments: &'static [MarkupAttributeValue],
480    /// The named arguments.
481    pub properties: &'static [(&'static str, MarkupAttributeValue)],
482}
483
484impl MarkupAttribute {
485    /// The named argument `name`.
486    pub fn property(&self, name: &str) -> Option<MarkupAttributeValue> {
487        self.properties.iter().find(|(n, _)| *n == name).map(|(_, value)| *value)
488    }
489}
490
491/// The name and attributes of a parameter of a [`MarkupConstructor`]
492/// (`[InheritDataTypeFrom(..)] FerroProperty property` of the managed
493/// original).
494#[derive(Clone, Copy, Debug, PartialEq)]
495pub struct MarkupParameter {
496    /// The parameter name, when the declaration states it.
497    pub name: Option<&'static str>,
498    pub attributes: &'static [MarkupAttribute],
499}
500
501impl MarkupConstructor {
502    /// The declared name of parameter `index`.
503    pub fn parameter_name(&self, index: usize) -> Option<&'static str> {
504        self.parameter_info.get(index).and_then(|parameter| parameter.name)
505    }
506
507    /// The declared attributes of parameter `index`.
508    pub fn parameter_attributes(&self, index: usize) -> &'static [MarkupAttribute] {
509        self.parameter_info.get(index).map_or(&[], |parameter| parameter.attributes)
510    }
511}
512
513/// A constructor with arguments. (The parameterless constructor of a class
514/// is its [`TypeInfo::default_constructor`]; other types list it here with
515/// no parameters.)
516#[derive(Clone, Copy)]
517pub struct MarkupConstructor {
518    pub parameters: &'static [TypeOf],
519    /// What the declaration states about each parameter beyond its type
520    /// (its name and attributes), by index. Empty when the constructor is
521    /// declared in the positional form `(A, B) => callable`, otherwise as
522    /// long as [`parameters`](Self::parameters).
523    pub parameter_info: &'static [MarkupParameter],
524    /// Creates the instance from the arguments.
525    pub invoke: MarkupInvoke,
526    /// The typed function the declaration generated for the constructor
527    /// (see [`MarkupEmit`]): `__markup_new_<n>(a0: A, ..) -> T`, where `T` is
528    /// the value type of the declared type ([`MarkupType::value`]).
529    pub emit: CompilerMetadata<Option<MarkupEmit>>,
530}
531
532/// A property that is not a registered property: a plain property with a
533/// getter and/or a setter. Collections are read-only properties whose type
534/// has an `Add` method.
535#[derive(Clone, Copy)]
536pub struct MarkupProperty {
537    pub name: &'static str,
538    pub type_: TypeOf,
539    /// Reads the property: `(instance) -> value`.
540    pub get: Option<MarkupInvoke>,
541    /// Writes the property: `(instance, value)`.
542    pub set: Option<MarkupInvoke>,
543    pub attributes: &'static [MarkupAttribute],
544    /// Adds the TYPED element of this property to a compiled binding path
545    /// built at run time (what `CompiledBindingPathBuilder::typed_property`
546    /// adds in generated code), so that a binding whose path is this single
547    /// property is a typed binding expression. Generated by the declaration
548    /// forms from the accessors; the hook returns `None` (and the caller
549    /// uses the untyped element) unless the instance type of the declaration
550    /// is a shared reference type `Rc<S>` (notifying or not). `None` for a static
551    /// property and for a property with a fallible setter. See
552    /// [`typed_path`](super::typed_path).
553    pub typed_path_element: Option<super::typed_path::TypedPathElement>,
554    /// The typed accessor functions the declaration generated for the
555    /// getter and the setter (see [`MarkupEmit`]); `None` for an accessor
556    /// that is not declared.
557    pub emit_get: CompilerMetadata<Option<MarkupEmit>>,
558    pub emit_set: CompilerMetadata<Option<MarkupEmit>>,
559}
560
561/// What only the emitter of Rust source reads (the typed functions of
562/// [`MarkupEmit`], the instance and value types of a declaration): the value
563/// itself with the `compiler-metadata` feature, a zero-sized [`NotRecorded`]
564/// without it, so that shipped applications carry neither the data nor the
565/// code the declaration macros would generate for it.
566#[cfg(feature = "compiler-metadata")]
567pub type CompilerMetadata<T> = T;
568
569/// What only the emitter of Rust source reads; see the other definition.
570#[cfg(not(feature = "compiler-metadata"))]
571pub type CompilerMetadata<T> = NotRecorded<T>;
572
573/// The zero-sized stand-in of [`CompilerMetadata`] without the
574/// `compiler-metadata` feature: nothing is recorded.
575pub struct NotRecorded<T>(std::marker::PhantomData<fn() -> T>);
576
577impl<T> NotRecorded<T> {
578    /// Nothing.
579    pub const fn new() -> Self {
580        Self(std::marker::PhantomData)
581    }
582}
583
584impl<T> Clone for NotRecorded<T> {
585    fn clone(&self) -> Self {
586        *self
587    }
588}
589
590impl<T> Copy for NotRecorded<T> {}
591
592impl<T> fmt::Debug for NotRecorded<T> {
593    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
594        f.write_str("NotRecorded")
595    }
596}
597
598/// The value of a [`CompilerMetadata`] slot a declaration leaves empty.
599#[cfg(feature = "compiler-metadata")]
600pub const fn not_recorded<T>() -> CompilerMetadata<Option<T>> {
601    None
602}
603
604/// The value of a [`CompilerMetadata`] slot a declaration leaves empty.
605#[cfg(not(feature = "compiler-metadata"))]
606pub const fn not_recorded<T>() -> CompilerMetadata<Option<T>> {
607    NotRecorded::new()
608}
609
610/// A typed function the declaration forms generate for a declared member,
611/// for the emitter of Rust source: an associated function of the declared
612/// type (`#[doc(hidden)] pub fn __markup_get_Child(this: &Ref<Border>) -> ..`),
613/// public wherever the type is, that calls the declared callable with
614/// exactly the declared types. Generated code calls it by the public path
615/// of the type and `function`, whatever form the callable has (a path or a
616/// closure).
617///
618/// | Member | Function |
619/// |---|---|
620/// | property getter / setter | `__markup_get_<Name>(this: &This) -> T` / `__markup_set_<Name>(this: &This, value: T)` |
621/// | static property getter / setter | `__markup_static_get_<Name>() -> T` / `__markup_static_set_<Name>(value: T)` |
622/// | method (instance or static), in declaration order `n` | `__markup_<Name>_<n>([this: &This,] a0: A, ..) -> R` |
623/// | constructor, in declaration order `n` | `__markup_new_<n>(a0: A, ..) -> T` |
624/// | static field | `__markup_field_<Name>() -> T` |
625/// | `Parse(string)` | `__markup_parse(text: String) -> Result<T, MarkupInvokeError>` |
626///
627/// A fallible member (`try`) returns `Result<T, MarkupInvokeError>`
628/// ([`markup_result`] of the callable's result).
629#[derive(Clone, Copy, Debug, PartialEq, Eq)]
630pub struct MarkupEmit {
631    /// The name of the associated function.
632    pub function: &'static str,
633    /// Whether the function returns `Result<_, MarkupInvokeError>`.
634    pub fallible: bool,
635}
636
637/// An indexer (`this[..]` of the managed original): a property with index
638/// parameters. Binding paths reach it with `Path[0]` / `Path[key]`.
639#[derive(Clone, Copy)]
640pub struct MarkupIndexer {
641    /// The types of the index parameters, in order.
642    pub parameters: &'static [TypeOf],
643    /// The type of the values of the indexer.
644    pub type_: TypeOf,
645    /// Reads the value: `(instance, index..) -> value`.
646    pub get: Option<MarkupInvoke>,
647    /// Writes the value: `(instance, index.., value)`.
648    pub set: Option<MarkupInvoke>,
649    pub attributes: &'static [MarkupAttribute],
650}
651
652/// A method: an instance method (`Add`, a command method, an event handler)
653/// or a static one (`Parse`, a factory method, an attached property
654/// accessor).
655#[derive(Clone, Copy)]
656pub struct MarkupMethod {
657    pub name: &'static str,
658    pub is_static: bool,
659    /// The parameter types, without the instance.
660    pub parameters: &'static [TypeOf],
661    /// `None` for a method that returns nothing.
662    pub return_type: Option<TypeOf>,
663    /// Calls the method: `(instance, arguments..)`, or `(arguments..)` for
664    /// a static method.
665    pub invoke: MarkupInvoke,
666    pub attributes: &'static [MarkupAttribute],
667    /// The typed function the declaration generated for the method (see
668    /// [`MarkupEmit`]).
669    pub emit: CompilerMetadata<Option<MarkupEmit>>,
670}
671
672/// A static field of the managed original: a `static readonly` field or a
673/// constant (`Button.ClickEvent`, `ObjectConverters.IsNull`). A static
674/// PROPERTY (`static T Name { get; }`: `Brushes.Red`) is declared in
675/// [`MarkupType::static_properties`].
676#[derive(Clone, Copy)]
677pub struct MarkupField {
678    pub name: &'static str,
679    pub type_: TypeOf,
680    pub get: fn() -> MarkupValue,
681    pub attributes: &'static [MarkupAttribute],
682    /// The typed function of the field, for the emitter of Rust source.
683    pub emit: CompilerMetadata<Option<MarkupEmit>>,
684}
685
686/// An event that is not a routed event: handlers are attached through
687/// `add`.
688#[derive(Clone, Copy)]
689pub struct MarkupEvent {
690    pub name: &'static str,
691    /// The types of the arguments the event passes to its handlers
692    /// (sender first, where the event has one).
693    pub arguments: &'static [TypeOf],
694    /// Subscribes a handler: `(instance, handler)`, where the handler is a
695    /// [`MarkupDelegate`] called with the event arguments in untyped form.
696    pub add: MarkupInvoke,
697}
698
699/// A member of an enumeration.
700#[derive(Clone, Copy)]
701pub struct MarkupEnumMember {
702    pub name: &'static str,
703    /// The numeric value (the bits, for a flags enumeration).
704    pub value: i64,
705    /// The member as a value of the enumeration type.
706    pub get: fn() -> BoxedValue,
707    /// The identifier of the Rust variant of a plain enumeration (the member
708    /// name unless the declaration renames it), for the emitter of Rust
709    /// source: the member is `<public path of the type>::<rust_variant>`.
710    /// `None` for the members of a set of flags (their constants are
711    /// arbitrary expressions).
712    pub rust_variant: Option<&'static str>,
713}
714
715/// States that a type is an instantiation of a generic type
716/// (`FerroList<T>`): the name of the definition with its arity, as the
717/// managed original spells it (``FerroList`1``), and the type arguments.
718#[derive(Clone, Copy)]
719pub struct MarkupGeneric {
720    pub definition: &'static str,
721    pub arguments: &'static [TypeOf],
722}
723
724/// The markup metadata of a type. Built by the declaration macros as
725/// constant data; see the [module documentation](self).
726#[derive(Clone, Copy)]
727pub struct MarkupType {
728    /// The type name, without namespace, as markup spells it.
729    pub name: &'static str,
730    /// The dotted namespace, when it is not the namespace registered for
731    /// [`module_path`](Self::module_path) (types that mirror runtime library
732    /// types state `"System"` here).
733    pub explicit_namespace: Option<&'static str>,
734    /// The Rust module that declares the type (`module_path!()`).
735    pub module_path: &'static str,
736    pub kind: MarkupTypeKind,
737    /// The Rust types values of this type are held in, the untyped
738    /// (canonical) form first: `[Ref<T>, Option<Ref<T>>]` for a class,
739    /// `[T, Rc<T>, Option<Rc<T>>]` for a reference type, `[T]` for a
740    /// value type (its nullable form `Option<T>` is a type of its own, as
741    /// in the managed original), `[Rc<dyn I>, Option<Rc<dyn I>>]` for a
742    /// contract. Empty for static types.
743    pub handles: &'static [TypeOf],
744    /// The nullable form of a value type or enumeration (`Option<T>`), which
745    /// is a type of its own (the `Nullable<T>` of the managed original).
746    /// `None` for every other kind of type.
747    pub nullable: Option<TypeOf>,
748    /// The class of the object model this metadata belongs to, if any.
749    pub type_info: Option<fn() -> &'static TypeInfo>,
750    /// The base type (by one of its handles). Classes of the object model
751    /// leave this empty: their base is [`TypeInfo::base_type`].
752    pub base: Option<TypeOf>,
753    /// The contracts the type implements (by their handles), in addition
754    /// to the ones of its base type.
755    pub interfaces: &'static [TypeOf],
756    pub generic: Option<MarkupGeneric>,
757    /// The name of the content property (the `[Content]` attribute of the
758    /// managed original). Inherited by deriving types.
759    pub content_property: Option<&'static str>,
760    /// Converts text to a value of the type: `(text) -> value`. The
761    /// `Parse(string)` method of the managed original.
762    pub parse: Option<MarkupInvoke>,
763    pub constructors: &'static [MarkupConstructor],
764    pub properties: &'static [MarkupProperty],
765    /// The indexers the type declares (not the ones of its base types), in
766    /// declaration order.
767    pub indexers: &'static [MarkupIndexer],
768    /// Attributes of REGISTERED properties (styled, direct, attached) the
769    /// type declares or owns, by property name. Registered properties need
770    /// no declaration; this only carries what the property system does not
771    /// know about them (`[DependsOn]`, `[ResolveByName]`,
772    /// `[InheritDataTypeFromItems]`, `[TemplateContent]`, ...).
773    pub property_attributes: &'static [(&'static str, &'static [MarkupAttribute])],
774    pub methods: &'static [MarkupMethod],
775    /// The static fields and constants (`static readonly` / `const` of the
776    /// managed original).
777    pub fields: &'static [MarkupField],
778    /// The static properties (`static T Name { get; set; }` of the managed
779    /// original): the accessors take no instance, `get` is `() -> value`
780    /// and `set` is `(value)`.
781    pub static_properties: &'static [MarkupProperty],
782    pub events: &'static [MarkupEvent],
783    pub enum_members: &'static [MarkupEnumMember],
784    /// Whether an enumeration is a set of flags.
785    pub is_flags: bool,
786    /// Converts a numeric value to a value of the enumeration: the cast
787    /// `(TEnum)value` of the managed original. For a plain enumeration the
788    /// value must be the value of a member; for a set of flags any
789    /// combination of the bits of its members.
790    pub enum_from_value: Option<fn(i64) -> Option<BoxedValue>>,
791    /// The numeric value of a value of the enumeration: the cast
792    /// `(int)value` of the managed original. `None` for a value that is not
793    /// of the enumeration type.
794    pub enum_to_value: Option<fn(&dyn crate::AnyValue) -> Option<i64>>,
795    pub attributes: &'static [MarkupAttribute],
796    /// Views an untyped value of this type as a source of property change
797    /// notifications (the `INotifyPropertyChanged` of the managed original),
798    /// for types that are not classes of the object model: view models.
799    /// Bindings resolved through metadata (reflection bindings, compiled
800    /// bindings built at run time) subscribe through it; `None` means the
801    /// properties of the type are read once.
802    pub notify_property_changed:
803        Option<fn(&dyn crate::AnyValue) -> Option<&dyn crate::data::model::INotifyPropertyChanged>>,
804    /// The Rust type instance members receive (`&This`): the `this:` of the
805    /// declaration, else the declared type (`Ref<Class>` for a class). The
806    /// typed functions of the instance members ([`MarkupEmit`]) take it.
807    pub this: CompilerMetadata<Option<TypeOf>>,
808    /// The Rust type of a value of the type as its constructors and its
809    /// `Parse` return it, and so their typed functions ([`MarkupEmit`]):
810    /// the instance type when the declaration states `this:`, else the
811    /// first of its handles, else the declared type (`Rc<dyn Trait>` for a
812    /// contract). `Ref<Class>` for a class.
813    pub value: CompilerMetadata<Option<TypeOf>>,
814}
815
816impl MarkupType {
817    /// Metadata that states nothing but the name and kind of the type.
818    pub const fn new(name: &'static str, kind: MarkupTypeKind, module_path: &'static str) -> Self {
819        Self {
820            name,
821            explicit_namespace: None,
822            module_path,
823            kind,
824            handles: &[],
825            nullable: None,
826            type_info: None,
827            base: None,
828            interfaces: &[],
829            generic: None,
830            content_property: None,
831            parse: None,
832            constructors: &[],
833            properties: &[],
834            indexers: &[],
835            property_attributes: &[],
836            methods: &[],
837            fields: &[],
838            static_properties: &[],
839            events: &[],
840            enum_members: &[],
841            is_flags: false,
842            enum_from_value: None,
843            enum_to_value: None,
844            attributes: &[],
845            notify_property_changed: None,
846            this: not_recorded(),
847            value: not_recorded(),
848        }
849    }
850
851    #[cfg(feature = "compiler-metadata")]
852    /// Declares the public Rust paths of markup types: the metadata of a
853    /// type, the path another crate names the type by
854    /// (`"ferroui_base::layout::HorizontalAlignment"`) and whether the path
855    /// names a trait (a contract, whose values are `Rc<dyn Trait>`). Called
856    /// from the `register_types()` of a crate with the table of its
857    /// generated `rust_paths.rs` ([`ferro_rust_paths!`](crate::ferro_rust_paths)).
858    /// The emitter of Rust source reads the table; nothing else does.
859    pub fn register_rust_paths(paths: &[(&'static MarkupType, &'static str, bool)]) {
860        let mut table = rust_paths().write().unwrap_or_else(|e| e.into_inner());
861        for &(markup, path, is_trait) in paths {
862            table.insert(markup as *const MarkupType as usize, (markup, path, is_trait));
863        }
864    }
865
866    #[cfg(feature = "compiler-metadata")]
867    /// The public Rust path of the type
868    /// ([`register_rust_paths`](Self::register_rust_paths)), if its crate
869    /// recorded one; for a contract, the path of the trait.
870    pub fn rust_path(&'static self) -> Option<&'static str> {
871        self.rust_path_entry().map(|entry| entry.1)
872    }
873
874    #[cfg(feature = "compiler-metadata")]
875    /// Whether the recorded public Rust path names a trait.
876    pub fn rust_path_is_trait(&'static self) -> bool {
877        self.rust_path_entry().is_some_and(|entry| entry.2)
878    }
879
880    #[cfg(feature = "compiler-metadata")]
881    fn rust_path_entry(&'static self) -> Option<(&'static MarkupType, &'static str, bool)> {
882        rust_paths().read().unwrap_or_else(|e| e.into_inner()).get(&(self as *const MarkupType as usize)).copied()
883    }
884
885    #[cfg(feature = "compiler-metadata")]
886    /// Every markup type with a registered public Rust path, with the path
887    /// and whether it names a trait, in no particular order.
888    pub fn all_rust_paths() -> Vec<(&'static MarkupType, &'static str, bool)> {
889        rust_paths().read().unwrap_or_else(|e| e.into_inner()).values().copied().collect()
890    }
891
892    /// The dotted, markup-facing namespace of the type.
893    pub fn namespace(&self) -> &'static str {
894        match self.explicit_namespace {
895            Some(namespace) => namespace,
896            None => TypeInfo::namespace_of_module(self.module_path),
897        }
898    }
899
900    /// The namespace-qualified name of the type.
901    pub fn full_name(&self) -> String {
902        match self.namespace() {
903            "" => self.name.to_string(),
904            namespace => format!("{namespace}.{}", self.name),
905        }
906    }
907
908    /// The untyped (canonical) handle type of the type, if it has values.
909    pub fn handle(&self) -> Option<ValueType> {
910        self.handles.first().map(|handle| handle())
911    }
912
913    /// The plain property `name` declared by this type (not by its base
914    /// types).
915    pub fn find_property(&self, name: &str) -> Option<&'static MarkupProperty> {
916        self.properties.iter().find(|p| p.name == name)
917    }
918
919    /// The indexer this type declares (not its base types) that takes
920    /// `parameter_count` index arguments.
921    pub fn find_indexer(&self, parameter_count: usize) -> Option<&'static MarkupIndexer> {
922        self.indexers.iter().find(|indexer| indexer.parameters.len() == parameter_count)
923    }
924
925    /// The registered metadata of the base type ([`base`](Self::base)): for
926    /// a class of the object model the metadata of the nearest base class
927    /// that has any, otherwise the registered type that the base handle
928    /// belongs to. This is how untyped code walks the hierarchy of a type,
929    /// as reflection walks base classes.
930    pub fn base_type(&self) -> Option<&'static MarkupType> {
931        if let Some(type_info) = self.type_info {
932            let mut current = type_info().base_type();
933            while let Some(class) = current {
934                if let Some(markup) = class.markup() {
935                    return Some(markup);
936                }
937                current = class.base_type();
938            }
939        }
940        Self::find_by_handle(self.base?().id())
941    }
942
943    /// The attributes this type declares for its registered property `name`.
944    pub fn find_property_attributes(&self, name: &str) -> &'static [MarkupAttribute] {
945        self.property_attributes.iter().find(|(n, _)| *n == name).map_or(&[], |(_, attributes)| *attributes)
946    }
947
948    /// The methods named `name` declared by this type.
949    pub fn find_methods<'a>(&self, name: &'a str) -> impl Iterator<Item = &'static MarkupMethod> + 'a {
950        self.methods.iter().filter(move |m| m.name == name)
951    }
952
953    /// The static field `name` declared by this type.
954    pub fn find_field(&self, name: &str) -> Option<&'static MarkupField> {
955        self.fields.iter().find(|f| f.name == name)
956    }
957
958    /// The static property `name` declared by this type.
959    pub fn find_static_property(&self, name: &str) -> Option<&'static MarkupProperty> {
960        self.static_properties.iter().find(|p| p.name == name)
961    }
962
963    /// The event `name` declared by this type.
964    pub fn find_event(&self, name: &str) -> Option<&'static MarkupEvent> {
965        self.events.iter().find(|e| e.name == name)
966    }
967
968    /// The attribute `name` of the type.
969    pub fn find_attribute(&self, name: &str) -> Option<&'static MarkupAttribute> {
970        self.attributes.iter().find(|a| a.name == name)
971    }
972
973    /// The enumeration member `name`; `ignore_case` as the managed
974    /// `Enum.Parse(.., ignoreCase)`.
975    pub fn find_enum_member(&self, name: &str, ignore_case: bool) -> Option<&'static MarkupEnumMember> {
976        self.enum_members
977            .iter()
978            .find(|m| if ignore_case { m.name.eq_ignore_ascii_case(name) } else { m.name == name })
979    }
980
981    /// Adds a type to the process-wide table of types with markup metadata,
982    /// making it discoverable with [`find`](Self::find) and
983    /// [`find_by_handle`](Self::find_by_handle). Registering a type again
984    /// does nothing.
985    ///
986    /// A crate registers its types from its `register_types()` function.
987    /// The metadata of a class of the object model needs no registration to
988    /// be reachable from its runtime type ([`TypeInfo::markup`]).
989    pub fn register(type_: &'static MarkupType) {
990        Self::register_all(&[type_]);
991    }
992
993    /// Registers several types; see [`register`](Self::register).
994    pub fn register_all(types: &[&'static MarkupType]) {
995        let mut registry = registry().write().unwrap_or_else(|e| e.into_inner());
996        for type_ in types {
997            registry.insert(type_);
998        }
999    }
1000
1001    /// Registers the Rust type `H` as one more handle of the registered type `type_`: a
1002    /// type of another crate whose values are values of `type_` (a wrapper a property
1003    /// holds the value in), next to the [`handles`](Self::handles) the declaration lists.
1004    /// The crate that declares `H` also registers the casts between `H` and the handles
1005    /// of the type ([`ValueTypes::register_cast`]). A handle that is already known keeps
1006    /// its type.
1007    pub fn register_handle<H: 'static>(type_: &'static MarkupType) {
1008        let mut registry = registry().write().unwrap_or_else(|e| e.into_inner());
1009        registry.insert(type_);
1010        registry.by_handle.entry(TypeId::of::<H>()).or_insert(type_);
1011    }
1012
1013    /// Finds a registered type by namespace and name.
1014    pub fn find(namespace: &str, name: &str) -> Option<&'static MarkupType> {
1015        let candidates: Vec<&'static MarkupType> = {
1016            let registry = registry().read().unwrap_or_else(|e| e.into_inner());
1017            registry.by_name.get(name)?.clone()
1018        };
1019        candidates.into_iter().find(|t| t.namespace() == namespace)
1020    }
1021
1022    /// Finds the registered type that values of the Rust type `handle` are
1023    /// values of (any of its [`handles`](Self::handles)).
1024    pub fn find_by_handle(handle: TypeId) -> Option<&'static MarkupType> {
1025        let registry = registry().read().unwrap_or_else(|e| e.into_inner());
1026        registry.by_handle.get(&handle).copied()
1027    }
1028
1029    /// Finds the registered value type or enumeration whose nullable form
1030    /// ([`nullable`](Self::nullable)) is the Rust type `handle`.
1031    pub fn find_by_nullable_handle(handle: TypeId) -> Option<&'static MarkupType> {
1032        let registry = registry().read().unwrap_or_else(|e| e.into_inner());
1033        registry.by_nullable_handle.get(&handle).copied()
1034    }
1035
1036    /// Finds the registered metadata that belongs to the runtime type
1037    /// `type_` ([`type_info`](Self::type_info)): the metadata of a static
1038    /// type declared with `ferro_markup_type!(static X { type_info: X, .. })`.
1039    /// (The metadata of a class is its [`TypeInfo::markup`].)
1040    pub fn find_by_type_info(type_: &'static TypeInfo) -> Option<&'static MarkupType> {
1041        if let Some(markup) = type_.markup() {
1042            return Some(markup);
1043        }
1044        let registry = registry().read().unwrap_or_else(|e| e.into_inner());
1045        registry.by_type_info.get(&(type_ as *const TypeInfo as usize)).copied()
1046    }
1047
1048    /// Every registered type, in registration order.
1049    pub fn registered_types() -> Vec<&'static MarkupType> {
1050        registry().read().unwrap_or_else(|e| e.into_inner()).types.clone()
1051    }
1052}
1053
1054impl fmt::Debug for MarkupType {
1055    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1056        f.write_str(self.name)
1057    }
1058}
1059
1060/// A Rust type that declares markup metadata with
1061/// [`ferro_markup_type!`](crate::ferro_markup_type) or
1062/// [`ferro_markup_enum!`](crate::ferro_markup_enum).
1063pub trait MarkupTyped {
1064    /// The markup metadata of the type.
1065    const MARKUP: &'static MarkupType;
1066}
1067
1068#[derive(Default)]
1069struct MarkupRegistry {
1070    types: Vec<&'static MarkupType>,
1071    by_name: HashMap<&'static str, Vec<&'static MarkupType>>,
1072    by_handle: HashMap<TypeId, &'static MarkupType>,
1073    by_nullable_handle: HashMap<TypeId, &'static MarkupType>,
1074    by_type_info: HashMap<usize, &'static MarkupType>,
1075}
1076
1077impl MarkupRegistry {
1078    fn insert(&mut self, type_: &'static MarkupType) {
1079        let known = self.by_name.get(type_.name).is_some_and(|types| types.iter().any(|t| std::ptr::eq(*t, type_)));
1080        if known {
1081            return;
1082        }
1083        self.types.push(type_);
1084        self.by_name.entry(type_.name).or_default().push(type_);
1085        for handle in type_.handles {
1086            self.by_handle.entry(handle().id()).or_insert(type_);
1087        }
1088        if let Some(type_info) = type_.type_info {
1089            self.by_type_info.entry(type_info() as *const TypeInfo as usize).or_insert(type_);
1090        }
1091        if let Some(nullable) = type_.nullable {
1092            self.by_nullable_handle.entry(nullable().id()).or_insert(type_);
1093        }
1094    }
1095}
1096
1097#[cfg(feature = "compiler-metadata")]
1098fn rust_paths() -> &'static RwLock<HashMap<usize, (&'static MarkupType, &'static str, bool)>> {
1099    static PATHS: OnceLock<RwLock<HashMap<usize, (&'static MarkupType, &'static str, bool)>>> = OnceLock::new();
1100    PATHS.get_or_init(Default::default)
1101}
1102
1103fn registry() -> &'static RwLock<MarkupRegistry> {
1104    static REGISTRY: OnceLock<RwLock<MarkupRegistry>> = OnceLock::new();
1105    REGISTRY.get_or_init(Default::default)
1106}
1107
1108/// The names of the attributes the framework understands, for
1109/// [`MarkupAttribute::name`]. Each is the name of the attribute class of the
1110/// managed original without its `Attribute` suffix; arguments are the ones
1111/// of that class.
1112pub mod attributes {
1113    /// On a property: its value is content built on demand
1114    /// (`TemplateResultType` names the type of the built object).
1115    pub const TEMPLATE_CONTENT: &str = "TemplateContent";
1116    /// On a property: must be assigned after the named property.
1117    pub const DEPENDS_ON: &str = "DependsOn";
1118    /// On a property: a binding assigned in markup is stored as the value
1119    /// instead of being applied.
1120    pub const ASSIGN_BINDING: &str = "AssignBinding";
1121    /// On a type: instances are attached to their parent before their own
1122    /// properties are set.
1123    pub const USABLE_DURING_INITIALIZATION: &str = "UsableDuringInitialization";
1124    /// On a collection type: whitespace between its items is significant.
1125    pub const WHITESPACE_SIGNIFICANT_COLLECTION: &str = "WhitespaceSignificantCollection";
1126    /// On a type: whitespace around an element of the type is trimmed.
1127    pub const TRIM_SURROUNDING_WHITESPACE: &str = "TrimSurroundingWhitespace";
1128    /// On a type or property: names the converter type used to convert
1129    /// text.
1130    pub const TYPE_CONVERTER: &str = "TypeConverter";
1131    /// On a type: it is the scope of a control template.
1132    pub const CONTROL_TEMPLATE_SCOPE: &str = "ControlTemplateScope";
1133    /// On a property: it states the data type of the bindings in scope.
1134    pub const DATA_TYPE: &str = "DataType";
1135    /// On a property: the data type of its bindings is inherited from
1136    /// another property.
1137    pub const INHERIT_DATA_TYPE_FROM: &str = "InheritDataTypeFrom";
1138    /// On a property: the data type of its bindings is the item type of a
1139    /// collection property.
1140    pub const INHERIT_DATA_TYPE_FROM_ITEMS: &str = "InheritDataTypeFromItems";
1141    /// On a property: text assigned in markup is a name to resolve in the
1142    /// name scope.
1143    pub const RESOLVE_BY_NAME: &str = "ResolveByName";
1144    /// On a property of an option markup extension: the option it holds.
1145    pub const MARKUP_EXTENSION_OPTION: &str = "MarkupExtensionOption";
1146    /// On a property of an option markup extension: the default option.
1147    pub const MARKUP_EXTENSION_DEFAULT_OPTION: &str = "MarkupExtensionDefaultOption";
1148    /// On a type or property: how a list is parsed from text (separators,
1149    /// split options).
1150    pub const FERRO_LIST: &str = "FerroList";
1151    /// On a control type: a named part its template must contain.
1152    pub const TEMPLATE_PART: &str = "TemplatePart";
1153    /// On a control type: the pseudo-classes it sets.
1154    pub const PSEUDO_CLASSES: &str = "PseudoClasses";
1155    /// On any member: it is obsolete (the argument is the message).
1156    pub const OBSOLETE: &str = "Obsolete";
1157    /// On any member: it is not stable API.
1158    pub const UNSTABLE: &str = "Unstable";
1159    /// On a type: it is private API.
1160    pub const PRIVATE_API: &str = "PrivateApi";
1161    /// On a type: implemented only by the framework.
1162    pub const NOT_CLIENT_IMPLEMENTABLE: &str = "NotClientImplementable";
1163    /// On a property: the content property (stated with `content:` in the
1164    /// declaration forms; listed for completeness).
1165    pub const CONTENT: &str = "Content";
1166    /// On a constructor parameter or property of a markup extension.
1167    pub const CONSTRUCTOR_ARGUMENT: &str = "ConstructorArgument";
1168}