Skip to content

Commit 1647de9

Browse files
committed
wip
1 parent f35db85 commit 1647de9

4 files changed

Lines changed: 270 additions & 13 deletions

File tree

anathema-core/src/attributes.rs

Lines changed: 147 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
//! Element attributes
2+
use std::borrow::Borrow;
23
// #![deny(missing_docs)]
4+
use std::ops::Deref;
5+
36
use anathema_store::remotecell::RemoteCell;
47
use anathema_store::slab::SecondaryMap;
58
use 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)]
2852
pub struct Attributes<'bp> {
29-
inner: SmallMap<&'bp str, RemoteCell<TemplateValue<'bp>>>,
53+
inner: SmallMap<ValueKey<'bp>, RemoteCell<TemplateValue<'bp>>>,
3054
}
3155

3256
impl<'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
}

anathema-core/src/runtime/eval/mod.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use anathema_store::remotecell::RemoteHandle;
55

66
use self::scope::Scope;
77
use super::error::Result;
8-
use crate::attributes::{AllAttributes, Attributes};
8+
use crate::attributes::{AllAttributes, Attributes, ValueKey};
99
use crate::runtime::components::Components;
1010
use crate::runtime::elements::{Element, ElementId, Elements};
1111
use crate::runtime::eval::expression::{eval_by_id, RuntimeExpression, RuntimeExpressions};
@@ -136,13 +136,12 @@ impl Evaluator for SingleEval {
136136

137137
for (key, expr) in input.attributes.iter() {
138138
let value = eval_by_id(*expr, element_id, parent, ctx);
139-
attributes.set(key, value);
139+
attributes.set_attribute(ValueKey::Attribute(key), value);
140140
}
141141

142142
if let Some(expr) = &input.value {
143143
let val = eval_by_id(*expr, element_id, parent, ctx);
144-
eprintln!("val: {val:?}");
145-
attributes.set(panic!("bring back the value key"), val);
144+
attributes.set_attribute(ValueKey::Value, val);
146145
}
147146

148147
let el = match factory.make(&input.ident, &attributes) {
@@ -299,7 +298,7 @@ mod test {
299298
// * Look at dirty widgets
300299
// * Update the values using the remote handle
301300

302-
panic!("this is some bs: {:#?}", ctx.attributes)
301+
// panic!("this is some bs: {:#?}", ctx.attributes)
303302
});
304303
}
305304

@@ -312,6 +311,6 @@ mod test {
312311

313312
let mut test = RunBuilder::from_src(tpl);
314313
let mut inst = test.finish();
315-
inst.eval(|ctx| panic!("{:#?}", ctx.elements));
314+
// inst.eval(|ctx| panic!("{:#?}", ctx.elements));
316315
}
317316
}

anathema-core/src/runtime/eval/values.rs

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,70 @@ macro_rules! impl_from {
6969
}
7070
}
7171

72-
impl_from!(i64, Int);
73-
impl_from!(f64, Float);
7472
impl_from!(bool, Bool);
7573
impl_from!(char, Char);
7674
impl_from!(Hex, Hex);
7775
impl_from!(Color, Color);
7876

77+
macro_rules! from_int {
78+
($int:ty) => {
79+
impl From<$int> for TemplateValue<'_> {
80+
fn from(value: $int) -> Self {
81+
TemplateValue::Int(value as i64)
82+
}
83+
}
84+
};
85+
}
86+
87+
from_int!(i64);
88+
from_int!(i32);
89+
from_int!(i16);
90+
from_int!(i8);
91+
from_int!(u64);
92+
from_int!(u32);
93+
from_int!(u16);
94+
from_int!(u8);
95+
96+
impl From<f64> for TemplateValue<'_> {
97+
fn from(value: f64) -> Self {
98+
TemplateValue::Float(value)
99+
}
100+
}
101+
102+
impl From<f32> for TemplateValue<'_> {
103+
fn from(value: f32) -> Self {
104+
TemplateValue::Float(value as f64)
105+
}
106+
}
107+
79108
impl From<std::ops::Range<usize>> for TemplateValue<'static> {
80109
fn from(value: std::ops::Range<usize>) -> Self {
81110
Self::Range(value.start, value.end)
82111
}
83112
}
84113

114+
impl<'bp, T> From<Vec<T>> for TemplateValue<'bp>
115+
where
116+
T: Into<TemplateValue<'bp>>,
117+
{
118+
fn from(value: Vec<T>) -> Self {
119+
let list = value.into_iter().map(T::into).collect();
120+
TemplateValue::List(list)
121+
}
122+
}
123+
124+
impl<'a> From<&'a str> for TemplateValue<'a> {
125+
fn from(value: &'a str) -> Self {
126+
TemplateValue::Str(Cow::Borrowed(value))
127+
}
128+
}
129+
130+
impl From<String> for TemplateValue<'_> {
131+
fn from(value: String) -> Self {
132+
TemplateValue::Str(value.into())
133+
}
134+
}
135+
85136
// -----------------------------------------------------------------------------
86137
// - Primitives -
87138
// -----------------------------------------------------------------------------
@@ -132,3 +183,66 @@ pub fn map<'a, T: Into<TemplateValue<'a>>>(map: HashMap<&'static str, T>) -> Tem
132183
}
133184
TemplateValue::Map(hm)
134185
}
186+
187+
// -----------------------------------------------------------------------------
188+
// - Try From -
189+
// -----------------------------------------------------------------------------
190+
macro_rules! try_from_valuekind {
191+
($t:ty, $kind:ident) => {
192+
impl TryFrom<&TemplateValue<'_>> for $t {
193+
type Error = ();
194+
195+
fn try_from(value: &TemplateValue<'_>) -> Result<Self, Self::Error> {
196+
match value {
197+
TemplateValue::$kind(val) => Ok(*val),
198+
_ => Err(()),
199+
}
200+
}
201+
}
202+
};
203+
}
204+
205+
macro_rules! try_from_valuekind_int {
206+
($t:ty, $kind:ident) => {
207+
impl TryFrom<&TemplateValue<'_>> for $t {
208+
type Error = ();
209+
210+
fn try_from(value: &TemplateValue<'_>) -> Result<Self, Self::Error> {
211+
match value {
212+
TemplateValue::$kind(val) => Ok(*val as $t),
213+
_ => Err(()),
214+
}
215+
}
216+
}
217+
};
218+
}
219+
220+
try_from_valuekind!(i64, Int);
221+
try_from_valuekind!(f64, Float);
222+
try_from_valuekind!(bool, Bool);
223+
try_from_valuekind!(char, Char);
224+
try_from_valuekind!(Hex, Hex);
225+
try_from_valuekind!(Color, Color);
226+
227+
try_from_valuekind_int!(usize, Int);
228+
try_from_valuekind_int!(isize, Int);
229+
try_from_valuekind_int!(i32, Int);
230+
try_from_valuekind_int!(f32, Float);
231+
try_from_valuekind_int!(i16, Int);
232+
try_from_valuekind_int!(i8, Int);
233+
try_from_valuekind_int!(u32, Int);
234+
try_from_valuekind_int!(u64, Int);
235+
try_from_valuekind_int!(u16, Int);
236+
try_from_valuekind_int!(u8, Int);
237+
238+
impl<'a, 'bp> TryFrom<&'a TemplateValue<'bp>> for &'a str {
239+
type Error = ();
240+
241+
fn try_from(value: &'a TemplateValue<'bp>) -> Result<Self, Self::Error> {
242+
match value {
243+
TemplateValue::Str(Cow::Borrowed(val)) => Ok(val),
244+
TemplateValue::Str(Cow::Owned(val)) => Ok(val.as_str()),
245+
_ => Err(()),
246+
}
247+
}
248+
}

anathema-core/src/runtime/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
pub use widgets::iter::Children;
22
pub use widgets::{RegisteredWidgets, Widget};
33

4+
pub use crate::runtime::eval::values::TemplateValue;
5+
46
pub mod components;
57
pub(crate) mod elements;
68
mod error;

0 commit comments

Comments
 (0)