implement TokensIterator::peek

This commit is contained in:
🪞👃🪞 2025-01-18 03:47:18 +01:00
parent a949117017
commit 92fcb0af8f
7 changed files with 196 additions and 198 deletions

View file

@ -1,5 +1,5 @@
use crate::*;
use std::{sync::Arc, marker::PhantomData};
use std::{sync::Arc, fmt::Debug};
use TokenKind::*;
/// Define an EDN-backed view.
///
@ -46,104 +46,112 @@ use TokenKind::*;
}
}
/// Renders from EDN source and context.
#[derive(Default)] pub enum AtomView<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> {
///
/// Generic over:
///
/// * `O` - Output target.
/// * `S` - State provider.
/// * `A` - Atom storage type.
#[derive(Default, Clone)] pub enum AtomView<'a, O, S, A> {
_Unused(std::marker::PhantomData<&'a O>),
#[default] Inert,
Ok(T, Atom<Arc<str>>),
//render: Box<dyn Fn(&'a T)->Box<dyn Render<E> + Send + Sync + 'a> + Send + Sync + 'a>
Err(String),
_Unused(PhantomData<&'a E>),
Src(S, &'a str),
Ref(S, &'a A),
Own(S, A),
Err(Arc<str>)
}
impl<'a, E: Output, T: ViewContext<'a, E> + std::fmt::Debug> std::fmt::Debug for AtomView<'a, E, T> {
impl<'a, O, S, A> Debug for AtomView<'a, O, S, A>
where S: Debug, A: Debug {
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
Self::Inert | Self::_Unused(_) =>
Self::Inert =>
write!(f, "AtomView::Inert"),
Self::Ok(state, view) =>
write!(f, "AtomView::Ok(state={state:?} view={view:?}"),
Self::Src(state, view) =>
write!(f, "AtomView::Src(state={state:?} view={view:?}"),
Self::Ref(state, view) =>
write!(f, "AtomView::Ref(state={state:?} view={view:?}"),
Self::Own(state, view) =>
write!(f, "AtomView::Arc(state={state:?} view={view:?}"),
Self::Err(error) =>
write!(f, "AtomView::Err({error})"),
_ => unreachable!()
}
}
}
impl<'a, E: Output, T> ViewContext<'a, E> for T where T:
Context<'a, bool> +
Context<'a, usize> +
Context<'a, E::Unit> +
Context<'a, Box<dyn Render<E> + 'a>>
{}
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 RefAtom::read_one(&source) {
Ok((layout, _)) => Self::Ok(state, layout),
Err(error) => Self::Err(format!("{error} in {source}"))
}
}
pub fn from_atoms (state: T, atoms: Vec<impl Atom>) -> Self {
Self::Ok(state, Atom::Exp(atoms).to_arc())
}
}
impl<E: Output, T: for<'a>ViewContext<'a, E> + Send + Sync + std::fmt::Debug> Content<E> for AtomView<'_, E, T> {
fn content (&self) -> impl Render<E> {
impl<'a, O, S, A> Content<O> for AtomView<'a, O, S, A>
where O: Output, S: ViewContext<'a, O>, A: Atom {
fn content (&self) -> impl Render<O> {
match self {
Self::Ok(state, layout) => state.get_content(layout),
Self::Err(_error) => {
panic!("{self:?}");
//TODO:&format!("AtomView error: {error:?}")) // FIXME: String is not Render
},
_ => todo!()
Self::Inert => { panic!("inert rendered") },
Self::Err(e) => { panic!("render error: {e}") },
Self::Src(state, source) => {},
Self::Ref(state, atom) => {},
Self::Own(state, atom) => {},
_ => unreachable!()
}
}
}
impl<'a, E: Output, T> ViewContext<'a, E> for T where T: Sized + Send + Sync
+ Context<bool>
+ Context<usize>
+ Context<E::Unit>
+ Context<Box<dyn Render<E> + 'a>> {}
/// Provides values to the template
pub trait ViewContext<'a, E: Output>:
Context<'a, bool> +
Context<'a, usize> +
Context<'a, E::Unit> +
Context<'a, Box<dyn Render<E> + 'a>>
pub trait ViewContext<'a, E: Output>: Sized + Send + Sync
+ Context<bool>
+ Context<usize>
+ Context<E::Unit>
+ Context<Box<dyn Render<E> + 'a>>
{
fn get_bool (&'a self, atom: RefAtom<'a>) -> Option<bool> {
fn get_bool (&self, atom: &impl Atom) -> Option<bool> {
Some(match atom.kind() {
Sym => match atom.text().as_ref() {
":false" | ":f" => false,
":true" | ":t" => true,
Num => match atom.num() { 0 => false, _ => true },
Sym => match atom.text() {
":false" | ":f" => false, ":true" | ":t" => true,
_ => return Context::get(self, atom)
},
Num => match atom.num() {
0 => false,
_ => true
},
_ => return Context::get(self, atom)
})
}
fn get_usize (&'a self, atom: RefAtom<'a>) -> Option<usize> {
fn get_usize (&self, atom: &impl Atom) -> Option<usize> {
Some(match atom.kind() {
Num => atom.num(),
_ => return Context::get(self, atom)
})
}
fn get_unit (&'a self, atom: RefAtom<'a>) -> Option<E::Unit> {
fn get_unit (&self, atom: &impl Atom) -> Option<E::Unit> {
Some(match atom.kind() {
Num => E::Unit::from(atom.num() as u16),
_ => return Context::get(self, atom)
})
}
fn get_content (&'a self, atom: RefAtom<'a>) -> Option<Box<dyn Render<E> + '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>>);
try_delegate!(self, atom, Bsp::<_, RenderBox<'a, E>, RenderBox<'a, E>>);
try_delegate!(self, atom, Fill::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Fixed::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Min::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Max::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Shrink::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Expand::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Push::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Pull::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Margin::<_, _, RenderBox<'a, E>>);
try_delegate!(self, atom, Padding::<_, _, RenderBox<'a, E>>);
Context::get_or_fail(self, atom)
fn get_content (&self, atom: &impl Atom) -> Option<Box<dyn Render<E> + '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>>);
try_delegate!(self, atom, Bsp::<RenderBox<'a, E>, RenderBox<'a, E>>);
try_delegate!(self, atom, Fill::<RenderBox<'a, E>>);
try_delegate!(self, atom, Fixed::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Min::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Max::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Shrink::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Expand::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Push::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Pull::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Margin::<_, RenderBox<'a, E>>);
try_delegate!(self, atom, Padding::<_, RenderBox<'a, E>>);
Some(Context::get_or_fail(self, atom))
}
}
#[macro_export] macro_rules! try_delegate {
($s:ident, $atom:expr, $T:ty) => {
if $atom.kind() == TokenKind::Exp {
if let [head, tail @ ..] = $atom.as_slice() {
if let Some(value) = <$T>::try_from_atoms($s, head, tail) {
return Some(value.boxed())
}
}
}
}
}
// A function that returns a `RenderBox.