Skip to main content

ferroui_base/
i_named.rs

1//! Port of `INamed.cs`.
2
3use crate::{ObjectType, Ref, StyledElement, Upcast};
4use std::rc::Rc;
5
6/// Objects implementing this contract and providing a value for
7/// [`name`](INamed::name) are registered in the relevant name scope when
8/// constructed in markup.
9pub trait INamed {
10    /// Gets the element name.
11    fn name(&self) -> Option<String>;
12
13    /// The identity of the object, used for reference equality.
14    #[doc(hidden)]
15    fn reference_id(&self) -> *const () {
16        self as *const Self as *const ()
17    }
18}
19
20/// Handles compare by identity (reference equality): two handles are equal
21/// when they refer to the same object, whichever adapter they were made
22/// from.
23impl PartialEq for dyn INamed {
24    #[inline]
25    fn eq(&self, other: &Self) -> bool {
26        self.reference_id() == other.reference_id()
27    }
28}
29
30/// Implements the contract for the styled element behind a class handle.
31struct StyledElementNamed(Ref<StyledElement>);
32
33impl INamed for StyledElementNamed {
34    fn name(&self) -> Option<String> {
35        self.0.name()
36    }
37
38    fn reference_id(&self) -> *const () {
39        &*self.0 as *const StyledElement as *const ()
40    }
41}
42
43impl<T: ObjectType + Upcast<StyledElement>> From<Ref<T>> for Rc<dyn INamed> {
44    fn from(value: Ref<T>) -> Self {
45        Rc::new(StyledElementNamed(value.upcast()))
46    }
47}
48
49impl<T: ObjectType + Upcast<StyledElement>> From<&Ref<T>> for Rc<dyn INamed> {
50    fn from(value: &Ref<T>) -> Self {
51        Rc::new(StyledElementNamed(value.clone().upcast()))
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use crate::data::core::{ValueType, ValueTypes};
59    use crate::BoxedValue;
60
61    #[test]
62    fn styled_elements_are_named() {
63        let element = StyledElement::new();
64        element.set_name(Some("root".to_string()));
65        let named: Rc<dyn INamed> = (&element).into();
66        assert_eq!(named.name().as_deref(), Some("root"));
67
68        let again: Rc<dyn INamed> = element.clone().into();
69        let other: Rc<dyn INamed> = StyledElement::new().into();
70        assert!(*named == *again);
71        assert!(*named != *other);
72    }
73
74    #[test]
75    fn the_handle_of_a_styled_element_casts_to_the_contract() {
76        let element = StyledElement::new();
77        assert!(StyledElement::TYPE.interfaces().iter().any(|i| i() == ValueType::of::<Rc<dyn INamed>>()));
78        let boxed: BoxedValue = Rc::new(element.clone());
79        let cast = ValueTypes::try_cast(&boxed, ValueType::of::<Rc<dyn INamed>>()).expect("the cast is declared");
80        assert!(cast.downcast_ref::<Rc<dyn INamed>>().is_some());
81    }
82}