mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 03:36:42 +01:00
wip: dsl, input, output, proc: more precise lifetimes
Some checks are pending
/ build (push) Waiting to run
Some checks are pending
/ build (push) Waiting to run
This commit is contained in:
parent
22d63eed9c
commit
5e09f5a4bb
11 changed files with 140 additions and 122 deletions
|
|
@ -1,11 +1,17 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait TryFromDsl<'a, T>: Sized {
|
||||
fn try_from_expr (_state: &'a T, _iter: TokenIter<'a>) -> Option<Self> {
|
||||
pub trait TryFromDsl<'state, T>: Sized {
|
||||
fn try_from_expr <'source: 'state> (
|
||||
_state: &'state T, _iter: TokenIter<'source>
|
||||
) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
fn try_from_atom (state: &'a T, value: Value<'a>) -> Option<Self> {
|
||||
if let Exp(0, iter) = value { return Self::try_from_expr(state, iter) }
|
||||
fn try_from_atom <'source: 'state> (
|
||||
state: &'state T, value: Value<'source>
|
||||
) -> Option<Self> {
|
||||
if let Exp(0, iter) = value {
|
||||
return Self::try_from_expr(state, iter.clone())
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -15,29 +21,20 @@ pub trait TryIntoDsl<T>: Sized {
|
|||
}
|
||||
|
||||
/// Map EDN tokens to parameters of a given type for a given context
|
||||
pub trait Context<U>: Sized {
|
||||
fn get (&self, _atom: &Value) -> Option<U> {
|
||||
pub trait Context<'state, U>: Sized {
|
||||
fn get <'source> (&'state self, _iter: &mut TokenIter<'source>) -> Option<U> {
|
||||
None
|
||||
}
|
||||
fn get_or_fail (&self, dsl: &Value) -> U {
|
||||
self.get(dsl).expect("no value")
|
||||
}
|
||||
|
||||
impl<'state, T: Context<'state, U>, U> Context<'state, U> for &T {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<U> {
|
||||
(*self).get(iter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Context<U>, U> Context<U> for &T {
|
||||
fn get (&self, dsl: &Value) -> Option<U> {
|
||||
(*self).get(dsl)
|
||||
}
|
||||
fn get_or_fail (&self, dsl: &Value) -> U {
|
||||
(*self).get_or_fail(dsl)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Context<U>, U> Context<U> for Option<T> {
|
||||
fn get (&self, dsl: &Value) -> Option<U> {
|
||||
self.as_ref().map(|s|s.get(dsl)).flatten()
|
||||
}
|
||||
fn get_or_fail (&self, dsl: &Value) -> U {
|
||||
self.as_ref().map(|s|s.get_or_fail(dsl)).expect("no provider")
|
||||
impl<'state, T: Context<'state, U>, U> Context<'state, U> for Option<T> {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<U> {
|
||||
self.as_ref().map(|s|s.get(iter)).flatten()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,38 +22,38 @@
|
|||
//!```
|
||||
use crate::*;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct Token<'a> {
|
||||
pub source: &'a str,
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct Token<'source> {
|
||||
pub source: &'source str,
|
||||
pub start: usize,
|
||||
pub length: usize,
|
||||
pub value: Value<'a>,
|
||||
pub value: Value<'source>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum Value<'a> {
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum Value<'source> {
|
||||
#[default] Nil,
|
||||
Err(ParseError),
|
||||
Num(usize),
|
||||
Sym(&'a str),
|
||||
Key(&'a str),
|
||||
Str(&'a str),
|
||||
Exp(usize, TokenIter<'a>),
|
||||
Sym(&'source str),
|
||||
Key(&'source str),
|
||||
Str(&'source str),
|
||||
Exp(usize, TokenIter<'source>),
|
||||
}
|
||||
|
||||
impl<'a> Token<'a> {
|
||||
pub const fn new (source: &'a str, start: usize, length: usize, value: Value<'a>) -> Self {
|
||||
impl<'source> Token<'source> {
|
||||
pub const fn new (source: &'source str, start: usize, length: usize, value: Value<'source>) -> Self {
|
||||
Self { source, start, length, value }
|
||||
}
|
||||
pub const fn end (&self) -> usize {
|
||||
self.start.saturating_add(self.length)
|
||||
}
|
||||
pub const fn slice (&'a self) -> &'a str {
|
||||
pub const fn slice (&'source self) -> &'source str {
|
||||
self.slice_source(self.source)
|
||||
//str_range(self.source, self.start, self.end())
|
||||
}
|
||||
pub const fn slice_source <'b> (&'a self, source: &'b str) -> &'b str {
|
||||
pub const fn slice_source <'range> (&'source self, source: &'range str) -> &'range str {
|
||||
str_range(source, self.start, self.end())
|
||||
}
|
||||
pub const fn slice_source_exp <'b> (&'a self, source: &'b str) -> &'b str {
|
||||
pub const fn slice_source_exp <'range> (&'source self, source: &'range str) -> &'range str {
|
||||
str_range(source, self.start.saturating_add(1), self.end())
|
||||
}
|
||||
pub const fn value (&self) -> Value {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ use crate::*;
|
|||
use std::marker::PhantomData;
|
||||
|
||||
/// A [Command] that can be constructed from a [Token].
|
||||
pub trait DslCommand<'a, C>: TryFromDsl<'a, C> + Command<C> {}
|
||||
pub trait DslCommand<'state, C>: TryFromDsl<'state, C> + Command<C> {}
|
||||
|
||||
impl<'a, C, T: TryFromDsl<'a, C> + Command<C>> DslCommand<'a, C> for T {}
|
||||
impl<'state, C, T: TryFromDsl<'state, C> + Command<C>> DslCommand<'state, C> for T {}
|
||||
|
||||
/// [Input] state that can be matched against a [Value].
|
||||
pub trait DslInput: Input {
|
||||
|
|
@ -12,14 +12,14 @@ pub trait DslInput: Input {
|
|||
}
|
||||
|
||||
/// A pre-configured mapping of input events to commands.
|
||||
pub trait KeyMap<'a, S, C: DslCommand<'a, S>, I: DslInput> {
|
||||
pub trait KeyMap<'state, S, C: DslCommand<'state, S>, I: DslInput> {
|
||||
/// Try to find a command that matches the current input event.
|
||||
fn command (&'a self, state: &'a S, input: &'a I) -> Option<C>;
|
||||
fn command (&'state self, state: &'state S, input: &'state I) -> Option<C>;
|
||||
}
|
||||
|
||||
/// A [SourceIter] can be a [KeyMap].
|
||||
impl<'a, S, C: DslCommand<'a, S>, I: DslInput> KeyMap<'a, S, C, I> for SourceIter<'a> {
|
||||
fn command (&'a self, state: &'a S, input: &'a I) -> Option<C> {
|
||||
impl<'state, S, C: DslCommand<'state, S>, I: DslInput> KeyMap<'state, S, C, I> for SourceIter<'state> {
|
||||
fn command (&'state self, state: &'state S, input: &'state I) -> Option<C> {
|
||||
let mut iter = self.clone();
|
||||
while let Some((token, rest)) = iter.next() {
|
||||
iter = rest;
|
||||
|
|
@ -45,8 +45,8 @@ impl<'a, S, C: DslCommand<'a, S>, I: DslInput> KeyMap<'a, S, C, I> for SourceIte
|
|||
}
|
||||
|
||||
/// A [TokenIter] can be a [KeyMap].
|
||||
impl<'a, S, C: DslCommand<'a, S>, I: DslInput> KeyMap<'a, S, C, I> for TokenIter<'a> {
|
||||
fn command (&'a self, state: &'a S, input: &'a I) -> Option<C> {
|
||||
impl<'state, S, C: DslCommand<'state, S>, I: DslInput> KeyMap<'state, S, C, I> for TokenIter<'state> {
|
||||
fn command (&'state self, state: &'state S, input: &'state I) -> Option<C> {
|
||||
let mut iter = self.clone();
|
||||
while let Some(next) = iter.next() {
|
||||
match next {
|
||||
|
|
@ -70,25 +70,25 @@ impl<'a, S, C: DslCommand<'a, S>, I: DslInput> KeyMap<'a, S, C, I> for TokenIter
|
|||
}
|
||||
}
|
||||
|
||||
pub type InputLayerCond<'a, S> = Box<dyn Fn(&S)->bool + Send + Sync + 'a>;
|
||||
pub type InputLayerCond<'state, S> = Box<dyn Fn(&S)->bool + Send + Sync + 'state>;
|
||||
|
||||
/// A collection of pre-configured mappings of input events to commands,
|
||||
/// which may be made available subject to given conditions.
|
||||
pub struct InputMap<'a, S, C, I, M>
|
||||
pub struct InputMap<'state, S, C, I, M>
|
||||
where
|
||||
C: DslCommand<'a, S>,
|
||||
C: DslCommand<'state, S>,
|
||||
I: DslInput,
|
||||
M: KeyMap<'a, S, C, I> + Send + Sync
|
||||
M: KeyMap<'state, S, C, I> + Send + Sync
|
||||
{
|
||||
__: &'a PhantomData<(S, C, I)>,
|
||||
pub layers: Vec<(InputLayerCond<'a, S>, M)>,
|
||||
__: &'state PhantomData<(S, C, I)>,
|
||||
pub layers: Vec<(InputLayerCond<'state, S>, M)>,
|
||||
}
|
||||
|
||||
impl<'a, S, C, I, M> Default for InputMap<'a, S, C, I, M>
|
||||
impl<'state, S, C, I, M> Default for InputMap<'state, S, C, I, M>
|
||||
where
|
||||
C: DslCommand<'a, S>,
|
||||
C: DslCommand<'state, S>,
|
||||
I: DslInput,
|
||||
M: KeyMap<'a, S, C, I> + Send + Sync
|
||||
M: KeyMap<'state, S, C, I> + Send + Sync
|
||||
{
|
||||
fn default () -> Self {
|
||||
Self {
|
||||
|
|
@ -98,11 +98,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, S, C, I, M> InputMap<'a, S, C, I, M>
|
||||
impl<'state, S, C, I, M> InputMap<'state, S, C, I, M>
|
||||
where
|
||||
C: DslCommand<'a, S>,
|
||||
C: DslCommand<'state, S>,
|
||||
I: DslInput,
|
||||
M: KeyMap<'a, S, C, I> + Send + Sync
|
||||
M: KeyMap<'state, S, C, I> + Send + Sync
|
||||
{
|
||||
pub fn new (keymap: M) -> Self {
|
||||
Self::default().layer(keymap)
|
||||
|
|
@ -115,21 +115,21 @@ where
|
|||
self.add_layer_if(Box::new(|_|true), keymap);
|
||||
self
|
||||
}
|
||||
pub fn layer_if (mut self, condition: InputLayerCond<'a, S>, keymap: M) -> Self {
|
||||
pub fn layer_if (mut self, condition: InputLayerCond<'state, S>, keymap: M) -> Self {
|
||||
self.add_layer_if(condition, keymap);
|
||||
self
|
||||
}
|
||||
pub fn add_layer_if (&mut self, condition: InputLayerCond<'a, S>, keymap: M) -> &mut Self {
|
||||
pub fn add_layer_if (&mut self, condition: InputLayerCond<'state, S>, keymap: M) -> &mut Self {
|
||||
self.layers.push((Box::new(condition), keymap));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S, C, I, M> std::fmt::Debug for InputMap<'a, S, C, I, M>
|
||||
impl<'state, S, C, I, M> std::fmt::Debug for InputMap<'state, S, C, I, M>
|
||||
where
|
||||
C: DslCommand<'a, S>,
|
||||
C: DslCommand<'state, S>,
|
||||
I: DslInput,
|
||||
M: KeyMap<'a, S, C, I> + Send + Sync
|
||||
M: KeyMap<'state, S, C, I> + Send + Sync
|
||||
{
|
||||
fn fmt (&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
write!(f, "[InputMap: {} layer(s)]", self.layers.len());
|
||||
|
|
@ -138,13 +138,13 @@ where
|
|||
}
|
||||
|
||||
/// An [InputMap] can be a [KeyMap].
|
||||
impl<'a, S, C, I, M> KeyMap<'a, S, C, I> for InputMap<'a, S, C, I, M>
|
||||
impl<'state, S, C, I, M> KeyMap<'state, S, C, I> for InputMap<'state, S, C, I, M>
|
||||
where
|
||||
C: DslCommand<'a, S>,
|
||||
C: DslCommand<'state, S>,
|
||||
I: DslInput,
|
||||
M: KeyMap<'a, S, C, I> + Send + Sync
|
||||
M: KeyMap<'state, S, C, I> + Send + Sync
|
||||
{
|
||||
fn command (&'a self, state: &'a S, input: &'a I) -> Option<C> {
|
||||
fn command (&'state self, state: &'state S, input: &'state I) -> Option<C> {
|
||||
for (condition, keymap) in self.layers.iter() {
|
||||
if !condition(state) {
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W }
|
|||
pub struct Align<A>(Alignment, A);
|
||||
|
||||
#[cfg(feature = "dsl")]
|
||||
try_from_expr!(<'a, E>: Align<RenderBox<'a, E>>: |state, iter|{
|
||||
try_from_expr!(<'source, 'state, E>: Align<RenderBox<'state, E>>: |state, iter|{
|
||||
if let Some(Token { value: Value::Key(key), .. }) = iter.peek() {
|
||||
match key {
|
||||
"align/c"|"align/x"|"align/y"|
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl<E: Output, A: Content<E>, B: Content<E>> Content<E> for Bsp<A, B> {
|
|||
}
|
||||
}
|
||||
#[cfg(feature = "dsl")]
|
||||
try_from_expr!(<'a, E>: Bsp<RenderBox<'a, E>, RenderBox<'a, E>>: |state, iter| {
|
||||
try_from_expr!(<'source, 'state, E>: Bsp<RenderBox<'state, E>, RenderBox<'state, E>>: |state, iter| {
|
||||
if let Some(Token { value: Value::Key(key), .. }) = iter.peek() {
|
||||
match key {
|
||||
"bsp/n"|"bsp/s"|"bsp/e"|"bsp/w"|"bsp/a"|"bsp/b" => {
|
||||
|
|
|
|||
|
|
@ -19,12 +19,12 @@ impl<A, B> Either<A, B> {
|
|||
}
|
||||
|
||||
#[cfg(feature = "dsl")]
|
||||
try_from_expr!(<'a, E>: When<RenderBox<'a, E>>: |state, iter| {
|
||||
try_from_expr!(<'source, 'state, E>: When<RenderBox<'state, E>>: |state, iter| {
|
||||
if let Some(Token { value: Value::Key("when"), .. }) = iter.peek() {
|
||||
let _ = iter.next().unwrap();
|
||||
|
||||
let condition = iter.next().expect("no condition specified");
|
||||
let condition = state.get(&condition.value).expect("no condition provided");
|
||||
let condition = state.get(&mut iter).expect("no condition provided");
|
||||
|
||||
let content = iter.next().expect("no content specified");
|
||||
let content = if let Some(content) = state.get_content(&content.value) {
|
||||
|
|
@ -38,12 +38,12 @@ try_from_expr!(<'a, E>: When<RenderBox<'a, E>>: |state, iter| {
|
|||
});
|
||||
|
||||
#[cfg(feature = "dsl")]
|
||||
try_from_expr!(<'a, E>: Either<RenderBox<'a, E>, RenderBox<'a, E>>: |state, iter| {
|
||||
try_from_expr!(<'source, 'state, E>: Either<RenderBox<'state, E>, RenderBox<'state, E>>: |state, iter| {
|
||||
if let Some(Token { value: Value::Key("either"), .. }) = iter.peek() {
|
||||
let _ = iter.next().unwrap();
|
||||
|
||||
let condition = iter.next().expect("no condition specified");
|
||||
let condition = state.get(&condition.value).expect("no condition provided");
|
||||
let condition = state.get(&mut iter).expect("no condition provided");
|
||||
|
||||
let content = iter.next().expect("no content specified");
|
||||
let content = if let Some(content) = state.get_content(&content.value) {
|
||||
|
|
|
|||
|
|
@ -33,9 +33,11 @@ macro_rules! transform_xy {
|
|||
#[inline] pub const fn xy (item: T) -> Self { Self::XY(item) }
|
||||
}
|
||||
#[cfg(feature = "dsl")]
|
||||
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromDsl<'a, T>
|
||||
for $Enum<RenderBox<'a, E>> {
|
||||
fn try_from_expr (state: &'a T, iter: TokenIter<'a>) -> Option<Self> {
|
||||
impl<'state, E: Output + 'state, T: ViewContext<'state, E>> TryFromDsl<'state, T>
|
||||
for $Enum<RenderBox<'state, E>> {
|
||||
fn try_from_expr <'source: 'state> (state: &'state T, iter: TokenIter<'source>)
|
||||
-> Option<Self>
|
||||
{
|
||||
let mut iter = iter.clone();
|
||||
if let Some(Token { value: Value::Key(k), .. }) = iter.peek() {
|
||||
if k == $x || k == $y || k == $xy {
|
||||
|
|
@ -80,17 +82,16 @@ macro_rules! transform_xy_unit {
|
|||
#[inline] pub const fn xy (x: U, y: U, item: T) -> Self { Self::XY(x, y, item) }
|
||||
}
|
||||
#[cfg(feature = "dsl")]
|
||||
impl<'a, E: Output + 'a, T: ViewContext<'a, E>> TryFromDsl<'a, T>
|
||||
for $Enum<E::Unit, RenderBox<'a, E>> {
|
||||
fn try_from_expr (state: &'a T, iter: TokenIter<'a>) -> Option<Self> {
|
||||
impl<'state, E: Output + 'state, T: ViewContext<'state, E>> TryFromDsl<'state, T>
|
||||
for $Enum<E::Unit, RenderBox<'state, E>> {
|
||||
fn try_from_expr <'source: 'state> (state: &'state T, iter: TokenIter<'source>) -> Option<Self> {
|
||||
let mut iter = iter.clone();
|
||||
if let Some(Token { value: Value::Key(k), .. }) = iter.peek() {
|
||||
if k == $x || k == $y {
|
||||
let _ = iter.next().unwrap();
|
||||
let u = iter.next().expect("no unit specified");
|
||||
let u = get_value!(state => u);
|
||||
let c = iter.next().expect("no content specified");
|
||||
let c = get_content!(state => c);
|
||||
let u = state.get(&mut iter).expect("no unit specified");
|
||||
let c = state.get_content(&iter.next().expect("no content specified").value)
|
||||
.expect("no content provided");
|
||||
return Some(match k {
|
||||
$x => Self::x(u, c),
|
||||
$y => Self::y(u, c),
|
||||
|
|
@ -98,9 +99,10 @@ macro_rules! transform_xy_unit {
|
|||
})
|
||||
} else if k == $xy {
|
||||
let _ = iter.next().unwrap();
|
||||
let u = get_value!(state => iter.next().expect("no unit specified"));
|
||||
let v = get_value!(state => iter.next().expect("no unit specified"));
|
||||
let c = get_content!(state => iter.next().expect("no content specified"));
|
||||
let u = state.get(&mut iter).expect("no unit specified");
|
||||
let v = state.get(&mut iter).expect("no unit specified");
|
||||
let c = state.get_content(&iter.next().expect("no content specified").value)
|
||||
.expect("no content provided");
|
||||
return Some(Self::xy(u, v, c))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,34 +45,37 @@ impl<'a, O: Output + 'a, T: ViewContext<'a, O>> Content<O> for View<'a, T> {
|
|||
|
||||
// Provides components to the view.
|
||||
#[cfg(feature = "dsl")]
|
||||
pub trait ViewContext<'a, E: Output + 'a>: Send + Sync
|
||||
+ Context<bool>
|
||||
+ Context<usize>
|
||||
+ Context<E::Unit>
|
||||
pub trait ViewContext<'state, E: Output + 'state>: Send + Sync
|
||||
+ Context<'state, bool>
|
||||
+ Context<'state, usize>
|
||||
+ Context<'state, E::Unit>
|
||||
{
|
||||
fn get_content (&'a self, value: &Value<'a>) -> Option<RenderBox<'a, E>> {
|
||||
fn get_content <'source: 'state> (&'state self, value: &Value<'source>) -> Option<RenderBox<'state, E>> {
|
||||
match value {
|
||||
Value::Sym(_) => self.get_content_sym(value),
|
||||
Value::Exp(_, _) => self.get_content_exp(value),
|
||||
_ => panic!("only :symbols and (expressions) accepted here")
|
||||
}
|
||||
}
|
||||
fn get_content_sym (&'a self, value: &Value<'a>) -> Option<RenderBox<'a, E>>;
|
||||
fn get_content_exp (&'a self, value: &Value<'a>) -> Option<RenderBox<'a, E>> {
|
||||
try_delegate!(self, *value, When::<RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Either::<RenderBox<'a, E>, RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Align::<RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Bsp::<RenderBox<'a, E>, RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Fill::<RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Fixed::<_, RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Min::<_, RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Max::<_, RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Shrink::<_, RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Expand::<_, RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Push::<_, RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Pull::<_, RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Margin::<_, RenderBox<'a, E>>);
|
||||
try_delegate!(self, *value, Padding::<_, RenderBox<'a, E>>);
|
||||
fn get_content_sym <'source: 'state> (&'state self, value: &Value<'source>)
|
||||
-> Option<RenderBox<'state, E>>;
|
||||
fn get_content_exp <'source: 'state> (&'state self, value: &Value<'source>)
|
||||
-> Option<RenderBox<'state, E>>
|
||||
{
|
||||
try_delegate!(self, *value, When::<RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Either::<RenderBox<'state, E>, RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Align::<RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Bsp::<RenderBox<'state, E>, RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Fill::<RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Fixed::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Min::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Max::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Shrink::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Expand::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Push::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Pull::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Margin::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, *value, Padding::<_, RenderBox<'state, E>>);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -88,9 +91,20 @@ pub trait ViewContext<'a, E: Output + 'a>: Send + Sync
|
|||
|
||||
#[cfg(feature = "dsl")]
|
||||
#[macro_export] macro_rules! try_from_expr {
|
||||
(<$l:lifetime, $E:ident>: $Struct:ty: |$state:ident, $iter:ident|$body:expr) => {
|
||||
impl<$l, $E: Output + $l, T: ViewContext<$l, $E>> TryFromDsl<$l, T> for $Struct {
|
||||
fn try_from_expr ($state: &$l T, $iter: TokenIter<'a>) -> Option<Self> {
|
||||
(<
|
||||
$lt_source:lifetime,
|
||||
$lt_state:lifetime,
|
||||
$Output:ident
|
||||
>: $Struct:ty: |$state:ident, $iter:ident|$body:expr) => {
|
||||
impl<
|
||||
$lt_state,
|
||||
$Output: Output + $lt_state,
|
||||
T: ViewContext<$lt_state, $Output>
|
||||
> TryFromDsl<$lt_state, T> for $Struct {
|
||||
fn try_from_expr <$lt_source: $lt_state> (
|
||||
$state: &$lt_state T,
|
||||
$iter: TokenIter<$lt_source>
|
||||
) -> Option<Self> {
|
||||
let mut $iter = $iter.clone();
|
||||
$body;
|
||||
None
|
||||
|
|
|
|||
|
|
@ -68,8 +68,10 @@ impl ToTokens for CommandDef {
|
|||
}
|
||||
#block
|
||||
/// Generated by [tengri_proc].
|
||||
impl<'a> TryFromDsl<'a, #target> for #enumeration {
|
||||
fn try_from_expr (state: &#target, iter: TokenIter) -> Option<Self> {
|
||||
impl<'state> TryFromDsl<'state, #target> for #enumeration {
|
||||
fn try_from_expr <'source: 'state> (
|
||||
state: &'state #target, iter: TokenIter<'source>
|
||||
) -> Option<Self> {
|
||||
let mut iter = iter.clone();
|
||||
match iter.next() {
|
||||
#(#matchers)*
|
||||
|
|
@ -148,11 +150,10 @@ impl CommandArm {
|
|||
for (arg, ty) in self.args() {
|
||||
let take_err = LitStr::new(&format!("{}: missing argument \"{}\" ({})",
|
||||
quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site());
|
||||
let give_err = LitStr::new(&format!("{}: missing value \"{}\" ({})",
|
||||
let give_err = LitStr::new(&format!("{}: missing value for \"{}\" ({})",
|
||||
quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site());
|
||||
write_quote_to(&mut out, quote! {
|
||||
#arg : Context::get(state, &iter.next().expect(#take_err).value)
|
||||
.expect(#give_err) ,
|
||||
#arg: Context::get(state, &mut iter).expect(#give_err),
|
||||
});
|
||||
}
|
||||
out
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ impl ToTokens for ExposeImpl {
|
|||
let formatted_type = format!("{}", quote! { #t });
|
||||
let predefined = match formatted_type.as_str() {
|
||||
"bool" => quote! {
|
||||
::tengri::dsl::Value::Sym(":true") => true,
|
||||
::tengri::dsl::Value::Sym(":false") => false,
|
||||
Some(::tengri::dsl::Value::Sym(":true")) => true,
|
||||
Some(::tengri::dsl::Value::Sym(":false")) => false,
|
||||
},
|
||||
"u8" | "u16" | "u32" | "u64" | "usize" |
|
||||
"i8" | "i16" | "i32" | "i64" | "isize" => {
|
||||
|
|
@ -76,7 +76,7 @@ impl ToTokens for ExposeImpl {
|
|||
Span::call_site()
|
||||
);
|
||||
quote! {
|
||||
::tengri::dsl::Value::Num(n) => TryInto::<#t>::try_into(*n)
|
||||
Some(::tengri::dsl::Value::Num(n)) => TryInto::<#t>::try_into(n)
|
||||
.unwrap_or_else(|_|panic!(#num_err)),
|
||||
}
|
||||
},
|
||||
|
|
@ -85,9 +85,11 @@ impl ToTokens for ExposeImpl {
|
|||
let values = variants.iter().map(ExposeArm::from);
|
||||
write_quote_to(out, quote! {
|
||||
/// Generated by [tengri_proc].
|
||||
impl ::tengri::dsl::Context<#t> for #target {
|
||||
fn get (&self, dsl: &::tengri::dsl::Value) -> Option<#t> {
|
||||
Some(match dsl {
|
||||
impl<'state> ::tengri::dsl::Context<'state, #t> for #target {
|
||||
fn get <'source> (
|
||||
&self, iter: &mut ::tengri::dsl::TokenIter<'source>
|
||||
) -> Option<#t> {
|
||||
Some(match iter.next().map(|x|x.value) {
|
||||
#predefined
|
||||
#(#values,)*
|
||||
_ => return None
|
||||
|
|
@ -113,7 +115,7 @@ impl ToTokens for ExposeArm {
|
|||
let Self(key, value) = self;
|
||||
let key = LitStr::new(&key, Span::call_site());
|
||||
write_quote_to(out, quote! {
|
||||
::tengri::dsl::Value::Sym(#key) => self.#value()
|
||||
Some(::tengri::dsl::Value::Sym(#key)) => self.#value()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,8 +55,10 @@ impl ToTokens for ViewDef {
|
|||
}
|
||||
}
|
||||
/// Generated by [tengri_proc].
|
||||
impl<'a> ::tengri::output::ViewContext<'a, #output> for #ident {
|
||||
fn get_content_sym (&'a self, value: &Value<'a>) -> Option<RenderBox<'a, #output>> {
|
||||
impl<'state> ::tengri::output::ViewContext<'state, #output> for #ident {
|
||||
fn get_content_sym <'source: 'state> (&'state self, value: &Value<'source>)
|
||||
-> Option<RenderBox<'state, #output>>
|
||||
{
|
||||
match value {
|
||||
#(#exposed)*
|
||||
_ => panic!("expected Sym(content), got: {value:?}")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue