diff --git a/Cargo.toml b/Cargo.toml
index abdddc80e..31c31b1f6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,6 +17,7 @@ maintenance = { status = "experimental" }
[dependencies]
libm = "0.1.2"
+lazy_static = "0.1"
[features]
default = ["std"]
diff --git a/src/id.rs b/src/id.rs
new file mode 100644
index 000000000..ce8cb3e03
--- /dev/null
+++ b/src/id.rs
@@ -0,0 +1,36 @@
+//! Identifier for a Node
+//!
+//!
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub(crate) struct Id {
+ id: u32,
+ generation: u32,
+}
+
+pub(crate) struct Allocator {
+ new_id: u32,
+ free_ids: Vec<Id>,
+}
+
+impl Allocator {
+ pub fn new() -> Self {
+ Allocator { new_id: 0, free_ids: Vec::new() }
+ }
+
+ pub fn allocate(&mut self) -> Id {
+ // TODO: better balancing
+ match self.free_ids.pop() {
+ Some(id) => Id { id: id.id, generation: id.generation + 1 },
+ None => {
+ let id = self.new_id;
+ self.new_id += 1;
+ Id { id, generation: 0 }
+ }
+ }
+ }
+
+ pub fn free(&mut self, ids: &[Id]) {
+ self.free_ids.extend(ids);
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 95b432e92..b9705ac80 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,6 +3,9 @@
#[cfg(not(feature = "std"))]
extern crate alloc;
+#[macro_use]
+extern crate lazy_static;
+
pub mod geometry;
pub mod node;
pub mod number;
@@ -10,5 +13,6 @@ pub mod result;
pub mod style;
mod algo;
+mod id;
pub use crate::node::Stretch;
diff --git a/src/node.rs b/src/node.rs
index 3e85f761f..66c5e7967 100644
--- a/src/node.rs
+++ b/src/node.rs
@@ -2,43 +2,33 @@
use alloc::{vec, vec::Vec};
use std::collections::HashMap;
+use std::ops::Drop;
+use std::sync::Mutex;
use crate::geometry::Size;
+use crate::id;
use crate::number::Number;
use crate::result::{Cache, Layout, Result};
use crate::style::*;
type MeasureFunc = Box<Fn(Size<Number>) -> Result<Size<f32>>>;
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub struct Node(usize);
-
-pub(crate) type Storage<T> = HashMap<Node, T>;
-
-struct Allocator {
- new_id: usize,
- free_ids: Vec<usize>,
+lazy_static! {
+ /// Global stretch instance id allocator.
+ static ref INSTANCE_ALLOCATOR: Mutex<id::Allocator> = Mutex::new(id::Allocator::new());
}
-impl Allocator {
- pub fn new() -> Self {
- Allocator { new_id: 0, free_ids: Vec::new() }
- }
-
- pub fn allocate(&mut self) -> Node {
- match self.free_ids.pop() {
- Some(id) => Node(id),
- None => {
- let id = self.new_id;
- self.new_id += 1;
- Node(id)
- }
- }
- }
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct Node {
+ instance: id::Id,
+ local: id::Id,
}
+pub(crate) type Storage<T> = HashMap<Node, T>;
+
pub struct Stretch {
- nodes: Allocator,
+ id: id::Id,
+ nodes: id::Allocator,
pub(crate) style: Storage<Style>,
pub(crate) parents: Storage<Vec<Node>>,
pub(crate) children: Storage<Vec<Node>>,
@@ -51,7 +41,8 @@ pub struct Stretch {
impl Stretch {
pub fn new() -> Self {
Stretch {
- nodes: Allocator::new(),
+ id: INSTANCE_ALLOCATOR.lock().unwrap().allocate(),
+ nodes: id::Allocator::new(),
style: Storage::new(),
parents: Storage::new(),
children: Storage::new(),
@@ -62,20 +53,27 @@ impl Stretch {
}
}
+ fn allocate_node(&mut self) -> Node {
+ let local = self.nodes.allocate();
+ Node { instance: self.id, local }
+ }
+
pub fn new_leaf(&mut self, style: Style, measure: MeasureFunc) -> Node {
- // Node(Rc::new(RefCell::new(InternalNode {
- // style,
- // parents: Vec::with_capacity(1),
- // children: Vec::with_capacity(0),
- // measure: Some(measure),
- // layout_cache: None,
- // is_dirty: true,
- // })))
- unimplemented!()
+ let node = self.allocate_node();
+
+ self.style.insert(node, style);
+ self.parents.insert(node, Vec::with_capacity(1));
+ self.children.insert(node, Vec::with_capacity(0));
+ self.measure.insert(node, Some(measure));
+ self.layout.insert(node, Layout::new());
+ self.layout_cache.insert(node, None);
+ self.is_dirty.insert(node, true);
+
+ node
}
pub fn new_node(&mut self, style: Style, children: Vec<Node>) -> Node {
- let node = self.nodes.allocate();
+ let node = self.allocate_node();
for child in &children {
self.parents.get_mut(&child).unwrap().push(node);
@@ -93,10 +91,8 @@ impl Stretch {
}
pub fn set_measure(&mut self, node: Node, measure: Option<MeasureFunc>) {
- // self.0.borrow_mut().measure = measure;
- // self.mark_dirty();
-
- unimplemented!()
+ *self.measure[&node].unwrap() = measure;
+ self.mark_dirty(node);
}
pub fn add_child(&mut self, node: Node, child: Node) {
@@ -167,17 +163,11 @@ impl Stretch {
}
pub fn children(&self, node: Node) -> Vec<Node> {
- // let node = self.0.borrow_mut();
- // node.children.iter().map(|child| Node(Rc::clone(child))).collect()
-
- unimplemented!()
+ self.children[&node].clone()
}
pub fn child_count(&self, node: Node) -> usize {
- // let node = self.0.borrow_mut();
- // node.children.len()
-
- unimplemented!()
+ self.children[&node].len()
}
pub fn set_style(&mut self, node: Node, style: Style) {
@@ -187,10 +177,8 @@ impl Stretch {
unimplemented!()
}
- pub fn style(&self, node: Node) -> Style {
- // self.0.borrow().style
-
- unimplemented!()
+ pub fn style(&self, node: Node) -> &Style {
+ &self.style[&node]
}
pub fn layout(&self, node: Node) -> &Layout {
@@ -212,12 +200,16 @@ impl Stretch {
}
pub fn dirty(&self, node: Node) -> bool {
- // self.0.borrow().is_dirty
-
- unimplemented!()
+ self.is_dirty[&node]
}
pub fn compute_layout(&mut self, node: Node, size: Size<Number>) -> Result<()> {
self.compute(node, size)
}
}
+
+impl Drop for Stretch {
+ fn drop(&mut self) {
+ INSTANCE_ALLOCATOR.lock().unwrap().free(&[self.id]);
+ }
+}