diff --git a/edn/src/token.rs b/edn/src/token.rs index 6b8ea813..31c943c7 100644 --- a/edn/src/token.rs +++ b/edn/src/token.rs @@ -30,7 +30,7 @@ macro_rules! iterate { } } } -#[derive(Clone, PartialEq)] pub struct TokensIterator<'a>(&'a str); +#[derive(Copy, Clone, PartialEq)] pub struct TokensIterator<'a>(&'a str); impl<'a> Iterator for TokensIterator<'a> { type Item = TokenResult<'a>; fn next (&mut self) -> Option> { self.next_mut().map(|(result, _)|result) } @@ -159,14 +159,14 @@ pub trait Atom: Sized { fn text (&self) -> &str; fn num (&self) -> usize; } -#[derive(Clone, PartialEq)] pub enum RefAtom<'a> { +#[derive(Copy, Clone, PartialEq)] pub enum RefAtom<'a> { Num(usize), Sym(&'a str), Key(&'a str), Exp(RefAtomsIterator<'a>), } type RefAtomResult<'a> = Result, ParseError>; -#[derive(Clone, PartialEq)] pub struct RefAtomsIterator<'a>(TokensIterator<'a>); +#[derive(Copy, Clone, PartialEq)] pub struct RefAtomsIterator<'a>(TokensIterator<'a>); impl<'a> Iterator for RefAtomsIterator<'a> { type Item = RefAtomResult<'a>; fn next (&mut self) -> Option> { @@ -398,17 +398,9 @@ impl<'a, T: Context<'a, U>, U> Context<'a, U> for Option { #[macro_export] macro_rules! try_delegate { ($s:ident, $atom:expr, $T:ty) => { if let [head, tail @ ..] = $atom.as_slice() { - if let Some(value) = <$T>::try_from_atom($s, head, tail) { + if let Some(value) = <$T>::try_from_atoms($s, head, tail) { return Some(value.boxed()) } } } } -pub trait TryFromAtom<'a, T>: Sized { - fn try_from_atom (state: &'a T, head: &impl Atom, tail: &'a [impl Atom]) -> - Option; -} -pub trait TryIntoAtom<'a, T>: Sized { - fn try_from_atom (state: &'a T, head: &impl Atom, tail: &'a [impl Atom]) -> - Option; -} diff --git a/input/src/keymap.rs b/input/src/keymap.rs index ee0b6360..e3523b90 100644 --- a/input/src/keymap.rs +++ b/input/src/keymap.rs @@ -44,7 +44,7 @@ pub trait KeyMap { //} //} pub struct ArcKeyMap(Vec); -impl<'a> KeyMap for ArcKeyMap { +impl KeyMap for ArcKeyMap { fn command > (&self, state: &S, input: &impl AtomInput) -> Option { for atom in self.0.iter() { match atom { diff --git a/output/src/measure.rs b/output/src/measure.rs index c6bf83e0..d097f421 100644 --- a/output/src/measure.rs +++ b/output/src/measure.rs @@ -57,7 +57,7 @@ impl Measure { y: Arc::new(0.into()), } } - pub fn of > (&self, item: T) -> Bsp, T> { + pub fn of > (&self, item: T) -> Bsp, T> { Bsp::b(Fill::xy(self), item) } } diff --git a/output/src/op_align.rs b/output/src/op_align.rs index cd78f5b3..b8598cbd 100644 --- a/output/src/op_align.rs +++ b/output/src/op_align.rs @@ -1,23 +1,40 @@ use crate::*; -use RefAtom::*; #[derive(Debug, Copy, Clone, Default)] pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W } -pub struct Align(PhantomData, Alignment, A); -impl Align { - pub fn c (a: A) -> Self { Self(Default::default(), Alignment::Center, a) } - pub fn x (a: A) -> Self { Self(Default::default(), Alignment::X, a) } - pub fn y (a: A) -> Self { Self(Default::default(), Alignment::Y, a) } - pub fn n (a: A) -> Self { Self(Default::default(), Alignment::N, a) } - pub fn s (a: A) -> Self { Self(Default::default(), Alignment::S, a) } - pub fn e (a: A) -> Self { Self(Default::default(), Alignment::E, a) } - pub fn w (a: A) -> Self { Self(Default::default(), Alignment::W, a) } - pub fn nw (a: A) -> Self { Self(Default::default(), Alignment::NW, a) } - pub fn sw (a: A) -> Self { Self(Default::default(), Alignment::SW, a) } - pub fn ne (a: A) -> Self { Self(Default::default(), Alignment::NE, a) } - pub fn se (a: A) -> Self { Self(Default::default(), Alignment::SE, a) } +pub struct Align(Alignment, A); +try_from_atoms!(<'a, E>: Align>: |state, atoms| { + let head = atoms.next()?; + if head.kind() != TokenKind::Key { return None } + match head.text() { + "align/c" => return Some(Self::c(state.get_content(atoms.next()?).expect("no content"))), + "align/x" => return Some(Self::x(state.get_content(atoms.next()?).expect("no content"))), + "align/y" => return Some(Self::y(state.get_content(atoms.next()?).expect("no content"))), + "align/n" => return Some(Self::n(state.get_content(atoms.next()?).expect("no content"))), + "align/s" => return Some(Self::s(state.get_content(atoms.next()?).expect("no content"))), + "align/e" => return Some(Self::e(state.get_content(atoms.next()?).expect("no content"))), + "align/w" => return Some(Self::w(state.get_content(atoms.next()?).expect("no content"))), + "align/nw" => return Some(Self::nw(state.get_content(atoms.next()?).expect("no content"))), + "align/ne" => return Some(Self::ne(state.get_content(atoms.next()?).expect("no content"))), + "align/sw" => return Some(Self::sw(state.get_content(atoms.next()?).expect("no content"))), + "align/se" => return Some(Self::se(state.get_content(atoms.next()?).expect("no content"))), + _ => {} + } +}); +impl Align { + pub fn c (a: A) -> Self { Self(Alignment::Center, a) } + pub fn x (a: A) -> Self { Self(Alignment::X, a) } + pub fn y (a: A) -> Self { Self(Alignment::Y, a) } + pub fn n (a: A) -> Self { Self(Alignment::N, a) } + pub fn s (a: A) -> Self { Self(Alignment::S, a) } + pub fn e (a: A) -> Self { Self(Alignment::E, a) } + pub fn w (a: A) -> Self { Self(Alignment::W, a) } + pub fn nw (a: A) -> Self { Self(Alignment::NW, a) } + pub fn sw (a: A) -> Self { Self(Alignment::SW, a) } + pub fn ne (a: A) -> Self { Self(Alignment::NE, a) } + pub fn se (a: A) -> Self { Self(Alignment::SE, a) } } -impl> Content for Align { +impl> Content for Align { fn content (&self) -> impl Render { - &self.2 + &self.1 } fn layout (&self, on: E::Area) -> E::Area { use Alignment::*; @@ -26,7 +43,7 @@ impl> Content for Align { let cy = on.y()+(on.h().minus(it.h())/2.into()); let fx = (on.x()+on.w()).minus(it.w()); let fy = (on.y()+on.h()).minus(it.h()); - let [x, y] = match self.1 { + let [x, y] = match self.0 { Center => [cx, cy], X => [cx, it.y()], Y => [it.x(), cy], @@ -45,25 +62,3 @@ impl> Content for Align { to.place(Content::layout(self, to.area()), &self.content()) } } -impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for Align> { - fn try_from_atom ( - state: &'a T, - head: &impl Atom, - tail: &'a [impl Atom] - ) -> Option { - Some(match (head.to_ref(), tail) { - (Key("align/c"), [a]) => Self::c(state.get_content(a).expect("no content")), - (Key("align/x"), [a]) => Self::x(state.get_content(a).expect("no content")), - (Key("align/y"), [a]) => Self::y(state.get_content(a).expect("no content")), - (Key("align/n"), [a]) => Self::n(state.get_content(a).expect("no content")), - (Key("align/s"), [a]) => Self::s(state.get_content(a).expect("no content")), - (Key("align/e"), [a]) => Self::e(state.get_content(a).expect("no content")), - (Key("align/w"), [a]) => Self::w(state.get_content(a).expect("no content")), - (Key("align/nw"), [a]) => Self::nw(state.get_content(a).expect("no content")), - (Key("align/ne"), [a]) => Self::ne(state.get_content(a).expect("no content")), - (Key("align/sw"), [a]) => Self::sw(state.get_content(a).expect("no content")), - (Key("align/se"), [a]) => Self::se(state.get_content(a).expect("no content")), - _ => return None - }) - } -} diff --git a/output/src/op_bsp.rs b/output/src/op_bsp.rs index 57be6c8f..54f5f650 100644 --- a/output/src/op_bsp.rs +++ b/output/src/op_bsp.rs @@ -17,8 +17,8 @@ impl Direction { } } /// A split or layer. -pub struct Bsp(PhantomData, Direction, X, Y); -impl, B: Content> Content for Bsp { +pub struct Bsp(Direction, X, Y); +impl, B: Content> Content for Bsp { fn layout (&self, outer: E::Area) -> E::Area { let [_, _, c] = self.areas(outer); c @@ -26,19 +26,50 @@ impl, B: Content> Content for Bsp { fn render (&self, to: &mut E) { let [area_a, area_b, _] = self.areas(to.area()); let (a, b) = self.contents(); - match self.1 { + match self.0 { Below => { to.place(area_a, a); to.place(area_b, b); }, _ => { to.place(area_b, b); to.place(area_a, a); } } } } -impl Bsp { - pub fn n (a: A, b: B) -> Self { Self(Default::default(), North, a, b) } - pub fn s (a: A, b: B) -> Self { Self(Default::default(), South, a, b) } - pub fn e (a: A, b: B) -> Self { Self(Default::default(), East, a, b) } - pub fn w (a: A, b: B) -> Self { Self(Default::default(), West, a, b) } - pub fn a (a: A, b: B) -> Self { Self(Default::default(), Above, a, b) } - pub fn b (a: A, b: B) -> Self { Self(Default::default(), Below, a, b) } +try_from_atoms!(<'a, E>: Bsp, RenderBox<'a, E>>: |state, atoms| { + let head = atoms.next()?; + if head.kind() != TokenKind::Key { return None } + match head.text() { + "bsp/n" => return Some(Self::n( + state.get_content(atoms.next()?).expect("no south"), + state.get_content(atoms.next()?).expect("no north") + )), + "bsp/s" => return Some(Self::s( + state.get_content(atoms.next()?).expect("no north"), + state.get_content(atoms.next()?).expect("no south") + )), + "bsp/e" => return Some(Self::e( + state.get_content(atoms.next()?).expect("no west"), + state.get_content(atoms.next()?).expect("no east") + )), + "bsp/w" => return Some(Self::w( + state.get_content(atoms.next()?).expect("no east"), + state.get_content(atoms.next()?).expect("no west") + )), + "bsp/a" => return Some(Self::a( + state.get_content(atoms.next()?).expect("no above"), + state.get_content(atoms.next()?).expect("no below") + )), + "bsp/b" => return Some(Self::b( + state.get_content(atoms.next()?).expect("no above"), + state.get_content(atoms.next()?).expect("no below") + )), + _ => {} + } +}); +impl Bsp { + pub fn n (a: A, b: B) -> Self { Self(North, a, b) } + pub fn s (a: A, b: B) -> Self { Self(South, a, b) } + pub fn e (a: A, b: B) -> Self { Self(East, a, b) } + pub fn w (a: A, b: B) -> Self { Self(West, a, b) } + pub fn a (a: A, b: B) -> Self { Self(Above, a, b) } + pub fn b (a: A, b: B) -> Self { Self(Below, a, b) } } pub trait BspAreas, B: Content> { fn direction (&self) -> Direction; @@ -89,34 +120,9 @@ pub trait BspAreas, B: Content> { } } } -impl, B: Content> BspAreas for Bsp { - fn direction (&self) -> Direction { self.1 } - fn contents (&self) -> (&A, &B) { (&self.2, &self.3) } -} -impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for Bsp, RenderBox<'a, E>> { - fn try_from_atom (s: &'a T, head: &impl Atom, tail: &'a [impl Atom]) -> Option { - Some(match (head.to_ref(), tail) { - (Key("bsp/n"), [a, b]) => Self::n( - s.get_content(a).expect("no south"), - s.get_content(b).expect("no north")), - (Key("bsp/s"), [a, b]) => Self::s( - s.get_content(a).expect("no north"), - s.get_content(b).expect("no south")), - (Key("bsp/e"), [a, b]) => Self::e( - s.get_content(a).expect("no west"), - s.get_content(b).expect("no east")), - (Key("bsp/w"), [a, b]) => Self::w( - s.get_content(a).expect("no east"), - s.get_content(b).expect("no west")), - (Key("bsp/a"), [a, b]) => Self::a( - s.get_content(a).expect("no above"), - s.get_content(b).expect("no below")), - (Key("bsp/b"), [a, b]) => Self::b( - s.get_content(a).expect("no above"), - s.get_content(b).expect("no below")), - _ => return None - }) - } +impl, B: Content> BspAreas for Bsp { + fn direction (&self) -> Direction { self.0 } + fn contents (&self) -> (&A, &B) { (&self.1, &self.2) } } /// Renders multiple things on top of each other, diff --git a/output/src/op_cond.rs b/output/src/op_cond.rs index a765e060..77fbe549 100644 --- a/output/src/op_cond.rs +++ b/output/src/op_cond.rs @@ -1,30 +1,42 @@ use crate::*; -use RefAtom::*; /// Show an item only when a condition is true. -pub struct When(pub PhantomData, pub bool, pub A); -impl When { - pub fn new (c: bool, a: A) -> Self { - Self(Default::default(), c, a) - } -} -impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for When> { - fn try_from_atom ( - state: &'a T, head: &impl Atom, tail: &'a [impl Atom] - ) -> Option { - if let (Key("when"), [condition, content]) = (head.to_ref(), tail) { - Some(Self( - Default::default(), - state.get_bool(condition).expect("when: no condition"), - state.get_content(content).expect("when: no content") - )) - } else { - None +pub struct When(pub bool, pub A); +impl When { pub fn new (c: bool, a: A) -> Self { Self(c, a) } } +/// Show one item if a condition is true and another if the condition is false +pub struct Either(pub bool, pub A, pub B); +impl Either { pub fn new (c: bool, a: A, b: B) -> Self { Self(c, a, b) } } +try_from_atoms!(<'a, E>: When>: |state, atoms| { + let head = atoms.next()?; + if (head.kind(), head.text()) == (TokenKind::Key, "when") { + let condition = atoms.next(); + if let Some(condition) = condition { + let condition = state.get_bool(condition).expect("no condition"); + if let Some(content) = atoms.next() { + let content = state.get_content(content).expect("no atom"); + return Some(Self(condition, content)) + } } } -} -impl> Content for When { +}); +try_from_atoms!(<'a, E>: Either, RenderBox<'a, E>>: |state, atoms| { + let head = atoms.next()?; + if (head.kind(), head.text()) == (TokenKind::Key, "either") { + let condition = atoms.next(); + if let Some(condition) = condition { + let condition = state.get_bool(condition).expect("no condition"); + if let Some(content1) = atoms.next() { + let content1 = state.get_content(content1).expect("no content1"); + if let Some(content2) = atoms.next() { + let content2 = state.get_content(content2).expect("no content2"); + return Some(Self(condition, content1, content2)) + } + } + } + } +}); +impl> Content for When { fn layout (&self, to: E::Area) -> E::Area { - let Self(_, cond, item) = self; + let Self(cond, item) = self; let mut area = E::Area::zero(); if *cond { let item_area = item.layout(to); @@ -36,37 +48,17 @@ impl> Content for When { area.into() } fn render (&self, to: &mut E) { - let Self(_, cond, item) = self; + let Self(cond, item) = self; if *cond { item.render(to) } } } -/// Show one item if a condition is true and another if the condition is false -pub struct Either(pub PhantomData, pub bool, pub A, pub B); -impl Either { - pub fn new (c: bool, a: A, b: B) -> Self { - Self(Default::default(), c, a, b) - } -} -impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for Either, RenderBox<'a, E>> { - fn try_from_atom (state: &'a T, head: &impl Atom, tail: &'a [impl Atom]) -> Option { - if let (Key("either"), [condition, content, alternative]) = (head.to_ref(), tail) { - Some(Self::new( - state.get_bool(condition).expect("either: no condition"), - state.get_content(content).expect("either: no content"), - state.get_content(alternative).expect("either: no alternative") - )) - } else { - None - } - } -} -impl, B: Render> Content for Either { +impl, B: Render> Content for Either { fn layout (&self, to: E::Area) -> E::Area { - let Self(_, cond, a, b) = self; + let Self(cond, a, b) = self; if *cond { a.layout(to) } else { b.layout(to) } } fn render (&self, to: &mut E) { - let Self(_, cond, a, b) = self; + let Self(cond, a, b) = self; if *cond { a.render(to) } else { b.render(to) } } } diff --git a/output/src/op_transform.rs b/output/src/op_transform.rs index 019cf1bf..4fea2486 100644 --- a/output/src/op_transform.rs +++ b/output/src/op_transform.rs @@ -7,19 +7,18 @@ use RefAtom::*; /// using `PhantomData` to permit the double generic. macro_rules! transform_xy { ($x:literal $y:literal $xy:literal |$self:ident : $Enum:ident, $to:ident|$area:expr) => { - pub enum $Enum { _Unused(PhantomData), X(T), Y(T), XY(T) } - impl $Enum { + pub enum $Enum { X(T), Y(T), XY(T) } + impl $Enum { pub fn x (item: T) -> Self { Self::X(item) } pub fn y (item: T) -> Self { Self::Y(item) } pub fn xy (item: T) -> Self { Self::XY(item) } } - impl> Content for $Enum { + impl> Content for $Enum { fn content (&self) -> impl Render { match self { Self::X(item) => item, Self::Y(item) => item, Self::XY(item) => item, - _ => unreachable!(), } } fn layout (&$self, $to: ::Area) -> ::Area { @@ -27,14 +26,20 @@ macro_rules! transform_xy { $area } } - impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for $Enum> { - fn try_from_atom ( - state: &'a T, head: &impl Atom, tail: &'a [impl Atom] - ) -> Option { - Some(match (head.to_ref(), tail) { - (Key($x), [a]) => Self::x(state.get_content(a).expect("no content")), - (Key($y), [a]) => Self::y(state.get_content(a).expect("no content")), - (Key($xy), [a]) => Self::xy(state.get_content(a).expect("no content")), + impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for $Enum> { + fn try_from_atoms (state: &'a T, mut atoms: impl Iterator> + 'a) -> Option { + let head = atoms.next()?; + if head.kind() != TokenKind::Key { return None } + Some(match head.text() { + $x => Self::x( + state.get_content(atoms.next().expect("no content")).expect("no content") + ), + $y => Self::y( + state.get_content(atoms.next().expect("no content")).expect("no content") + ), + $xy => Self::xy( + state.get_content(atoms.next().expect("no content")).expect("no content") + ), _ => return None }) } @@ -45,60 +50,53 @@ macro_rules! transform_xy { /// along either the X axis, the Y axis, or both. macro_rules! transform_xy_unit { ($x:literal $y:literal $xy:literal |$self:ident : $Enum:ident, $to:ident|$layout:expr) => { - pub enum $Enum { _Unused(E), X(U, T), Y(U, T), XY(U, U, T), } - impl $Enum { + pub enum $Enum { X(U, T), Y(U, T), XY(U, U, T), } + impl $Enum { pub fn x (x: U, item: T) -> Self { Self::X(x, item) } pub fn y (y: U, item: T) -> Self { Self::Y(y, item) } pub fn xy (x: U, y: U, item: T) -> Self { Self::XY(x, y, item) } } - impl $Enum { + impl $Enum { pub fn dx (&self) -> U { match self { - Self::X(x, _) => *x, - Self::Y(_, _) => 0.into(), - Self::XY(x, _, _) => *x, - _ => unreachable!(), + Self::X(x, _) => *x, Self::Y(_, _) => 0.into(), Self::XY(x, _, _) => *x, } } pub fn dy (&self) -> U { match self { - Self::X(_, _) => 0.into(), - Self::Y(y, _) => *y, - Self::XY(_, y, _) => *y, - _ => unreachable!(), + Self::X(_, _) => 0.into(), Self::Y(y, _) => *y, Self::XY(_, y, _) => *y, } } } - impl> Content for $Enum { + impl> Content for $Enum { fn content (&self) -> impl Render { Some(match self { - Self::X(_, content) => content, - Self::Y(_, content) => content, + Self::X(_, content) => content, + Self::Y(_, content) => content, Self::XY(_, _, content) => content, - _ => unreachable!(), }) } fn layout (&$self, $to: E::Area) -> E::Area { $layout.into() } } - impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for $Enum> { - fn try_from_atom ( - state: &'a T, head: &impl Atom, tail: &'a [impl Atom] - ) -> Option { - Some(match (head.to_ref(), tail) { - (Key($x), [x, a]) => Self::x( - state.get_unit(x).expect("no x"), - state.get_content(a).expect("no content"), + impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromAtom<'a, T> for $Enum> { + fn try_from_atoms (state: &'a T, mut atoms: impl Iterator> + 'a) -> Option { + let head = atoms.next()?; + if head.kind() != TokenKind::Key { return None } + Some(match head.text() { + $x => Self::x( + state.get_unit(atoms.next().expect("no x")).expect("no x"), + state.get_content(atoms.next().expect("no content")).expect("no content") ), - (Key($y), [y, a]) => Self::y( - state.get_unit(y).expect("no y"), - state.get_content(a).expect("no content"), + $y => Self::y( + state.get_unit(atoms.next().expect("no y")).expect("no y"), + state.get_content(atoms.next().expect("no content")).expect("no content") ), - (Key($xy), [x, y, a]) => Self::xy( - state.get_unit(x).expect("no x"), - state.get_unit(y).expect("no y"), - state.get_content(a).expect("no content"), + $xy => Self::xy( + state.get_unit(atoms.next().expect("no x")).expect("no x"), + state.get_unit(atoms.next().expect("no y")).expect("no y"), + state.get_content(atoms.next().expect("no content")).expect("no content"), ), _ => return None }) diff --git a/output/src/view.rs b/output/src/view.rs index 4f6a9783..8ab4271f 100644 --- a/output/src/view.rs +++ b/output/src/view.rs @@ -74,7 +74,7 @@ impl<'a, E: Output, T> ViewContext<'a, E> for T where T: {} impl<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> AtomView<'a, E, T> { pub fn from_source (state: T, source: &'a str) -> Self { - match Atom::read_one(&source) { + match RefAtom::read_one(&source) { Ok((layout, _)) => Self::Ok(state, layout), Err(error) => Self::Err(format!("{error} in {source}")) } @@ -102,7 +102,7 @@ pub trait ViewContext<'a, E: Output>: Context<'a, E::Unit> + Context<'a, Box + 'a>> { - fn get_bool (&'a self, atom: &'a impl Atom) -> Option { + fn get_bool (&'a self, atom: RefAtom<'a>) -> Option { Some(match atom.kind() { Sym => match atom.text().as_ref() { ":false" | ":f" => false, @@ -116,19 +116,19 @@ pub trait ViewContext<'a, E: Output>: _ => return Context::get(self, atom) }) } - fn get_usize (&'a self, atom: &'a impl Atom) -> Option { + fn get_usize (&'a self, atom: RefAtom<'a>) -> Option { Some(match atom.kind() { Num => atom.num(), _ => return Context::get(self, atom) }) } - fn get_unit (&'a self, atom: &'a impl Atom) -> Option { + fn get_unit (&'a self, atom: RefAtom<'a>) -> Option { Some(match atom.kind() { Num => E::Unit::from(atom.num() as u16), _ => return Context::get(self, atom) }) } - fn get_content (&'a self, atom: &'a impl Atom) -> Option + 'a>> where E: 'a { + fn get_content (&'a self, atom: RefAtom<'a>) -> Option + 'a>> where E: 'a { try_delegate!(self, atom, When::<_, RenderBox<'a, E>>); try_delegate!(self, atom, Either::<_, RenderBox<'a, E>, RenderBox<'a, E>>); try_delegate!(self, atom, Align::<_, RenderBox<'a, E>>); @@ -152,3 +152,20 @@ pub type AtomCallback<'a, O, State> = // A box containing a function that returns a `RenderBox. pub type AtomRenderCallback<'a, O, State> = Box>; + +pub trait TryFromAtom<'a, T>: Sized { + fn try_from_atoms (state: &'a T, atoms: impl Iterator> + 'a) -> Option; +} +pub trait TryIntoAtom<'a, T>: Sized { + fn try_into_atoms (&self) -> Option>; +} +#[macro_export] macro_rules! try_from_atoms { + (<$l:lifetime, $E:ident>: $Struct:ty: |$state:ident,$atoms:ident|$body:expr) => { + impl<$l, $E: Output + $l, T: ViewContext<$l, $E>> TryFromAtom<$l, T> for $Struct { + fn try_from_atoms ($state: &$l T, mut $atoms: impl Iterator> + $l) -> Option { + $body; + None + } + } + } +}