tengri/output/src/ops/cond.rs

80 lines
2.7 KiB
Rust

use crate::*;
/// Show an item only when a condition is true.
pub struct When<A>(pub bool, pub A);
impl<A> When<A> {
/// Create a binary condition.
pub const fn new (c: bool, a: A) -> Self {
Self(c, a)
}
}
/// Show one item if a condition is true and another if the condition is false
pub struct Either<A, B>(pub bool, pub A, pub B);
impl<A, B> Either<A, B> {
/// Create a ternary condition.
pub const fn new (c: bool, a: A, b: B) -> Self {
Self(c, a, b)
}
}
#[cfg(feature = "dsl")]
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 content = iter.next().expect("no content specified").value;
return Some(Self(
state.get(&mut iter)
.expect("no condition provided"),
state.get_content(&content)
.unwrap_or_else(||panic!("no content corresponding to for {:?}", &content))
))
}
});
#[cfg(feature = "dsl")]
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 content = iter.next().expect("no content specified").value;
let alternate = iter.next().expect("no alternate specified").value;
return Some(Self(
state.get(&mut iter)
.expect("no condition provided"),
state.get_content(&content)
.unwrap_or_else(||panic!("no content 1 corresponding to {:?}", &content)),
state.get_content(&alternate)
.unwrap_or_else(||panic!("no content 2 corresponding to {:?}", &alternate)),
))
}
});
impl<E: Output, A: Render<E>> Content<E> for When<A> {
fn layout (&self, to: E::Area) -> E::Area {
let Self(cond, item) = self;
let mut area = E::Area::zero();
if *cond {
let item_area = item.layout(to);
area[0] = item_area.x();
area[1] = item_area.y();
area[2] = item_area.w();
area[3] = item_area.h();
}
area.into()
}
fn render (&self, to: &mut E) {
let Self(cond, item) = self;
if *cond { item.render(to) }
}
}
impl<E: Output, A: Render<E>, B: Render<E>> Content<E> for Either<A, B> {
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) }
}
}