11//! Element attributes
2+ use std:: borrow:: Borrow ;
23// #![deny(missing_docs)]
4+ use std:: ops:: Deref ;
5+
36use anathema_store:: remotecell:: RemoteCell ;
47use anathema_store:: slab:: SecondaryMap ;
58use anathema_store:: smallmap:: { SmallIndex , SmallMap } ;
@@ -24,23 +27,162 @@ impl<'bp> AllAttributes<'bp> {
2427 }
2528}
2629
30+ #[ derive( Debug , Copy , Clone , PartialEq ) ]
31+ pub enum ValueKey < ' bp > {
32+ Value ,
33+ Attribute ( & ' bp str ) ,
34+ }
35+
36+ impl ValueKey < ' _ > {
37+ pub fn as_str ( & self ) -> & str {
38+ match self {
39+ ValueKey :: Value => "[value]" ,
40+ ValueKey :: Attribute ( name) => name,
41+ }
42+ }
43+ }
44+
45+ impl Borrow < str > for ValueKey < ' _ > {
46+ fn borrow ( & self ) -> & str {
47+ self . as_str ( )
48+ }
49+ }
50+
2751#[ derive( Debug ) ]
2852pub struct Attributes < ' bp > {
29- inner : SmallMap < & ' bp str , RemoteCell < TemplateValue < ' bp > > > ,
53+ inner : SmallMap < ValueKey < ' bp > , RemoteCell < TemplateValue < ' bp > > > ,
3054}
3155
3256impl < ' bp > Attributes < ' bp > {
33- pub ( crate ) fn empty ( ) -> Self {
57+ pub fn empty ( ) -> Self {
3458 Self {
3559 inner : SmallMap :: empty ( ) ,
3660 }
3761 }
3862
39- pub fn set ( & mut self , key : & ' bp str , value : RemoteCell < TemplateValue < ' bp > > ) {
63+ /// Set an attribute value.
64+ /// ```
65+ /// # use anathema_core::attributes::Attributes;
66+ /// # use anathema_core::runtime::TemplateValue;
67+ ///
68+ /// let mut attributes = Attributes::empty();
69+ /// attributes.set("name", "Nonsense");
70+ /// attributes.get_as::<&str>("name").unwrap();
71+ /// ```
72+ pub fn set ( & mut self , key : & ' bp str , value : impl Into < TemplateValue < ' bp > > ) {
73+ let value = value. into ( ) ;
74+ let ( cell, _) = RemoteCell :: new ( value) ;
75+ self . inner . set ( ValueKey :: Attribute ( key) , cell) ;
76+ }
77+
78+ /// Set an attribute value.
79+ /// ```
80+ /// # use anathema_core::attributes::Attributes ;
81+ /// # use anathema_core::runtime::TemplateValue;
82+ ///
83+ /// let mut attributes = Attributes::empty();
84+ /// attributes.set_value("Nonsense");
85+ /// attributes.value_as::<&str>().unwrap();
86+ /// ```
87+ pub fn set_value ( & mut self , value : impl Into < TemplateValue < ' bp > > ) {
88+ let key = ValueKey :: Value ;
89+ let value = value. into ( ) ;
90+ let ( cell, _) = RemoteCell :: new ( value) ;
91+ self . inner . set ( key, cell) ;
92+ }
93+
94+ // Set remote cells directly.
95+ // Use this when there is an update handle at the other end
96+ pub ( crate ) fn set_attribute ( & mut self , key : ValueKey < ' bp > , value : RemoteCell < TemplateValue < ' bp > > ) {
4097 self . inner . set ( key, value) ;
4198 }
4299
43- pub ( crate ) fn get ( & self , s : & str ) -> TemplateValue < ' bp > {
44- todo ! ( )
100+ /// Remove a value from attributes
101+ pub fn remove ( & mut self , key : & str ) -> Option < RemoteCell < TemplateValue < ' bp > > > {
102+ self . inner . remove ( key)
103+ }
104+
105+ pub ( crate ) fn get ( & self , key : & str ) -> Option < & RemoteCell < TemplateValue < ' bp > > > {
106+ self . inner . get ( key)
107+ }
108+
109+ /// Get a value as a given type.
110+ /// If the value doesn't exist or can not be cast to the
111+ /// expected type `None` is returned.
112+ /// ```
113+ /// # use anathema_core::attributes::Attributes;
114+ ///
115+ /// let mut attributes = Attributes::empty();
116+ /// attributes.set("num", 123);
117+ ///
118+ /// assert_eq!(attributes.get_as::<u32>("num").unwrap(), 123);
119+ /// assert_eq!(attributes.get_as::<i16>("num").unwrap(), 123);
120+ /// ```
121+ pub fn get_as < ' a , T > ( & ' a self , key : & str ) -> Option < T >
122+ where
123+ T : TryFrom < & ' a TemplateValue < ' bp > > ,
124+ {
125+ self . inner . get ( key) . and_then ( |val| val. deref ( ) . try_into ( ) . ok ( ) )
126+ }
127+
128+ /// Get a value as a specific type
129+ pub fn value_as < ' a , T > ( & ' a self ) -> Option < T >
130+ where
131+ T : TryFrom < & ' a TemplateValue < ' bp > > ,
132+ {
133+ self . inner
134+ . get ( & ValueKey :: Value )
135+ . and_then ( |val| val. deref ( ) . try_into ( ) . ok ( ) )
136+ }
137+
138+ /// Get the `Value` out of attributes.
139+ /// This is always the first item
140+ pub fn value ( & self ) -> Option < & RemoteCell < TemplateValue < ' bp > > > {
141+ self . inner . get ( & ValueKey :: Value )
142+ }
143+
144+ /// Iterate over values of a given type
145+ /// ```
146+ /// # use anathema_core::attributes::Attributes;
147+ /// # use anathema_core::runtime::TemplateValue;
148+ ///
149+ /// let mut attributes = Attributes::empty();
150+ /// let values = TemplateValue::List(
151+ /// [
152+ /// TemplateValue::Int(1),
153+ /// TemplateValue::Bool(true),
154+ /// TemplateValue::Int(2),
155+ /// ]
156+ /// .into(),
157+ /// );
158+ /// attributes.set("mixed_list", values);
159+ ///
160+ /// let iter = attributes.iter_as::<u32>("mixed_list");
161+ /// assert_eq!(vec![1u32, 2], iter.collect::<Vec<_>>());
162+ /// ```
163+ pub fn iter_as < ' a , T > ( & ' a self , key : & str ) -> impl Iterator < Item = T >
164+ where
165+ T : TryFrom < & ' a TemplateValue < ' bp > > ,
166+ {
167+ self . inner
168+ . get ( key)
169+ . and_then ( |val| match & * * val {
170+ TemplateValue :: List ( list) => {
171+ let list = list. iter ( ) . filter_map ( |v| T :: try_from ( v) . ok ( ) ) ;
172+ Some ( list)
173+ }
174+ _ => None ,
175+ } )
176+ . into_iter ( )
177+ . flatten ( )
178+ }
179+
180+ /// Iterate over attributes.
181+ /// This will skip the value
182+ pub fn iter ( & self ) -> impl Iterator < Item = ( & ValueKey < ' _ > , & RemoteCell < TemplateValue < ' bp > > ) > {
183+ self . inner . iter ( ) . filter_map ( |( key, val) | match key {
184+ ValueKey :: Value => None ,
185+ ValueKey :: Attribute ( _) => Some ( ( key, & * val) ) ,
186+ } )
45187 }
46188}
0 commit comments