mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 11:46:42 +01:00
extact dsl_token; flip Dsl; try to obviate ViewContext
This commit is contained in:
parent
f08593f0f8
commit
f797a7143d
12 changed files with 264 additions and 209 deletions
|
|
@ -171,112 +171,3 @@ pub const fn to_digit (c: char) -> DslResult<usize> {
|
|||
_ => return Result::Err(Unexpected(c))
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct Token<'source> {
|
||||
pub source: &'source str,
|
||||
pub start: usize,
|
||||
pub length: usize,
|
||||
pub value: Value<'source>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum Value<'source> {
|
||||
#[default] Nil,
|
||||
Err(DslError),
|
||||
Num(usize),
|
||||
Sym(&'source str),
|
||||
Key(&'source str),
|
||||
Str(&'source str),
|
||||
Exp(usize, TokenIter<'source>),
|
||||
}
|
||||
|
||||
impl<'source> std::fmt::Display for Value<'source> {
|
||||
fn fmt (&self, out: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
write!(out, "{}", match self {
|
||||
Nil => String::new(),
|
||||
Err(e) => format!("[error: {e}]"),
|
||||
Num(n) => format!("{n}"),
|
||||
Sym(s) => format!("{s}"),
|
||||
Key(s) => format!("{s}"),
|
||||
Str(s) => format!("{s}"),
|
||||
Exp(_, e) => format!("{e:?}"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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 (&'source self) -> &'source str {
|
||||
self.slice_source(self.source)
|
||||
}
|
||||
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 <'range> (&'source self, source: &'range str) -> &'range str {
|
||||
str_range(source, self.start.saturating_add(1), self.end())
|
||||
}
|
||||
pub const fn with_value (self, value: Value<'source>) -> Self {
|
||||
Self { value, ..self }
|
||||
}
|
||||
pub const fn value (&self) -> Value {
|
||||
self.value
|
||||
}
|
||||
pub const fn error (self, error: DslError) -> Self {
|
||||
Self { value: Value::Err(error), ..self }
|
||||
}
|
||||
pub const fn grow (self) -> Self {
|
||||
Self { length: self.length.saturating_add(1), ..self }
|
||||
}
|
||||
pub const fn grow_num (self, m: usize, c: char) -> Self {
|
||||
match to_digit(c) {
|
||||
Ok(n) => Self { value: Num(10*m+n), ..self.grow() },
|
||||
Result::Err(e) => Self { value: Err(e), ..self.grow() },
|
||||
}
|
||||
}
|
||||
pub const fn grow_key (self) -> Self {
|
||||
let token = self.grow();
|
||||
token.with_value(Key(token.slice_source(self.source)))
|
||||
}
|
||||
pub const fn grow_sym (self) -> Self {
|
||||
let token = self.grow();
|
||||
token.with_value(Sym(token.slice_source(self.source)))
|
||||
}
|
||||
pub const fn grow_str (self) -> Self {
|
||||
let token = self.grow();
|
||||
token.with_value(Str(token.slice_source(self.source)))
|
||||
}
|
||||
pub const fn grow_exp (self) -> Self {
|
||||
let token = self.grow();
|
||||
if let Exp(depth, _) = token.value {
|
||||
token.with_value(Exp(depth, TokenIter::new(token.slice_source_exp(self.source))))
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
pub const fn grow_in (self) -> Self {
|
||||
let token = self.grow_exp();
|
||||
if let Value::Exp(depth, source) = token.value {
|
||||
token.with_value(Value::Exp(depth.saturating_add(1), source))
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
pub const fn grow_out (self) -> Self {
|
||||
let token = self.grow_exp();
|
||||
if let Value::Exp(depth, source) = token.value {
|
||||
if depth > 0 {
|
||||
token.with_value(Value::Exp(depth - 1, source))
|
||||
} else {
|
||||
return self.error(Unexpected(')'))
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,49 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait Dsl<State>: Sized {
|
||||
fn take_from <'state, 'source: 'state> (state: &'state State, _: &mut TokenIter<'source>)
|
||||
-> Perhaps<Self>
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn take_from_or_fail <'state, 'source: 'state> (
|
||||
state: &'state State,
|
||||
token: &mut TokenIter<'source>,
|
||||
error: impl Into<Box<dyn std::error::Error>>
|
||||
) -> Usually<Self> {
|
||||
if let Some(value) = Dsl::<State>::take_from(state, token)? {
|
||||
Ok(value)
|
||||
} else {
|
||||
Result::Err(error.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U: Dsl<T>> DslFrom<U> for T {}
|
||||
|
||||
pub trait DslFrom<T: Dsl<Self>>: Sized {
|
||||
fn take <'state, 'source: 'state> (&'state self, token: &mut TokenIter<'source>)
|
||||
-> Perhaps<T>
|
||||
{
|
||||
T::take_from(self, token)
|
||||
}
|
||||
fn take_or_fail <'state, 'source: 'state> (
|
||||
&'state self,
|
||||
token: &mut TokenIter<'source>,
|
||||
error: impl Into<Box<dyn std::error::Error>>
|
||||
) -> Usually<T> {
|
||||
T::take_from_or_fail(self, token, error)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement the [Dsl] trait, which boils down to
|
||||
/// specifying two types and providing an expression.
|
||||
#[macro_export] macro_rules! dsl {
|
||||
($T:ty: |$self:ident:$S:ty, $iter:ident|$expr:expr) => {
|
||||
impl ::tengri::dsl::Dsl<$T> for $S {
|
||||
fn take <'state, 'source> (
|
||||
&'state $self, $iter: &mut ::tengri::dsl::TokenIter<'source>,
|
||||
impl ::tengri::dsl::Dsl<$S> for $T {
|
||||
fn take_from <'state, 'source: 'state> (
|
||||
state: &'state $S,
|
||||
$iter: &mut ::tengri::dsl::TokenIter<'source>,
|
||||
) -> ::tengri::Perhaps<$T> {
|
||||
$expr
|
||||
}
|
||||
|
|
@ -14,43 +51,24 @@ use crate::*;
|
|||
}
|
||||
}
|
||||
|
||||
/// Maps a sequencer of EDN tokens to parameters of supported types
|
||||
/// for a given context.
|
||||
pub trait Dsl<Value>: Sized {
|
||||
fn take <'state, 'source> (&'state self, _: &mut TokenIter<'source>) -> Perhaps<Value> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn take_or_fail <'state, 'source> (
|
||||
&'state self,
|
||||
token: &mut TokenIter<'source>,
|
||||
error: impl Into<Box<dyn std::error::Error>>
|
||||
) -> Usually<Value> {
|
||||
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)
|
||||
} else {
|
||||
Result::Err(error.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
///// Maps a sequencer of EDN tokens to parameters of supported types
|
||||
///// for a given context.
|
||||
//pub trait Dsl<Value>: Sized {
|
||||
//fn take <'state, 'source> (&'state self, _: &mut TokenIter<'source>) -> Perhaps<Value> {
|
||||
//unimplemented!()
|
||||
//}
|
||||
//fn take_or_fail <'state, 'source> (
|
||||
//&'state self,
|
||||
//token: &mut TokenIter<'source>,
|
||||
//error: impl Into<Box<dyn std::error::Error>>
|
||||
//) -> Usually<Value> {
|
||||
//if let Some(value) = Dsl::<Value>::take(self, token)? {
|
||||
//Ok(value)
|
||||
//} else {
|
||||
//Result::Err(error.into())
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
//impl<T: Dsl<U>, U> Dsl<U> for &T {
|
||||
//fn take <'state, 'source> (&'state self, iter: &mut TokenIter<'source>) -> Perhaps<U> {
|
||||
|
|
@ -64,8 +82,8 @@ pub trait FromDsl<'state, State>: Sized {
|
|||
//}
|
||||
//}
|
||||
|
||||
impl<'state, X, Y> Dsl<X> for Y where Y: FromDsl<'state, X> {
|
||||
}
|
||||
|
||||
//impl<T, U: FromDsl<T>> Dsl<U> for T {
|
||||
//impl<'state, X, Y> Dsl<X> for Y where Y: Dsl<'state, X> {
|
||||
//}
|
||||
|
||||
//impl<T, U: Dsl<T>> Dsl<U> for T {
|
||||
//}
|
||||
|
|
|
|||
110
dsl/src/dsl_token.rs
Normal file
110
dsl/src/dsl_token.rs
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
use crate::*;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct Token<'source> {
|
||||
pub source: &'source str,
|
||||
pub start: usize,
|
||||
pub length: usize,
|
||||
pub value: Value<'source>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum Value<'source> {
|
||||
#[default] Nil,
|
||||
Err(DslError),
|
||||
Num(usize),
|
||||
Sym(&'source str),
|
||||
Key(&'source str),
|
||||
Str(&'source str),
|
||||
Exp(usize, TokenIter<'source>),
|
||||
}
|
||||
|
||||
impl<'source> std::fmt::Display for Value<'source> {
|
||||
fn fmt (&self, out: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
write!(out, "{}", match self {
|
||||
Nil => String::new(),
|
||||
Err(e) => format!("[error: {e}]"),
|
||||
Num(n) => format!("{n}"),
|
||||
Sym(s) => format!("{s}"),
|
||||
Key(s) => format!("{s}"),
|
||||
Str(s) => format!("{s}"),
|
||||
Exp(_, e) => format!("{e:?}"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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 (&'source self) -> &'source str {
|
||||
self.slice_source(self.source)
|
||||
}
|
||||
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 <'range> (&'source self, source: &'range str) -> &'range str {
|
||||
str_range(source, self.start.saturating_add(1), self.end())
|
||||
}
|
||||
pub const fn with_value (self, value: Value<'source>) -> Self {
|
||||
Self { value, ..self }
|
||||
}
|
||||
pub const fn value (&self) -> Value {
|
||||
self.value
|
||||
}
|
||||
pub const fn error (self, error: DslError) -> Self {
|
||||
Self { value: Value::Err(error), ..self }
|
||||
}
|
||||
pub const fn grow (self) -> Self {
|
||||
Self { length: self.length.saturating_add(1), ..self }
|
||||
}
|
||||
pub const fn grow_num (self, m: usize, c: char) -> Self {
|
||||
match to_digit(c) {
|
||||
Ok(n) => Self { value: Num(10*m+n), ..self.grow() },
|
||||
Result::Err(e) => Self { value: Err(e), ..self.grow() },
|
||||
}
|
||||
}
|
||||
pub const fn grow_key (self) -> Self {
|
||||
let token = self.grow();
|
||||
token.with_value(Key(token.slice_source(self.source)))
|
||||
}
|
||||
pub const fn grow_sym (self) -> Self {
|
||||
let token = self.grow();
|
||||
token.with_value(Sym(token.slice_source(self.source)))
|
||||
}
|
||||
pub const fn grow_str (self) -> Self {
|
||||
let token = self.grow();
|
||||
token.with_value(Str(token.slice_source(self.source)))
|
||||
}
|
||||
pub const fn grow_exp (self) -> Self {
|
||||
let token = self.grow();
|
||||
if let Exp(depth, _) = token.value {
|
||||
token.with_value(Exp(depth, TokenIter::new(token.slice_source_exp(self.source))))
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
pub const fn grow_in (self) -> Self {
|
||||
let token = self.grow_exp();
|
||||
if let Value::Exp(depth, source) = token.value {
|
||||
token.with_value(Value::Exp(depth.saturating_add(1), source))
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
pub const fn grow_out (self) -> Self {
|
||||
let token = self.grow_exp();
|
||||
if let Value::Exp(depth, source) = token.value {
|
||||
if depth > 0 {
|
||||
token.with_value(Value::Exp(depth - 1, source))
|
||||
} else {
|
||||
return self.error(Unexpected(')'))
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -46,6 +46,7 @@ pub(crate) use self::Value::*;
|
|||
pub(crate) use self::DslError::*;
|
||||
|
||||
mod dsl_error; pub use self::dsl_error::*;
|
||||
mod dsl_token; pub use self::dsl_token::*;
|
||||
mod dsl_parse; pub use self::dsl_parse::*;
|
||||
mod dsl_provide; pub use self::dsl_provide::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ use std::marker::PhantomData;
|
|||
pub trait DslInput: Input { fn matches_dsl (&self, token: &str) -> bool; }
|
||||
|
||||
/// A pre-configured mapping of input events to commands.
|
||||
pub trait KeyMap<S: Dsl<C>, C: Command<S>, I: DslInput> {
|
||||
pub trait KeyMap<S, C: Dsl<S> + Command<S>, I: DslInput> {
|
||||
/// Try to find a command that matches the current input event.
|
||||
fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps<C>;
|
||||
}
|
||||
|
||||
/// A [SourceIter] can be a [KeyMap].
|
||||
impl<'source, S: Dsl<C>, C: Command<S>, I: DslInput> KeyMap<S, C, I> for SourceIter<'source> {
|
||||
impl<'source, S, C: Dsl<S> + Command<S>, I: DslInput> KeyMap<S, C, I> for SourceIter<'source> {
|
||||
fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps<C> {
|
||||
let mut iter = self.clone();
|
||||
while let Some((token, rest)) = iter.next() {
|
||||
|
|
@ -22,7 +22,7 @@ impl<'source, S: Dsl<C>, C: Command<S>, I: DslInput> KeyMap<S, C, I> for SourceI
|
|||
match exp_iter.next() {
|
||||
Some(Token { value: Value::Sym(binding), .. }) => {
|
||||
if input.matches_dsl(binding) {
|
||||
if let Some(command) = Dsl::<C>::take(state, &mut exp_iter)? {
|
||||
if let Some(command) = Dsl::take_from(state, &mut exp_iter)? {
|
||||
return Ok(Some(command))
|
||||
}
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ impl<'source, S: Dsl<C>, C: Command<S>, I: DslInput> KeyMap<S, C, I> for SourceI
|
|||
}
|
||||
|
||||
/// A [TokenIter] can be a [KeyMap].
|
||||
impl<'source, S: Dsl<C>, C: Command<S>, I: DslInput> KeyMap<S, C, I> for TokenIter<'source> {
|
||||
impl<'source, S, C: Dsl<S> + Command<S>, I: DslInput> KeyMap<S, C, I> for TokenIter<'source> {
|
||||
fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps<C> {
|
||||
let mut iter = self.clone();
|
||||
while let Some(next) = iter.next() {
|
||||
|
|
@ -48,7 +48,7 @@ impl<'source, S: Dsl<C>, C: Command<S>, I: DslInput> KeyMap<S, C, I> for TokenIt
|
|||
match e.next() {
|
||||
Some(Token { value: Value::Sym(binding), .. }) => {
|
||||
if input.matches_dsl(binding) {
|
||||
if let Some(command) = Dsl::<C>::take(state, &mut e)? {
|
||||
if let Some(command) = C::take_from(state, &mut e)? {
|
||||
return Ok(Some(command))
|
||||
}
|
||||
}
|
||||
|
|
@ -68,20 +68,20 @@ pub type InputLayerCond<S> = Box<dyn Fn(&S)->Usually<bool> + Send + Sync>;
|
|||
/// A collection of pre-configured mappings of input events to commands,
|
||||
/// which may be made available subject to given conditions.
|
||||
pub struct InputMap<S, C, I, M>
|
||||
where S: Dsl<C>, C: Command<S>, I: DslInput, M: KeyMap<S, C, I> + Send + Sync {
|
||||
where C: Dsl<S> + Command<S>, I: DslInput, M: KeyMap<S, C, I> + Send + Sync {
|
||||
__: PhantomData<(S, C, I)>,
|
||||
pub layers: Vec<(InputLayerCond<S>, M)>,
|
||||
}
|
||||
|
||||
impl<S, C, I, M> Default for InputMap<S, C, I, M>
|
||||
where S: Dsl<C>, C: Command<S>, I: DslInput, M: KeyMap<S, C, I> + Send + Sync {
|
||||
where C: Dsl<S> + Command<S>, I: DslInput, M: KeyMap<S, C, I> + Send + Sync {
|
||||
fn default () -> Self {
|
||||
Self { __: PhantomData, layers: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, C, I, M> InputMap<S, C, I, M>
|
||||
where S: Dsl<C> + 'static, C: Command<S>, I: DslInput, M: KeyMap<S, C, I> + Send + Sync {
|
||||
impl<S: 'static, C, I, M> InputMap<S, C, I, M>
|
||||
where C: Dsl<S> + Command<S>, I: DslInput, M: KeyMap<S, C, I> + Send + Sync {
|
||||
pub fn new (keymap: M) -> Self {
|
||||
Self::default().layer(keymap)
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ where S: Dsl<C> + 'static, C: Command<S>, I: DslInput, M: KeyMap<S, C, I> + Send
|
|||
}
|
||||
|
||||
impl<S, C, I, M> std::fmt::Debug for InputMap<S, C, I, M>
|
||||
where S: Dsl<C>, C: Command<S>, I: DslInput, M: KeyMap<S, C, I> + Send + Sync {
|
||||
where C: Dsl<S> + Command<S>, I: DslInput, M: KeyMap<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())
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ where S: Dsl<C>, C: Command<S>, I: DslInput, M: KeyMap<S, C, I> + Send + Sync {
|
|||
|
||||
/// An [InputMap] can be a [KeyMap].
|
||||
impl<S, C, I, M> KeyMap<S, C, I> for InputMap<S, C, I, M>
|
||||
where S: Dsl<C>, C: Command<S>, I: DslInput, M: KeyMap<S, C, I> + Send + Sync {
|
||||
where C: Dsl<S> + Command<S>, I: DslInput, M: KeyMap<S, C, I> + Send + Sync {
|
||||
fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps<C> {
|
||||
for (condition, keymap) in self.layers.iter() {
|
||||
if !condition(state)? {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ pub struct Align<A>(Alignment, A);
|
|||
|
||||
#[cfg(feature = "dsl")]
|
||||
impl<'state, E: Output + 'state, T: ViewContext<'state, E>>
|
||||
FromDsl<'state, T> for Align<RenderBox<'state, E>> {
|
||||
Dsl<T> for Align<RenderBox<'state, E>> {
|
||||
fn take_from <'source: 'state> (state: &'state T, iter: &mut TokenIter<'source>) -> Perhaps<Self> {
|
||||
if let Some(Token { value: Value::Key(key), .. }) = iter.peek() {
|
||||
match key {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ impl<E: Output, A: Content<E>, B: Content<E>> Content<E> for Bsp<A, B> {
|
|||
}
|
||||
#[cfg(feature = "dsl")]
|
||||
impl<'state, E: Output + 'state, T: ViewContext<'state, E>>
|
||||
FromDsl<'state, T> for Bsp<RenderBox<'state, E>, RenderBox<'state, E>> {
|
||||
Dsl<T> for Bsp<RenderBox<'state, E>, RenderBox<'state, E>> {
|
||||
fn take_from <'source: 'state> (state: &'state T, iter: &mut TokenIter<'source>) -> Perhaps<Self> {
|
||||
Ok(if let Some(Token {
|
||||
value: Value::Key("bsp/n"|"bsp/s"|"bsp/e"|"bsp/w"|"bsp/a"|"bsp/b"),
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ impl<A, B> Either<A, B> {
|
|||
|
||||
#[cfg(feature = "dsl")]
|
||||
impl<'state, E: Output + 'state, T: ViewContext<'state, E>>
|
||||
FromDsl<'state, T> for When<RenderBox<'state, E>> {
|
||||
Dsl<T> for When<RenderBox<'state, E>> {
|
||||
fn take_from <'source: 'state> (state: &'state T, iter: &mut TokenIter<'source>) -> Perhaps<Self> {
|
||||
Ok(if let Some(Token {
|
||||
value: Value::Key("when"),
|
||||
|
|
@ -39,7 +39,7 @@ FromDsl<'state, T> for When<RenderBox<'state, E>> {
|
|||
|
||||
#[cfg(feature = "dsl")]
|
||||
impl<'state, E: Output + 'state, T: ViewContext<'state, E>>
|
||||
FromDsl<'state, T> for Either<RenderBox<'state, E>, RenderBox<'state, E>> {
|
||||
Dsl<T> for Either<RenderBox<'state, E>, RenderBox<'state, E>> {
|
||||
fn take_from <'source: 'state> (state: &'state T, iter: &mut TokenIter<'source>) -> Perhaps<Self> {
|
||||
if let Some(Token { value: Value::Key("either"), .. }) = iter.peek() {
|
||||
let base = iter.clone();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::*;
|
||||
use Direction::*;
|
||||
|
||||
pub struct Stack<E, F> {
|
||||
__: PhantomData<E>,
|
||||
|
|
@ -10,68 +11,76 @@ impl<E, F> Stack<E, F> {
|
|||
Self { direction, callback, __: Default::default(), }
|
||||
}
|
||||
pub fn north (callback: F) -> Self {
|
||||
Self::new(Direction::North, callback)
|
||||
Self::new(North, callback)
|
||||
}
|
||||
pub fn south (callback: F) -> Self {
|
||||
Self::new(Direction::South, callback)
|
||||
Self::new(South, callback)
|
||||
}
|
||||
pub fn east (callback: F) -> Self {
|
||||
Self::new(Direction::East, callback)
|
||||
Self::new(East, callback)
|
||||
}
|
||||
pub fn west (callback: F) -> Self {
|
||||
Self::new(Direction::West, callback)
|
||||
Self::new(West, callback)
|
||||
}
|
||||
}
|
||||
impl<E: Output, F: Fn(&mut dyn FnMut(&dyn Render<E>)->())->()> Content<E> for Stack<E, F> {
|
||||
fn layout (&self, mut to: E::Area) -> E::Area {
|
||||
let mut x = to.x();
|
||||
let mut y = to.y();
|
||||
let mut w = to.w();
|
||||
let mut h = to.h();
|
||||
let (mut w_used, mut w_remaining) = (E::Unit::zero(), to.w());
|
||||
let (mut h_used, mut h_remaining) = (E::Unit::zero(), to.h());
|
||||
(self.callback)(&mut move |component: &dyn Render<E>|{
|
||||
let layout = component.layout([x, y, w, h].into());
|
||||
let [_, _, w, h] = component.layout([x, y, w_remaining, h_remaining].into()).xywh();
|
||||
match self.direction {
|
||||
Direction::North => {
|
||||
todo!()
|
||||
South => {
|
||||
y = y.plus(h);
|
||||
h_used = h_used.plus(h);
|
||||
h_remaining = h_remaining.minus(h);
|
||||
w_used = w_used.max(w);
|
||||
},
|
||||
Direction::South => {
|
||||
y = y + layout.h();
|
||||
h = h.minus(layout.h());
|
||||
East => {
|
||||
x = x.plus(w);
|
||||
w_used = w_used.plus(w);
|
||||
w_remaining = w_remaining.minus(w);
|
||||
h_used = h_used.max(h);
|
||||
},
|
||||
Direction::East => {
|
||||
x = x + layout.w();
|
||||
w = w.minus(layout.w());
|
||||
},
|
||||
Direction::West => {
|
||||
North | West => {
|
||||
todo!()
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
});
|
||||
to
|
||||
match self.direction {
|
||||
North | West => {
|
||||
todo!()
|
||||
},
|
||||
South | East => {
|
||||
[to.x(), to.y(), w_used.into(), h_used.into()].into()
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
fn render (&self, to: &mut E) {
|
||||
let mut x = to.x();
|
||||
let mut y = to.y();
|
||||
let mut w = to.w();
|
||||
let mut h = to.h();
|
||||
let (mut w_used, mut w_remaining) = (E::Unit::zero(), to.w());
|
||||
let (mut h_used, mut h_remaining) = (E::Unit::zero(), to.h());
|
||||
(self.callback)(&mut move |component: &dyn Render<E>|{
|
||||
let layout = component.layout([x, y, w, h].into());
|
||||
let layout = component.layout([x, y, w_remaining, h_remaining].into());
|
||||
match self.direction {
|
||||
Direction::North => {
|
||||
todo!()
|
||||
},
|
||||
Direction::South => {
|
||||
y = y + layout.h();
|
||||
h = h.minus(layout.h());
|
||||
South => {
|
||||
y = y.plus(layout.h());
|
||||
h_remaining = h_remaining.minus(layout.h());
|
||||
h_used = h_used.plus(layout.h());
|
||||
to.place(layout, component);
|
||||
},
|
||||
Direction::East => {
|
||||
x = x + layout.w();
|
||||
w = w.minus(layout.w());
|
||||
East => {
|
||||
x = x.plus(layout.w());
|
||||
w_remaining = w_remaining.minus(layout.w());
|
||||
w_used = w_used.plus(layout.h());
|
||||
to.place(layout, component);
|
||||
},
|
||||
Direction::West => {
|
||||
North | West => {
|
||||
todo!()
|
||||
},
|
||||
_ => unreachable!()
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ macro_rules! transform_xy {
|
|||
}
|
||||
#[cfg(feature = "dsl")]
|
||||
impl<'state, E: Output + 'state, T: ViewContext<'state, E>>
|
||||
FromDsl<'state, T> for $Enum<RenderBox<'state, E>> {
|
||||
Dsl<T> for $Enum<RenderBox<'state, E>> {
|
||||
fn take_from <'source: 'state> (state: &'state T, iter: &mut TokenIter<'source>) -> Perhaps<Self> {
|
||||
if let Some(Token { value: Value::Key(k), .. }) = iter.peek() {
|
||||
let mut base = iter.clone();
|
||||
|
|
@ -85,7 +85,7 @@ macro_rules! transform_xy_unit {
|
|||
}
|
||||
#[cfg(feature = "dsl")]
|
||||
impl<'state, E: Output + 'state, T: ViewContext<'state, E>>
|
||||
FromDsl<'state, T> for $Enum<E::Unit, RenderBox<'state, E>> {
|
||||
Dsl<T> for $Enum<E::Unit, RenderBox<'state, E>> {
|
||||
fn take_from <'source: 'state> (state: &'state T, iter: &mut TokenIter<'source>) -> Perhaps<Self> {
|
||||
Ok(if let Some(Token { value: Value::Key($x|$y|$xy), .. }) = iter.peek() {
|
||||
let mut base = iter.clone();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::*;
|
|||
#[cfg(feature = "dsl")]
|
||||
#[macro_export] macro_rules! try_delegate {
|
||||
($s:ident, $dsl:expr, $T:ty) => {
|
||||
let value: Option<$T> = FromDsl::take_from($s, $dsl)?;
|
||||
let value: Option<$T> = Dsl::take_from($s, $dsl)?;
|
||||
if let Some(value) = value {
|
||||
return Ok(Some(value.boxed()))
|
||||
}
|
||||
|
|
@ -12,10 +12,10 @@ use crate::*;
|
|||
|
||||
// Provides components to the view.
|
||||
#[cfg(feature = "dsl")]
|
||||
pub trait ViewContext<'state, E: Output + 'state>: Send + Sync
|
||||
+ Dsl<bool>
|
||||
+ Dsl<usize>
|
||||
+ Dsl<E::Unit>
|
||||
pub trait ViewContext<'state, E: Output + 'state>: Send + Sync where
|
||||
bool: Dsl<Self>,
|
||||
usize: Dsl<Self>,
|
||||
E::Unit: Dsl<Self>,
|
||||
{
|
||||
fn get_content_or_fail <'source: 'state> (&'state self, iter: &mut TokenIter<'source>)
|
||||
-> Usually<RenderBox<'state, E>>
|
||||
|
|
|
|||
|
|
@ -64,12 +64,39 @@ impl ToTokens for ViewDef {
|
|||
}
|
||||
}
|
||||
/// Generated by [tengri_proc].
|
||||
impl<'state> ::tengri::dsl::FromDsl<'state, #view> for ::tengri::output::RenderBox<'state, #output> {
|
||||
impl<'state> ::tengri::dsl::FromDsl<'state, #view>
|
||||
for ::tengri::output::RenderBox<'state, #output> {
|
||||
fn take_from <'source: 'state> (
|
||||
state: &'state #view,
|
||||
token: &mut ::tengri::dsl::TokenIter<'source>
|
||||
) -> Perhaps<Self> {
|
||||
Ok(match token.peek() { #(#exposed)* _ => None })
|
||||
Ok(match token.peek() {
|
||||
Some(::tengri::dsl::Token {
|
||||
::tengri::dsl::value: Value::Exp(exp), ..
|
||||
}) => {
|
||||
let value: Option<$T> = FromDsl::take_from($s, $dsl)?;
|
||||
if let Some(value) = value {
|
||||
return Ok(Some(value.boxed()))
|
||||
}
|
||||
try_delegate!(self, iter, When::<RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Either::<RenderBox<'state, E>, RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Align::<RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Bsp::<RenderBox<'state, E>, RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Fill::<RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Fixed::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Min::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Max::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Shrink::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Expand::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Push::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Pull::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Margin::<_, RenderBox<'state, E>>);
|
||||
try_delegate!(self, iter, Padding::<_, RenderBox<'state, E>>);
|
||||
None
|
||||
},
|
||||
#(#exposed),*
|
||||
_ => None
|
||||
})
|
||||
}
|
||||
}
|
||||
} {
|
||||
|
|
@ -135,6 +162,5 @@ impl ToTokens for ViewArm {
|
|||
out.append(Group::new(Delimiter::Parenthesis, TokenStream2::new()));
|
||||
out
|
||||
}));
|
||||
out.append(Punct::new(',', Alone));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue