Skip to content

Commit

Permalink
organizing
Browse files Browse the repository at this point in the history
  • Loading branch information
cyypherus committed Oct 16, 2024
1 parent cc3194c commit 0b2a9a6
Show file tree
Hide file tree
Showing 5 changed files with 287 additions and 0 deletions.
191 changes: 191 additions & 0 deletions src/tests/scope_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
#[cfg(test)]
mod tests {
use crate::layout::*;
use crate::models::*;
use crate::nodes::*;
use crate::traits::Scopable;
use crate::traits::ScopableOption;
use crate::Node;
use crate::NodeWith;
#[test]
fn test_scope() {
struct A {
test: bool,
b: B,
}
struct B {
test: bool,
}
let mut a = A {
test: true,
b: B { test: true },
};
impl Scopable<B> for A {
fn scope<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(&mut B) -> Result,
{
f(&mut self.b)
}
}
fn layout(a: &mut A) -> NodeWith<A, ()> {
stack(vec![
if a.test {
draw(|area, a: &mut A| {
assert_eq!(area, Area::new(0., 0., 100., 100.));
a.test = false;
})
} else {
draw(|area, a: &mut A| {
assert_eq!(area, Area::new(0., 0., 100., 100.));
a.test = true;
})
},
scope(|b: &mut B| {
if b.test {
draw(|area, b: &mut B| {
assert_eq!(area, Area::new(0., 0., 100., 100.));
b.test = false;
})
} else {
draw(|area, b: &mut B| {
assert_eq!(area, Area::new(0., 0., 100., 100.));
b.test = true;
})
}
}),
])
}
Layout::new(layout).draw(Area::new(0., 0., 100., 100.), &mut a);
assert!(!a.test);
assert!(!a.b.test);
Layout::new(layout).draw(Area::new(0., 0., 100., 100.), &mut a);
assert!(a.test);
assert!(a.b.test);
}
#[test]
fn test_partial_scope_variadic() {
struct A;
struct C;
struct B {
c: C,
}

impl Scopable<A> for A {
fn scope<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(&mut A) -> Result,
{
f(self)
}
}

impl Scopable<C> for B {
fn scope<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(&mut C) -> Result,
{
f(&mut self.c)
}
}

fn layout(_: &mut A, _: &mut B) -> NodeWith<A, B> {
stack(vec![
draw_with(|area, _, _| {
assert_eq!(area, Area::new(0., 0., 100., 100.));
}),
scope_with(|_, _| {
draw_with(|area, _a: &mut A, _c: &mut C| {
assert_eq!(area, Area::new(0., 0., 100., 100.));
})
}),
])
}
Layout::new_with(layout).draw_with(Area::new(0., 0., 100., 100.), &mut A, &mut B { c: C });
}
#[test]
fn test_multiple_scope_paths() {
struct C;
struct B;
struct A {
b: B,
c: C,
}
fn layout(a: &mut A) -> Node<A> {
stack(vec![path_b(a), path_c(a)])
}
fn path_b(_: &mut A) -> Node<A> {
impl Scopable<B> for A {
fn scope<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(&mut B) -> Result,
{
f(&mut self.b)
}
}
stack(vec![scope(|_b: &mut B| space())])
}
fn path_c(_: &mut A) -> Node<A> {
impl Scopable<C> for A {
fn scope<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(&mut C) -> Result,
{
f(&mut self.c)
}
}
stack(vec![scope(|_c: &mut C| space())])
}
Layout::new(layout).draw(Area::new(0., 0., 100., 100.), &mut A { b: B, c: C });
}
#[test]
fn test_scope_unwrap() {
struct B;
struct A {
b: Option<B>,
}
impl ScopableOption<B> for A {
fn scope_option<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(Option<&mut B>) -> Result,
{
f(self.b.as_mut())
}
}
fn layout(_a: &mut A) -> Node<A> {
stack(vec![scope(|_b: &mut B| space())])
}
Layout::new(layout).draw(Area::new(0., 0., 100., 100.), &mut A { b: Some(B) });
}
#[test]
fn test_scope_unwrap_ctx() {
struct B;
struct A {
b: Option<B>,
}
impl ScopableOption<B> for A {
fn scope_option<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(Option<&mut B>) -> Result,
{
f(self.b.as_mut())
}
}
impl Scopable<B> for B {
fn scope<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(&mut B) -> Result,
{
f(self)
}
}
fn layout(_b: &mut B, _a: &mut A) -> NodeWith<B, A> {
stack(vec![scope_with(|_b: &mut B, _b_1: &mut B| space())])
}
Layout::new_with(layout).draw_with(
Area::new(0., 0., 100., 100.),
&mut B,
&mut A { b: Some(B) },
);
}
}
7 changes: 7 additions & 0 deletions src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod nodetrait;
mod scopable;
mod scopable_option;

pub(crate) use nodetrait::NodeTrait;
pub use scopable::Scopable;
pub use scopable_option::ScopableOption;
8 changes: 8 additions & 0 deletions src/traits/nodetrait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use crate::{constraints::SizeConstraints, models::Area};
use std::fmt::Debug;

pub(crate) trait NodeTrait<State, Ctx>: Debug {
fn draw(&mut self, state: &mut State, ctx: &mut Ctx);
fn layout(&mut self, available_area: Area, state: &mut State, ctx: &mut Ctx);
fn constraints(&mut self, area: Area, state: &mut State, ctx: &mut Ctx) -> SizeConstraints;
}
40 changes: 40 additions & 0 deletions src/traits/scopable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/// Implement `Scopable` to enable usage with [`Node::scope`]
pub trait Scopable<Scoped> {
/// Provide a scoped mutable reference to a subset of your state.
///
/// This method is called by backer for various purposes,
/// passing different closures for `f` & using the result returned by `Scopable::scope`.
///
/// ```rust
///
/// use backer::traits::Scopable;
///
/// struct A {
/// b: B,
/// }
///
/// struct B;
///
/// impl Scopable<B> for A {
/// fn scope<F, Result>(&mut self, f: F) -> Result
/// where
/// F: FnOnce(&mut B) -> Result,
/// {
/// let scoped = &mut self.b;
/// f(scoped)
/// }
/// }
/// ```
fn scope<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(&mut Scoped) -> Result;
}

impl Scopable<()> for () {
fn scope<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(&mut ()) -> Result,
{
f(self)
}
}
41 changes: 41 additions & 0 deletions src/traits/scopable_option.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use super::Scopable;

/// Implement `ScopableOption` to enable usage with [`Node::scope`] for optional state.
/// For non-optional state, implement [`Scopable`].
pub trait ScopableOption<Scoped> {
/// Provide a scoped mutable reference to an optional subset of your state.
///
/// ```rust
/// use backer::traits::ScopableOption;
///
/// struct A {
/// b: Option<B>,
/// }
///
/// struct B;
///
/// impl ScopableOption<B> for A {
/// fn scope_option<F, Result>(&mut self, f: F) -> Result
/// where
/// F: FnOnce(Option<&mut B>) -> Result,
/// {
/// f(self.b.as_mut())
/// }
/// }
/// ```
fn scope_option<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(Option<&mut Scoped>) -> Result;
}

impl<T, Scoped> ScopableOption<Scoped> for T
where
T: Scopable<Scoped>,
{
fn scope_option<F, Result>(&mut self, f: F) -> Result
where
F: FnOnce(Option<&mut Scoped>) -> Result,
{
self.scope(|s| f(Some(s)))
}
}

0 comments on commit 0b2a9a6

Please sign in to comment.