diff --git a/output/src/ops.rs b/output/src/ops.rs
index 7eba655..7b8010e 100644
--- a/output/src/ops.rs
+++ b/output/src/ops.rs
@@ -1,9 +1,10 @@
+//mod reduce; pub use self::reduce::*;
mod align; pub use self::align::*;
mod bsp; pub use self::bsp::*;
-mod cond; pub use self::cond::*;
+mod either; pub use self::either::*;
mod map; pub use self::map::*;
mod memo; pub use self::memo::*;
mod stack; pub use self::stack::*;
-//mod reduce; pub use self::reduce::*;
mod thunk; pub use self::thunk::*;
mod transform; pub use self::transform::*;
+mod when; pub use self::when::*;
diff --git a/output/src/ops/either.rs b/output/src/ops/either.rs
new file mode 100644
index 0000000..75c6ccf
--- /dev/null
+++ b/output/src/ops/either.rs
@@ -0,0 +1,38 @@
+use crate::*;
+
+/// 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 {
+ /// Create a ternary condition.
+ pub const fn new (c: bool, a: A, b: B) -> Self {
+ Self(c, a, b)
+ }
+}
+#[cfg(feature = "dsl")]
+impl + Dsl + Dsl> Namespace for Either {
+ fn take_from <'source> (
+ state: &T,
+ token: &mut TokenIter<'source>
+ ) -> Perhaps {
+ if let Some(Token { value: Value::Key("either"), .. }) = token.peek() {
+ let base = token.clone();
+ let _ = token.next().unwrap();
+ return Ok(Some(Self(
+ state.take_or_fail(token, "either: no condition")?,
+ state.take_or_fail(token, "either: no content 1")?,
+ state.take_or_fail(token, "either: no content 2")?,
+ )))
+ }
+ Ok(None)
+ }
+}
+impl, B: Render> Content for Either {
+ fn layout (&self, to: E::Area) -> E::Area {
+ 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;
+ if *cond { a.render(to) } else { b.render(to) }
+ }
+}
diff --git a/output/src/ops/cond.rs b/output/src/ops/when.rs
similarity index 51%
rename from output/src/ops/cond.rs
rename to output/src/ops/when.rs
index be950fe..188a5b5 100644
--- a/output/src/ops/cond.rs
+++ b/output/src/ops/when.rs
@@ -8,15 +8,6 @@ impl When {
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 {
- /// Create a ternary condition.
- pub const fn new (c: bool, a: A, b: B) -> Self {
- Self(c, a, b)
- }
-}
#[cfg(feature = "dsl")]
impl + Dsl> Namespace for When {
fn take_from <'source> (
@@ -55,31 +46,3 @@ impl> Content for When {
if *cond { item.render(to) }
}
}
-#[cfg(feature = "dsl")]
-impl + Dsl + Dsl> Namespace for Either {
- fn take_from <'source> (
- state: &T,
- token: &mut TokenIter<'source>
- ) -> Perhaps {
- if let Some(Token { value: Value::Key("either"), .. }) = token.peek() {
- let base = token.clone();
- let _ = token.next().unwrap();
- return Ok(Some(Self(
- state.take_or_fail(token, "either: no condition")?,
- state.take_or_fail(token, "either: no content 1")?,
- state.take_or_fail(token, "either: no content 2")?,
- )))
- }
- Ok(None)
- }
-}
-impl, B: Render> Content for Either {
- fn layout (&self, to: E::Area) -> E::Area {
- 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;
- if *cond { a.render(to) } else { b.render(to) }
- }
-}
diff --git a/proc/src/proc_view.rs b/proc/src/proc_view.rs
index 7223dc0..ac18a80 100644
--- a/proc/src/proc_view.rs
+++ b/proc/src/proc_view.rs
@@ -42,50 +42,53 @@ impl Parse for ViewImpl {
impl ToTokens for ViewDef {
fn to_tokens (&self, out: &mut TokenStream2) {
let Self(ViewMeta { output }, ViewImpl { block, exposed }) = self;
- let view = &block.self_ty;
- let builtins = builtins().iter().map(|ty|write_quote(quote! {
- if let Some(value) = Namespace::<#ty>::take_from(state, &mut exp.clone())? {
- return Ok(Some(value.boxed()))
- }
- })).collect::>();
- let mut available = vec![];
- let exposed: Vec<_> = exposed.iter().map(|(key, value)|{
- available.push(key.clone());
- write_quote(quote! { #key => Some(#view::#value(state).boxed()), })
- }).collect();
- let available: String = available.join(", ");
- let error_msg = LitStr::new(
- &format!("expected Sym(content), got: {{token:?}}, available: {available}"),
- Span::call_site()
- );
+ let self_ty = &block.self_ty;
+ let builtins: Vec<_> = builtins_with_types()
+ .iter()
+ .map(|ty|write_quote(quote! {
+ let value: Option<#ty> = Dsl::take(state, &mut exp.clone())?;
+ if let Some(value) = value {
+ return Ok(Some(value.boxed()))
+ }
+ }))
+ .collect();
+ let exposed: Vec<_> = exposed
+ .iter()
+ .map(|(key, value)|write_quote(quote! {
+ #key => Some(#self_ty::#value(state).boxed()),
+ })).collect();
write_quote_to(out, quote! {
#block
/// Generated by [tengri_proc].
///
- /// Delegates the rendering of [#view] to the [#view::view} method,
+ /// Delegates the rendering of [#self_ty] to the [#self_ty::view} method,
/// which you will need to implement, e.g. passing a [TokenIter]
/// containing a layout and keybindings config from user dirs.
- impl ::tengri::output::Content<#output> for #view {
+ impl ::tengri::output::Content<#output> for #self_ty {
fn content (&self) -> impl Render<#output> {
- self.view()
+ #self_ty::view(self)
}
}
/// Generated by [tengri_proc].
///
- /// Gives [#view] the ability to construct the [Render]able
+ /// Gives [#self_ty] the ability to construct the [Render]able
/// which might corresponds to a given [TokenStream],
- /// while taking [#view]'s state into consideration.
- impl ::tengri::dsl::Namespace<#view> for Box> {
+ /// while taking [#self_ty]'s state into consideration.
+ impl ::tengri::dsl::Namespace<#self_ty> for Box + '_> {
fn take_from <'source> (
- state: view,
+ state: self_ty,
words: &mut ::tengri::dsl::TokenIter<'source>
) -> Perhaps {
Ok(if let Some(::tengri::dsl::Token { value, .. }) = words.peek() {
match value {
+ // Expressions are handled by built-in functions
+ // that operate over constants and symbols.
::tengri::dsl::Value::Exp(_, exp) => {
- //#(#builtins)*
+ #(#builtins)*
None
},
+ // Symbols are handled by user-provided functions
+ // that take no parameters but `&self`.
::tengri::dsl::Value::Sym(sym) => match sym {
#(#exposed)*
_ => None
@@ -101,21 +104,21 @@ impl ToTokens for ViewDef {
}
}
-fn builtins () -> [TokenStream2;14] {
+fn builtins_with_types () -> [TokenStream2;14] {
[
- quote! { When::<_> },
- quote! { Either::<_, _> },
- quote! { Align::<_> },
- quote! { Bsp::<_, _> },
- quote! { Fill::<_> },
- quote! { Fixed::<_, _> },
- quote! { Min::<_, _> },
- quote! { Max::<_, _> },
- quote! { Shrink::<_, _> },
- quote! { Expand::<_, _> },
- quote! { Push::<_, _> },
- quote! { Pull::<_, _> },
- quote! { Margin::<_, _> },
- quote! { Padding::<_, _> },
+ quote! { When< Box + '_> > },
+ quote! { Either< Box + '_>, Box + '_>> },
+ quote! { Align< Box + '_> > },
+ quote! { Bsp< Box + '_>, Box + '_>> },
+ quote! { Fill< Box + '_> > },
+ quote! { Fixed<_, Box + '_> > },
+ quote! { Min<_, Box + '_> > },
+ quote! { Max<_, Box + '_> > },
+ quote! { Shrink<_, Box + '_> > },
+ quote! { Expand<_, Box + '_> > },
+ quote! { Push<_, Box + '_> > },
+ quote! { Pull<_, Box + '_> > },
+ quote! { Margin<_, Box + '_> > },
+ quote! { Padding<_, Box + '_> > },
]
}