tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 501HTML 254C 19JavaScript 81414 Definitions

⎇ dde8c6aa4a2faa6faea600e24ecf2ce67923c37e src/tree/traits.rs Rust · 254 lines · 12.9 KB History Who touched what raw

Rayon WIP dde8c6aa4 · Nico Burns ·

1//! The abstractions that make up the core of Taffy's low-level API
2//!
3//! ## Examples
4//!
5//! The following examples demonstrate end-to-end implementation of Taffy's traits and usage of the low-level compute APIs:
6//!
7//!   - [custom_tree_vec](https://github.com/DioxusLabs/taffy/blob/main/examples/custom_tree_vec.rs) which implements a custom Taffy tree using a `Vec` as an arena with NodeId's being index's into the Vec.
8//!   - [custom_tree_owned_partial](https://github.com/DioxusLabs/taffy/blob/main/examples/custom_tree_owned_partial.rs) which implements a custom Taffy tree using directly owned children with NodeId's being pointers.
9//!   - [custom_tree_owned_unsafe](https://github.com/DioxusLabs/taffy/blob/main/examples/custom_tree_owned_unsafe.rs) which implements a custom Taffy tree using directly owned children with NodeId's being pointers.
10//!
11//! ## Overview
12//!
13//! ### Trait dependency tree
14//!
15//! The tree below illustrates which traits depend on which other traits.
16//!
17//! ```text
18//! TraversePartialTree     - Access a node's children
19//! ├──  LayoutPartialTree  - Run layout algorithms on a node and it's direct children
20//! └──  TraverseTree       - Recursively access a node's descendants
21//!     ├──  RoundTree      - Round a float-valued`  layout to integer pixels
22//!     └──  PrintTree      - Print a debug representation of a node tree
23//! ```
24//!
25//! ### A table of traits
26//!
27//! | Trait                 | Requires                | Enables                                                                                                                                                                                                                                                                                                                                                                                                                   |
28//! | ---                   | ---                     | ---                                                                                                                                                                                                                                                                                                                                                                                                                       |
29//! | [`LayoutPartialTree`] | [`TraversePartialTree`] | [`compute_flexbox_layout`](crate::compute_flexbox_layout)<br />[`compute_grid_layout`](crate::compute_grid_layout)<br />[`compute_block_layout`](crate::compute_block_layout)<br />[`compute_root_layout`](crate::compute_root_layout)<br />[`compute_leaf_layout`](crate::compute_leaf_layout)<br />[`compute_hidden_layout`](crate::compute_hidden_layout)<br />[`compute_cached_layout`](crate::compute_cached_layout) |
30//! | [`RoundTree`]         | [`TraverseTree`]        | [`round_layout`](crate::round_layout)                                                                                                                                                                                                                                                                                                                                                                                     |
31//! | [`PrintTree`]         | [`TraverseTree`]        | [`print_tree`](crate::print_tree)                                                                                                                                                                                                                                                                                                                                                                                         |
32//!
33//! ## All of the traits on one page
34//!
35//! ### TraversePartialTree and TraverseTree
36//! These traits are Taffy's abstraction for downward tree traversal:
37//!  - [`TraversePartialTree`] allows access to a single container node, and it's immediate children. This is the only "traverse" trait that is required
38//!     for use of Taffy's core layout algorithms (flexbox, grid, etc).
39//!  - [`TraverseTree`] is a marker trait which uses the same API signature as `TraversePartialTree`, but extends it with a guarantee that the child/children methods can be used to recurse
40//!     infinitely down the tree. It is required by the `RoundTree` and
41//!     the `PrintTree` traits.
42//! ```rust
43//! # use taffy::*;
44//! pub trait TraversePartialTree {
45//!     /// Type representing an iterator of the children of a node
46//!     type ChildIter<'a>: Iterator<Item = NodeId>
47//!     where
48//!         Self: 'a;
49//!
50//!     /// Get the list of children IDs for the given node
51//!     fn child_ids(&self, parent_node_id: NodeId) -> Self::ChildIter<'_>;
52//!
53//!     /// Get the number of children for the given node
54//!     fn child_count(&self, parent_node_id: NodeId) -> usize;
55//!
56//!     /// Get a specific child of a node, where the index represents the nth child
57//!     fn get_child_id(&self, parent_node_id: NodeId, child_index: usize) -> NodeId;
58//! }
59//!
60//! pub trait TraverseTree: TraversePartialTree {}
61//! ```
62//!
63//! You must implement [`TraversePartialTree`] to access any of Taffy's low-level API. If your tree implementation allows you to implement [`TraverseTree`] with
64//! the correct semantics (full recursive traversal is available) then you should.
65//!
66//! ### LayoutPartialTree
67//!
68//! **Requires:** `TraversePartialTree`<br />
69//! **Enables:** Flexbox, Grid, Block and Leaf layout algorithms from the [`crate::compute`] module
70//!
71//! Any type that implements [`LayoutPartialTree`] can be laid out using [Taffy's algorithms](crate::compute)
72//!
73//! Note that this trait extends [`TraversePartialTree`] (not [`TraverseTree`]). Taffy's algorithm implementations have been designed such that they can be used for a laying out a single
74//! node that only has access to it's immediate children.
75//!
76//! ```rust
77//! # use taffy::*;
78//! pub trait LayoutPartialTree: TraversePartialTree {
79//!     /// Get a reference to the [`Style`] for this node.
80//!     fn get_style(&self, node_id: NodeId) -> &Style;
81//!
82//!     /// Set the node's unrounded layout
83//!     fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout);
84//!
85//!     /// Get a mutable reference to the [`Cache`] for this node.
86//!     fn get_cache_mut(&mut self, node_id: NodeId) -> &mut Cache;
87//!
88//!     /// Compute the specified node's size or full layout given the specified constraints
89//!     fn compute_child_layout(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput;
90//! }
91//! ```
92//!
93//! ### RoundTree
94//!
95//! **Requires:** `TraverseTree`
96//!
97//! Trait used by the `round_layout` method which takes a tree of unrounded float-valued layouts and performs
98//! rounding to snap the values to the pixel grid.
99//!
100//! As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
101//!
102//! ```rust
103//! # use taffy::*;
104//! pub trait RoundTree: TraverseTree {
105//!     /// Get the node's unrounded layout
106//!     fn get_unrounded_layout(&self, node_id: NodeId) -> &Layout;
107//!     /// Get a reference to the node's final layout
108//!     fn set_final_layout(&mut self, node_id: NodeId, layout: &Layout);
109//! }
110//! ```
111//!
112//! ### PrintTree
113//!
114//! **Requires:** `TraverseTree`
115//!
116//! ```rust
117//! /// Trait used by the `print_tree` method which prints a debug representation
118//! ///
119//! /// As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
120//! # use taffy::*;
121//! pub trait PrintTree: TraverseTree {
122//!     /// Get a debug label for the node (typically the type of node: flexbox, grid, text, image, etc)
123//!     fn get_debug_label(&self, node_id: NodeId) -> &'static str;
124//!     /// Get a reference to the node's final layout
125//!     fn get_final_layout(&self, node_id: NodeId) -> &Layout;
126//! }
127//! ```
128//!
129use super::{Cache, Layout, LayoutInput, LayoutOutput, NodeId, RequestedAxis, RunMode, SizingMode};
130use crate::geometry::{AbsoluteAxis, Line, Size};
131use crate::style::{AvailableSpace, Style};
132
133/// This trait is Taffy's abstraction for downward tree traversal.
134/// However, this trait does *not* require access to any node's other than a single container node's immediate children unless you also intend to implement `TraverseTree`.
135pub trait TraversePartialTree {
136    /// Type representing an iterator of the children of a node
137    type ChildIter<'a>: Iterator<Item = NodeId>
138    where
139        Self: 'a;
140
141    /// Get the list of children IDs for the given node
142    fn child_ids(&self, parent_node_id: NodeId) -> Self::ChildIter<'_>;
143
144    /// Get the number of children for the given node
145    fn child_count(&self, parent_node_id: NodeId) -> usize;
146
147    /// Get a specific child of a node, where the index represents the nth child
148    fn get_child_id(&self, parent_node_id: NodeId, child_index: usize) -> NodeId;
149}
150
151/// A marker trait which extends `TraversePartialTree` with the additional guarantee that the child/children methods can be used to recurse
152/// infinitely down the tree. Is required by the `RoundTree` and the `PrintTree` traits.
153pub trait TraverseTree: TraversePartialTree {}
154
155/// Any type that implements [`LayoutPartialTree`] can be laid out using [Taffy's algorithms](crate::compute)
156///
157/// Note that this trait extends [`TraversePartialTree`] (not [`TraverseTree`]). Taffy's algorithm implementations have been designed such that they can be used for a laying out a single
158/// node that only has access to it's immediate children.
159pub trait LayoutPartialTree: TraversePartialTree + Send + Sync {
160    /// Get a reference to the [`Style`] for this node.
161    fn get_style(&self, node_id: NodeId) -> &Style;
162
163    /// Set the node's unrounded layout
164    fn set_unrounded_layout(&self, node_id: NodeId, layout: &Layout);
165
166    /// Get a mutable reference to the [`Cache`] for this node.
167    fn get_cache_mut(&self, node_id: NodeId) -> &mut Cache;
168
169    /// Compute the specified node's size or full layout given the specified constraints
170    fn compute_child_layout(&self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput;
171}
172
173/// Trait used by the `round_layout` method which takes a tree of unrounded float-valued layouts and performs
174/// rounding to snap the values to the pixel grid.
175///
176/// As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
177pub trait RoundTree: TraverseTree {
178    /// Get the node's unrounded layout
179    fn get_unrounded_layout(&self, node_id: NodeId) -> &Layout;
180    /// Get a reference to the node's final layout
181    fn set_final_layout(&mut self, node_id: NodeId, layout: &Layout);
182}
183
184/// Trait used by the `print_tree` method which prints a debug representation
185///
186/// As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
187pub trait PrintTree: TraverseTree {
188    /// Get a debug label for the node (typically the type of node: flexbox, grid, text, image, etc)
189    fn get_debug_label(&self, node_id: NodeId) -> &'static str;
190    /// Get a reference to the node's final layout
191    fn get_final_layout(&self, node_id: NodeId) -> &Layout;
192}
193
194// --- PRIVATE TRAITS
195
196/// A private trait which allows us to add extra convenience methods to types which implement
197/// LayoutTree without making those methods public.
198pub(crate) trait LayoutPartialTreeExt: LayoutPartialTree {
199    /// Compute the size of the node given the specified constraints
200    #[inline(always)]
201    #[allow(clippy::too_many_arguments)]
202    fn measure_child_size(
203        &self,
204        node_id: NodeId,
205        known_dimensions: Size<Option<f32>>,
206        parent_size: Size<Option<f32>>,
207        available_space: Size<AvailableSpace>,
208        sizing_mode: SizingMode,
209        axis: AbsoluteAxis,
210        vertical_margins_are_collapsible: Line<bool>,
211    ) -> f32 {
212        self.compute_child_layout(
213            node_id,
214            LayoutInput {
215                known_dimensions,
216                parent_size,
217                available_space,
218                sizing_mode,
219                axis: axis.into(),
220                run_mode: RunMode::ComputeSize,
221                vertical_margins_are_collapsible,
222            },
223        )
224        .size
225        .get_abs(axis)
226    }
227
228    /// Perform a full layout on the node given the specified constraints
229    #[inline(always)]
230    fn perform_child_layout(
231        &self,
232        node_id: NodeId,
233        known_dimensions: Size<Option<f32>>,
234        parent_size: Size<Option<f32>>,
235        available_space: Size<AvailableSpace>,
236        sizing_mode: SizingMode,
237        vertical_margins_are_collapsible: Line<bool>,
238    ) -> LayoutOutput {
239        self.compute_child_layout(
240            node_id,
241            LayoutInput {
242                known_dimensions,
243                parent_size,
244                available_space,
245                sizing_mode,
246                axis: RequestedAxis::Both,
247                run_mode: RunMode::PerformLayout,
248                vertical_margins_are_collapsible,
249            },
250        )
251    }
252}
253
254impl<T: LayoutPartialTree> LayoutPartialTreeExt for T {}