wip: refactor(output): pen and paper ftw

This commit is contained in:
same mf who else 2026-02-14 19:43:04 +02:00
parent 501782f8fe
commit eaa05b7f09
26 changed files with 1701 additions and 1697 deletions

View file

@ -11,88 +11,145 @@
//#![feature(non_lifetime_binders)]
pub(crate) use self::Direction::*;
pub(crate) use std::fmt::{Debug, Display};
pub(crate) use std::marker::PhantomData;
pub(crate) use std::ops::{Add, Sub, Mul, Div};
pub(crate) use std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::Relaxed}};
pub(crate) use std::marker::PhantomData;
pub(crate) use dizzle::*;
mod output; pub use self::output::*;
mod content; pub use self::content::*;
mod draw; pub use self::draw::*;
mod group; pub use self::group::*;
mod layout; pub use self::layout::*;
mod space; pub use self::space::*;
mod thunk; pub use self::thunk::*;
mod widget; pub use self::widget::*;
#[cfg(feature = "dsl")] mod view;
#[cfg(feature = "dsl")] pub use self::view::*;
#[cfg(test)] pub(crate) use proptest_derive::Arbitrary;
#[cfg(test)] mod test {
use crate::{*, Direction::*};
//use proptest_derive::Arbitrary;
use proptest::{prelude::*, option::of};
macro_rules! test_op_transform {
($fn:ident, $Op:ident) => {
proptest! {
#[test] fn $fn (
op_x in of(u16::MIN..u16::MAX),
op_y in of(u16::MIN..u16::MAX),
content in "\\PC*",
x in u16::MIN..u16::MAX,
y in u16::MIN..u16::MAX,
w in u16::MIN..u16::MAX,
h in u16::MIN..u16::MAX,
) {
if let Some(op) = match (op_x, op_y) {
(Some(x), Some(y)) => Some($Op::XY(x, y, content)),
(Some(x), None) => Some($Op::X(x, content)),
(None, Some(y)) => Some($Op::Y(y, content)),
_ => None
} {
//assert_eq!(Content::layout(&op, [x, y, w, h]),
//Draw::layout(&op, [x, y, w, h]));
}
}
mod out_macros; // Must be defined first
mod out_traits; pub use self::out_traits::*;
mod out_structs; pub use self::out_structs::*;
mod out_impls; pub use self::out_impls::*;
mod widget; pub use self::widget::*;
mod layout; pub use self::layout::*;
#[cfg(test)] mod out_tests;
#[cfg(feature = "dsl")]
pub fn evaluate_output_expression <'a, O: Out + 'a, S> (
state: &S, output: &mut O, expr: &'a impl Expression
) -> Usually<bool> where
S: View<O, ()>
+ for<'b>Namespace<'b, bool>
+ for<'b>Namespace<'b, O::Unit>
{
// First element of expression is used for dispatch.
// Dispatch is proto-namespaced using separator character
let head = expr.head()?;
let mut frags = head.src()?.unwrap_or_default().split("/");
// The rest of the tokens in the expr are arguments.
// Their meanings depend on the dispatched operation
let args = expr.tail();
let arg0 = args.head();
let tail0 = args.tail();
let arg1 = tail0.head();
let tail1 = tail0.tail();
let arg2 = tail1.head();
// And we also have to do the above binding dance
// so that the Perhaps<token>s remain in scope.
match frags.next() {
Some("when") => output.place(&When::new(
state.resolve(arg0?)?.unwrap(),
Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap())
)),
Some("either") => output.place(&Either::new(
state.resolve(arg0?)?.unwrap(),
Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap()),
Thunk::new(move|output: &mut O|state.view(output, &arg2).unwrap())
)),
Some("bsp") => output.place(&{
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
let b = Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap());
match frags.next() {
Some("n") => Bsp::n(a, b),
Some("s") => Bsp::s(a, b),
Some("e") => Bsp::e(a, b),
Some("w") => Bsp::w(a, b),
Some("a") => Bsp::a(a, b),
Some("b") => Bsp::b(a, b),
frag => unimplemented!("bsp/{frag:?}")
}
}
}
test_op_transform!(proptest_op_fixed, Fixed);
test_op_transform!(proptest_op_min, Min);
test_op_transform!(proptest_op_max, Max);
test_op_transform!(proptest_op_push, Push);
test_op_transform!(proptest_op_pull, Pull);
test_op_transform!(proptest_op_shrink, Shrink);
test_op_transform!(proptest_op_expand, Expand);
test_op_transform!(proptest_op_padding, Pad);
}),
proptest! {
#[test] fn proptest_op_bsp (
d in prop_oneof![
Just(North), Just(South),
Just(East), Just(West),
Just(Above), Just(Below)
],
a in "\\PC*",
b in "\\PC*",
x in u16::MIN..u16::MAX,
y in u16::MIN..u16::MAX,
w in u16::MIN..u16::MAX,
h in u16::MIN..u16::MAX,
) {
let bsp = Bsp(d, a, b);
//assert_eq!(
//Content::layout(&bsp, [x, y, w, h]),
//Draw::layout(&bsp, [x, y, w, h]),
//);
}
}
Some("align") => output.place(&{
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
match frags.next() {
Some("n") => Align::n(a),
Some("s") => Align::s(a),
Some("e") => Align::e(a),
Some("w") => Align::w(a),
Some("x") => Align::x(a),
Some("y") => Align::y(a),
Some("c") => Align::c(a),
frag => unimplemented!("align/{frag:?}")
}
}),
//#[test] fn test_iter_map () {
//struct Foo;
//impl<T: Out> Content<T> for Foo {}
//fn _make_map <T: Out, U: Content<T> + Send + Sync> (data: &Vec<U>) -> impl Draw<T> {
//Map::new(||data.iter(), |_foo, _index|{})
//}
//let _data = vec![Foo, Foo, Foo];
////let map = make_map(&data);
//}
Some("fill") => output.place(&{
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
match frags.next() {
Some("xy") | None => Fill::XY(a),
Some("x") => Fill::X(a),
Some("y") => Fill::Y(a),
frag => unimplemented!("fill/{frag:?}")
}
}),
Some("fixed") => output.place(&{
let axis = frags.next();
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
match axis {
Some("xy") | None => Fixed::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
Some("x") => Fixed::X(state.resolve(arg0?)?.unwrap(), cb),
Some("y") => Fixed::Y(state.resolve(arg0?)?.unwrap(), cb),
frag => unimplemented!("fixed/{frag:?} ({expr:?}) ({head:?}) ({:?})",
head.src()?.unwrap_or_default().split("/").next())
}
}),
Some("min") => output.place(&{
let axis = frags.next();
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
match axis {
Some("xy") | None => Min::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
Some("x") => Min::X(state.resolve(arg0?)?.unwrap(), cb),
Some("y") => Min::Y(state.resolve(arg0?)?.unwrap(), cb),
frag => unimplemented!("min/{frag:?}")
}
}),
Some("max") => output.place(&{
let axis = frags.next();
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
match axis {
Some("xy") | None => Max::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
Some("x") => Max::X(state.resolve(arg0?)?.unwrap(), cb),
Some("y") => Max::Y(state.resolve(arg0?)?.unwrap(), cb),
frag => unimplemented!("max/{frag:?}")
}
}),
Some("push") => output.place(&{
let axis = frags.next();
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
match axis {
Some("xy") | None => Push::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
Some("x") => Push::X(state.resolve(arg0?)?.unwrap(), cb),
Some("y") => Push::Y(state.resolve(arg0?)?.unwrap(), cb),
frag => unimplemented!("push/{frag:?}")
}
}),
_ => return Ok(false)
};
Ok(true)
}