remove View; allow rendering Result
Some checks failed
/ build (push) Has been cancelled

This commit is contained in:
🪞👃🪞 2025-05-19 02:23:26 +03:00
parent 90f5699fff
commit f08593f0f8
5 changed files with 64 additions and 89 deletions

View file

@ -16,19 +16,35 @@ use crate::*;
/// Maps a sequencer of EDN tokens to parameters of supported types /// Maps a sequencer of EDN tokens to parameters of supported types
/// for a given context. /// for a given context.
pub trait Dsl<U>: Sized { pub trait Dsl<Value>: Sized {
fn take <'state, 'source> ( fn take <'state, 'source> (&'state self, _: &mut TokenIter<'source>) -> Perhaps<Value> {
&'state self,
_: &mut TokenIter<'source>
) -> Perhaps<U> {
unimplemented!() unimplemented!()
} }
fn take_or_fail <'state, 'source> ( fn take_or_fail <'state, 'source> (
&'state self, &'state self,
token: &mut TokenIter<'source>, token: &mut TokenIter<'source>,
error: impl Into<Box<dyn std::error::Error>> error: impl Into<Box<dyn std::error::Error>>
) -> Usually<U> { ) -> Usually<Value> {
if let Some(value) = Dsl::<U>::take(self, token)? { if let Some(value) = Dsl::<Value>::take(self, token)? {
Ok(value)
} else {
Result::Err(error.into())
}
}
}
pub trait FromDsl<'state, State>: Sized {
fn take_from <'source: 'state> (state: &'state State, _token: &mut TokenIter<'source>)
-> Perhaps<Self>
{
unimplemented!()
}
fn take_from_or_fail <'source: 'state> (
state: &'state State,
token: &mut TokenIter<'source>,
error: impl Into<Box<dyn std::error::Error>>
) -> Usually<Self> {
if let Some(value) = FromDsl::<State>::take_from(state, token)? {
Ok(value) Ok(value)
} else { } else {
Result::Err(error.into()) Result::Err(error.into())
@ -53,23 +69,3 @@ impl<'state, X, Y> Dsl<X> for Y where Y: FromDsl<'state, X> {
//impl<T, U: FromDsl<T>> Dsl<U> for T { //impl<T, U: FromDsl<T>> Dsl<U> for T {
//} //}
pub trait FromDsl<'state, T>: Sized {
fn take_from <'source: 'state> (
state: &'state T,
_token: &mut TokenIter<'source>
) -> Perhaps<Self> {
unimplemented!()
}
fn take_from_or_fail <'source: 'state> (
state: &'state T,
token: &mut TokenIter<'source>,
error: impl Into<Box<dyn std::error::Error>>
) -> Usually<Self> {
if let Some(value) = FromDsl::<T>::take_from(state, token)? {
Ok(value)
} else {
Result::Err(error.into())
}
}
}

View file

@ -85,7 +85,7 @@ impl<E: Output> Measure<E> {
pub fn format (&self) -> Arc<str> { pub fn format (&self) -> Arc<str> {
format!("{}x{}", self.w(), self.h()).into() format!("{}x{}", self.w(), self.h()).into()
} }
pub fn of <T: Content<E>> (&self, item: T) -> Bsp<Fill<&Self>, T> { pub fn of <T: Render<E>> (&self, item: T) -> Bsp<Fill<&Self>, T> {
Bsp::b(Fill::xy(self), item) Bsp::b(Fill::xy(self), item)
} }
} }

View file

@ -1,48 +1,13 @@
use crate::*; use crate::*;
#[macro_export] macro_rules! view {
($Output:ty: |$self:ident: $State:ty| $expr:expr; {
$($sym:literal => $body:expr),* $(,)?
}) => {
impl Content<$Output> for $State {
fn content (&$self) -> impl Render<$Output> { $expr }
}
impl<'a> ViewContext<'a, $Output> for $State {
fn get_content_sym (&'a $self, iter: &Value<'a>) -> Perhaps<RenderBox<'a, $Output>> {
Ok(if let Value::Sym(s) = value {
match *s {
$($sym => Some($body.boxed()),)*
_ => None
}
} else {
return Err(format!("expected content, got: {iter:?}").into())
})
}
}
}
}
// An ephemeral wrapper around view state and view description,
// that is meant to be constructed and returned from [Content::content].
#[cfg(feature = "dsl")] #[cfg(feature = "dsl")]
pub struct View<'a, T>( #[macro_export] macro_rules! try_delegate {
pub &'a T, ($s:ident, $dsl:expr, $T:ty) => {
pub TokenIter<'a> let value: Option<$T> = FromDsl::take_from($s, $dsl)?;
); if let Some(value) = value {
return Ok(Some(value.boxed()))
#[cfg(feature = "dsl")]
impl<'a, O: Output + 'a, T: ViewContext<'a, O>> Content<O> for View<'a, T> {
fn content (&self) -> impl Render<O> {
let mut iter = self.1.clone();
while let Some(Token { value, .. }) = iter.peek() {
if let Ok(Some(content)) = self.0.get_content(&mut iter) {
return Some(content)
// TODO handle errors here, how?
// error receiver trait in viewcontext?
} }
} }
return None
}
} }
// Provides components to the view. // Provides components to the view.
@ -96,13 +61,3 @@ pub trait ViewContext<'state, E: Output + 'state>: Send + Sync
Ok(None) Ok(None)
} }
} }
#[cfg(feature = "dsl")]
#[macro_export] macro_rules! try_delegate {
($s:ident, $dsl:expr, $T:ty) => {
let value: Option<$T> = FromDsl::take_from($s, $dsl)?;
if let Some(value) = value {
return Ok(Some(value.boxed()))
}
}
}

View file

@ -44,7 +44,7 @@ impl Parse for ViewImpl {
impl ToTokens for ViewDef { impl ToTokens for ViewDef {
fn to_tokens (&self, out: &mut TokenStream2) { fn to_tokens (&self, out: &mut TokenStream2) {
let Self(ViewMeta { output }, ViewImpl { block, exposed }) = self; let Self(ViewMeta { output }, ViewImpl { block, exposed }) = self;
let ident = &block.self_ty; let view = &block.self_ty;
let mut available = vec![]; let mut available = vec![];
let exposed: Vec<_> = exposed.iter().map(|(k,v)|{ let exposed: Vec<_> = exposed.iter().map(|(k,v)|{
available.push(k.clone()); available.push(k.clone());
@ -52,24 +52,24 @@ impl ToTokens for ViewDef {
}).collect(); }).collect();
let available: String = available.join(", "); let available: String = available.join(", ");
let error_msg = LitStr::new( let error_msg = LitStr::new(
&format!("expected Sym(content), got: {{iter:?}}, available: {available}"), &format!("expected Sym(content), got: {{token:?}}, available: {available}"),
Span::call_site() Span::call_site()
); );
for token in quote! { for token in quote! {
#block #block
/// Generated by [tengri_proc]. /// Generated by [tengri_proc].
impl ::tengri::output::Content<#output> for #ident { impl ::tengri::output::Content<#output> for #view {
fn content (&self) -> impl Render<#output> { fn content (&self) -> impl Render<#output> {
// TODO move to self.view() self.view()
self.size.of(::tengri::output::View(self, self.config.view))
} }
} }
/// Generated by [tengri_proc]. /// Generated by [tengri_proc].
impl<'state> ::tengri::output::ViewContext<'state, #output> for #ident { impl<'state> ::tengri::dsl::FromDsl<'state, #view> for ::tengri::output::RenderBox<'state, #output> {
fn get_content_sym <'source: 'state> (&'state self, iter: &mut TokenIter<'source>) fn take_from <'source: 'state> (
-> ::tengri::Perhaps<RenderBox<'state, #output>> state: &'state #view,
{ token: &mut ::tengri::dsl::TokenIter<'source>
Ok(match iter.peek() { #(#exposed)* _ => panic!(#error_msg) }) ) -> Perhaps<Self> {
Ok(match token.peek() { #(#exposed)* _ => None })
} }
} }
} { } {
@ -126,7 +126,7 @@ impl ToTokens for ViewArm {
out.append(Ident::new("Some", Span::call_site())); out.append(Ident::new("Some", Span::call_site()));
out.append(Group::new(Delimiter::Parenthesis, { out.append(Group::new(Delimiter::Parenthesis, {
let mut out = TokenStream2::new(); let mut out = TokenStream2::new();
out.append(Ident::new("self", Span::call_site())); out.append(Ident::new("state", Span::call_site()));
out.append(Punct::new('.', Alone)); out.append(Punct::new('.', Alone));
out.append(value.clone()); out.append(value.clone());
out.append(Group::new(Delimiter::Parenthesis, TokenStream2::new())); out.append(Group::new(Delimiter::Parenthesis, TokenStream2::new()));

View file

@ -21,6 +21,30 @@ impl<T: Content<TuiOut>> Content<TuiOut> for std::sync::Arc<T> {
} }
} }
impl<T: Content<TuiOut>> Content<TuiOut> for Result<T, Box<dyn std::error::Error>> {
fn content (&self) -> impl Render<TuiOut> {
Bsp::a(self.as_ref().ok(), self.as_ref().err()
.map(|e|Tui::fg_bg(Color::Rgb(255,255,255), Color::Rgb(32,32,32), e.to_string())))
}
}
//impl<T: Render<TuiOut>> Render<TuiOut> for Result<T, Box<dyn std::error::Error>> {
//fn layout (&self, to: [u16;4]) -> [u16;4] {
//match self {
//Ok(content) => content.layout(to),
//Err(e) => [0, 0, to.w(), to.h()]
//}
//}
//fn render (&self, to: &mut TuiOut) {
//match self {
//Ok(content) => content.render(to),
//Err(e) => to.blit(&e.to_string(), 0, 0, Some(Style::default()
//.bg(Color::Rgb(32,32,32))
//.fg(Color::Rgb(255,255,255))))
//}
//}
//}
mod tui_border; pub use self::tui_border::*; mod tui_border; pub use self::tui_border::*;
mod tui_button; pub use self::tui_button::*; mod tui_button; pub use self::tui_button::*;
mod tui_color; pub use self::tui_color::*; mod tui_color; pub use self::tui_color::*;