Skip to content

Commit

Permalink
Add declarative way of making trees; add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Raunak Bhagat committed Sep 14, 2023
1 parent 9cd0878 commit 6e1ef2f
Show file tree
Hide file tree
Showing 4 changed files with 269 additions and 112 deletions.
111 changes: 111 additions & 0 deletions common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#[macro_export]
macro_rules! node {
($value:expr, [$($child:expr),*$(,)?]) => {{
use common::DeclarativeNode;

DeclarativeNode {
value: $value,
children: vec![$($child),*],
}
}};

($value:expr$(,)?) => {{
use common::DeclarativeNode;

DeclarativeNode {
value: $value,
children: vec![],
}
}};
}

use indexmap::IndexSet;
use stretchbox::{Constraint, ConstraintKey, Frame, Solver};

pub use node;

#[derive(Default, Debug, Clone, PartialEq, Eq)]
pub struct DeclarativeNode<V> {
pub value: V,
pub children: Vec<Self>,
}

pub fn make_solver(declarative_node: Option<&DeclarativeNode<Constraint>>) -> Option<Solver> {
fn insert_root_node(
mut solver: Solver,
declarative_node: &DeclarativeNode<Constraint>,
) -> Option<Solver> {
solver
.insert_root(declarative_node.value)
.map(|root_constraint_key| {
insert_nodes(solver, &declarative_node.children, root_constraint_key)
})
}

fn insert_nodes(
mut solver: Solver,
declarative_nodes: &Vec<DeclarativeNode<Constraint>>,
parent_constraint_key: ConstraintKey,
) -> Solver {
let mut to_visit_keys_and_nodes = vec![(parent_constraint_key, declarative_nodes)];

while let Some((parent_constraint_key, declarative_nodes)) = to_visit_keys_and_nodes.pop() {
for declarative_node in declarative_nodes {
let constraint_key = solver
.insert(declarative_node.value, parent_constraint_key)
.unwrap();
to_visit_keys_and_nodes.push((constraint_key, &declarative_node.children));
}
}

solver
}

declarative_node.map_or_else(
|| Some(Solver::default()),
|declarative_node| {
let solver = Solver::default();
insert_root_node(solver, declarative_node)
},
)
}

pub fn make_frame_tree(solver: &Solver) -> Option<DeclarativeNode<Frame>> {
fn get_frame(solver: &Solver, constraint_key: ConstraintKey) -> DeclarativeNode<Frame> {
let frame = solver.get_frame(constraint_key).unwrap();
let child_constraint_keys = solver.get(constraint_key).unwrap().child_keys;
let children = get_frames(solver, child_constraint_keys);

DeclarativeNode {
value: frame,
children,
}
}

fn get_frames(
solver: &Solver,
constraint_keys: &IndexSet<ConstraintKey>,
) -> Vec<DeclarativeNode<Frame>> {
let mut frames = vec![];

for &constraint_key in constraint_keys {
let frame = get_frame(solver, constraint_key);
frames.push(frame);
}

frames
}

solver
.root_constraint_key()
.and_then(|root_constraint_key| {
let is_dirty = solver.is_dirty();

if is_dirty {
None
} else {
let frame_tree = get_frame(solver, root_constraint_key);
Some(frame_tree)
}
})
}
36 changes: 17 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,22 @@ impl Solver {

// Insertion/removal methods:

pub fn insert_root(&mut self, constraint: Constraint) -> ConstraintKey {
pub fn insert_root(&mut self, constraint: Constraint) -> Option<ConstraintKey> {
self.insert_root_with_capacity(constraint, 0)
}

pub fn insert_root_with_capacity(
&mut self,
constraint: Constraint,
capacity: usize,
) -> ConstraintKey {
let root_key = self
.constraint_tree
.insert_root_with_capacity(constraint, capacity);
self.is_dirty = true;
root_key
) -> Option<ConstraintKey> {
matches!(constraint.fill_x, Fill::Scale(..)).then(|| {
let root_key = self
.constraint_tree
.insert_root_with_capacity(constraint, capacity);
self.is_dirty = true;
root_key
})
}

pub fn insert(
Expand Down Expand Up @@ -155,31 +157,27 @@ impl Solver {

// Solve method:

pub fn solve(&mut self, length_x: f64) -> bool {
pub fn solve(&mut self, length_x: f64) {
let is_dirty = self.is_dirty;
let is_empty = self.constraint_tree.is_empty();

match (is_dirty, is_empty) {
(true, true) => {
self.is_dirty = false;
true
}
(true, true) => self.is_dirty = false,

(true, false) => {
let length_x = length_x.max(0.);
let did_solve = solve(

solve(
&self.constraint_tree,
&mut self.frame_tree,
&mut self.key_map,
length_x,
);
if did_solve {
self.is_dirty = false;
};
did_solve

self.is_dirty = false;
}

(false, _) => true,
(false, _) => (),
}
}
}
Expand Down Expand Up @@ -208,7 +206,7 @@ pub struct Padding {
pub right: f64,
}

#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct Frame {
pub offset_x: f64,
pub length_x: f64,
Expand Down
7 changes: 3 additions & 4 deletions src/solver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ pub(super) fn solve(
frame_tree: &mut Tree<FrameKey, Frame>,
key_map: &mut BTreeMap<ConstraintKey, FrameKey>,
length_x: f64,
) -> bool {
) {
let (root_constraint_key, root_constraint_node) = constraint_tree.root_key_value().unwrap();

match root_constraint_node.value.fill_x {
Fill::Exact(..) | Fill::Minimize => false,
Fill::Scale(scale) => {
let length_x = match scale {
0 => 0.,
Expand All @@ -43,9 +42,9 @@ pub(super) fn solve(
root_frame_key,
root_content_frame,
);

true
}

Fill::Exact(..) | Fill::Minimize => unreachable!(),
}
}

Expand Down
Loading

0 comments on commit 6e1ef2f

Please sign in to comment.