1
0

node.rs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. //! Items related to Nodes in the RealDom
  2. use rustc_hash::{FxHashMap, FxHashSet};
  3. use shipyard::Component;
  4. use std::{
  5. any::Any,
  6. fmt::{Debug, Display},
  7. };
  8. /// A element node in the RealDom
  9. #[derive(Debug, Clone, Default)]
  10. pub struct ElementNode<V: FromAnyValue = ()> {
  11. /// The [tag](https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName) of the element
  12. pub tag: String,
  13. /// The [namespace](https://developer.mozilla.org/en-US/docs/Web/API/Element/namespaceURI) of the element
  14. pub namespace: Option<String>,
  15. /// The attributes of the element
  16. pub attributes: FxHashMap<OwnedAttributeDiscription, OwnedAttributeValue<V>>,
  17. /// The events the element is listening for
  18. pub listeners: FxHashSet<String>,
  19. }
  20. impl ElementNode {
  21. /// Create a new element node
  22. pub fn new(tag: impl Into<String>, namespace: impl Into<Option<String>>) -> Self {
  23. Self {
  24. tag: tag.into(),
  25. namespace: namespace.into(),
  26. attributes: Default::default(),
  27. listeners: Default::default(),
  28. }
  29. }
  30. }
  31. /// A text node in the RealDom
  32. #[derive(Debug, Clone, Default)]
  33. pub struct TextNode {
  34. /// The text of the node
  35. pub text: String,
  36. /// The events the node is listening for
  37. pub listeners: FxHashSet<String>,
  38. }
  39. impl TextNode {
  40. /// Create a new text node
  41. pub fn new(text: String) -> Self {
  42. Self {
  43. text,
  44. listeners: Default::default(),
  45. }
  46. }
  47. }
  48. /// A type of node with data specific to the node type.
  49. #[derive(Debug, Clone, Component)]
  50. pub enum NodeType<V: FromAnyValue = ()> {
  51. /// A text node
  52. Text(TextNode),
  53. /// An element node
  54. Element(ElementNode<V>),
  55. /// A placeholder node. This can be used as a cheaper placeholder for a node that will be created later
  56. Placeholder,
  57. }
  58. impl<V: FromAnyValue, S: Into<String>> From<S> for NodeType<V> {
  59. fn from(text: S) -> Self {
  60. Self::Text(TextNode::new(text.into()))
  61. }
  62. }
  63. impl<V: FromAnyValue> From<TextNode> for NodeType<V> {
  64. fn from(text: TextNode) -> Self {
  65. Self::Text(text)
  66. }
  67. }
  68. impl<V: FromAnyValue> From<ElementNode<V>> for NodeType<V> {
  69. fn from(element: ElementNode<V>) -> Self {
  70. Self::Element(element)
  71. }
  72. }
  73. /// A discription of an attribute on a DOM node, such as `id` or `href`.
  74. #[derive(Debug, Clone, Hash, PartialEq, Eq)]
  75. pub struct OwnedAttributeDiscription {
  76. /// The name of the attribute.
  77. pub name: String,
  78. /// The namespace of the attribute used to identify what kind of attribute it is.
  79. ///
  80. /// For renderers that use HTML, this can be used to identify if the attribute is a style attribute.
  81. /// Instead of parsing the style attribute every time a style is changed, you can set an attribute with the `style` namespace.
  82. pub namespace: Option<String>,
  83. }
  84. impl From<String> for OwnedAttributeDiscription {
  85. fn from(name: String) -> Self {
  86. Self {
  87. name,
  88. namespace: None,
  89. }
  90. }
  91. }
  92. impl<S: Into<String>, N: Into<String>> From<(S, N)> for OwnedAttributeDiscription {
  93. fn from(name: (S, N)) -> Self {
  94. Self {
  95. name: name.0.into(),
  96. namespace: Some(name.1.into()),
  97. }
  98. }
  99. }
  100. /// An attribute on a DOM node, such as `id="my-thing"` or
  101. /// `href="https://example.com"`.
  102. #[derive(Clone, Copy, Debug)]
  103. pub struct OwnedAttributeView<'a, V: FromAnyValue = ()> {
  104. /// The discription of the attribute.
  105. pub attribute: &'a OwnedAttributeDiscription,
  106. /// The value of the attribute.
  107. pub value: &'a OwnedAttributeValue<V>,
  108. }
  109. /// The value of an attribute on a DOM node. This contains non-text values to allow users to skip parsing attribute values in some cases.
  110. #[derive(Clone)]
  111. pub enum OwnedAttributeValue<V: FromAnyValue = ()> {
  112. /// A string value. This is the most common type of attribute.
  113. Text(String),
  114. /// A floating point value.
  115. Float(f64),
  116. /// An integer value.
  117. Int(i64),
  118. /// A boolean value.
  119. Bool(bool),
  120. /// A custom value specific to the renderer
  121. Custom(V),
  122. }
  123. impl<V: FromAnyValue> From<String> for OwnedAttributeValue<V> {
  124. fn from(value: String) -> Self {
  125. Self::Text(value)
  126. }
  127. }
  128. impl<V: FromAnyValue> From<f64> for OwnedAttributeValue<V> {
  129. fn from(value: f64) -> Self {
  130. Self::Float(value)
  131. }
  132. }
  133. impl<V: FromAnyValue> From<i64> for OwnedAttributeValue<V> {
  134. fn from(value: i64) -> Self {
  135. Self::Int(value)
  136. }
  137. }
  138. impl<V: FromAnyValue> From<bool> for OwnedAttributeValue<V> {
  139. fn from(value: bool) -> Self {
  140. Self::Bool(value)
  141. }
  142. }
  143. impl<V: FromAnyValue> From<V> for OwnedAttributeValue<V> {
  144. fn from(value: V) -> Self {
  145. Self::Custom(value)
  146. }
  147. }
  148. /// Something that can be converted from a borrowed [Any] value.
  149. pub trait FromAnyValue: Clone + 'static {
  150. /// Convert from an [Any] value.
  151. fn from_any_value(value: &dyn Any) -> Self;
  152. }
  153. impl FromAnyValue for () {
  154. fn from_any_value(_: &dyn Any) -> Self {}
  155. }
  156. impl<V: FromAnyValue> Debug for OwnedAttributeValue<V> {
  157. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  158. match self {
  159. Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(),
  160. Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
  161. Self::Int(arg0) => f.debug_tuple("Int").field(arg0).finish(),
  162. Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
  163. Self::Custom(_) => f.debug_tuple("Any").finish(),
  164. }
  165. }
  166. }
  167. impl<V: FromAnyValue> Display for OwnedAttributeValue<V> {
  168. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  169. match self {
  170. Self::Text(arg0) => f.write_str(arg0),
  171. Self::Float(arg0) => f.write_str(&arg0.to_string()),
  172. Self::Int(arg0) => f.write_str(&arg0.to_string()),
  173. Self::Bool(arg0) => f.write_str(&arg0.to_string()),
  174. Self::Custom(_) => f.write_str("custom"),
  175. }
  176. }
  177. }
  178. #[cfg(feature = "dioxus")]
  179. impl<V: FromAnyValue> From<&dioxus_core::AttributeValue> for OwnedAttributeValue<V> {
  180. fn from(value: &dioxus_core::AttributeValue) -> Self {
  181. match value {
  182. dioxus_core::AttributeValue::Text(text) => Self::Text(text.clone()),
  183. dioxus_core::AttributeValue::Float(float) => Self::Float(*float),
  184. dioxus_core::AttributeValue::Int(int) => Self::Int(*int),
  185. dioxus_core::AttributeValue::Bool(bool) => Self::Bool(*bool),
  186. dioxus_core::AttributeValue::Any(any) => Self::Custom(V::from_any_value(any.as_any())),
  187. dioxus_core::AttributeValue::None => panic!("None attribute values result in removing the attribute, not converting it to a None value."),
  188. _ => panic!("Unsupported attribute value type"),
  189. }
  190. }
  191. }
  192. impl<V: FromAnyValue> OwnedAttributeValue<V> {
  193. /// Attempt to convert the attribute value to a string.
  194. pub fn as_text(&self) -> Option<&str> {
  195. match self {
  196. OwnedAttributeValue::Text(text) => Some(text),
  197. _ => None,
  198. }
  199. }
  200. /// Attempt to convert the attribute value to a float.
  201. pub fn as_float(&self) -> Option<f64> {
  202. match self {
  203. OwnedAttributeValue::Float(float) => Some(*float),
  204. OwnedAttributeValue::Int(int) => Some(*int as f64),
  205. _ => None,
  206. }
  207. }
  208. /// Attempt to convert the attribute value to an integer.
  209. pub fn as_int(&self) -> Option<i64> {
  210. match self {
  211. OwnedAttributeValue::Float(float) => Some(*float as i64),
  212. OwnedAttributeValue::Int(int) => Some(*int),
  213. _ => None,
  214. }
  215. }
  216. /// Attempt to convert the attribute value to a boolean.
  217. pub fn as_bool(&self) -> Option<bool> {
  218. match self {
  219. OwnedAttributeValue::Bool(bool) => Some(*bool),
  220. _ => None,
  221. }
  222. }
  223. /// Attempt to convert the attribute value to a custom value.
  224. pub fn as_custom(&self) -> Option<&V> {
  225. match self {
  226. OwnedAttributeValue::Custom(custom) => Some(custom),
  227. _ => None,
  228. }
  229. }
  230. }