⎇ a166049628f57f0e3c9851d4505a5e6d28627d00
src/tree/traits.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
fix description in traits.rs (#731)
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 index's into vec on parent node.
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, CoreStyle};
132#[cfg(feature = "flexbox")]
133use crate::style::{FlexboxContainerStyle, FlexboxItemStyle};
134#[cfg(feature = "grid")]
135use crate::style::{GridContainerStyle, GridItemStyle};
136#[cfg(feature = "block_layout")]
137use crate::{BlockContainerStyle, BlockItemStyle};
138use core::ops::{Deref, DerefMut};
139
140/// Taffy's abstraction for downward tree traversal.
141///
142/// 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`.
143pub trait TraversePartialTree {
144 /// Type representing an iterator of the children of a node
145 type ChildIter<'a>: Iterator<Item = NodeId>
146 where
147 Self: 'a;
148
149 /// Get the list of children IDs for the given node
150 fn child_ids(&self, parent_node_id: NodeId) -> Self::ChildIter<'_>;
151
152 /// Get the number of children for the given node
153 fn child_count(&self, parent_node_id: NodeId) -> usize;
154
155 /// Get a specific child of a node, where the index represents the nth child
156 fn get_child_id(&self, parent_node_id: NodeId, child_index: usize) -> NodeId;
157}
158
159/// A marker trait which extends `TraversePartialTree`
160///
161/// Implementing this trait implies the additional guarantee that the child/children methods can be used to recurse
162/// infinitely down the tree. Is required by the `RoundTree` and the `PrintTree` traits.
163pub trait TraverseTree: TraversePartialTree {}
164
165/// Any type that implements [`LayoutPartialTree`] can be laid out using [Taffy's algorithms](crate::compute)
166///
167/// 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
168/// node that only has access to it's immediate children.
169pub trait LayoutPartialTree: TraversePartialTree {
170 /// The style type representing the core container styles that all containers should have
171 /// Used when laying out the root node of a tree
172 type CoreContainerStyle<'a>: CoreStyle
173 where
174 Self: 'a;
175
176 /// A mutable reference to the cache. This is an associated type to allow for different
177 /// types of mutable reference such as mutex or refcell guards
178 type CacheMut<'b>: Deref<Target = Cache> + DerefMut
179 where
180 Self: 'b;
181
182 /// Get core style
183 fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_>;
184
185 /// Set the node's unrounded layout
186 fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout);
187
188 /// Get a mutable reference to the [`Cache`] for this node.
189 fn get_cache_mut(&mut self, node_id: NodeId) -> Self::CacheMut<'_>;
190
191 /// Compute the specified node's size or full layout given the specified constraints
192 fn compute_child_layout(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput;
193}
194
195/// Trait used by the `round_layout` method which takes a tree of unrounded float-valued layouts and performs
196/// rounding to snap the values to the pixel grid.
197///
198/// As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
199pub trait RoundTree: TraverseTree {
200 /// Get the node's unrounded layout
201 fn get_unrounded_layout(&self, node_id: NodeId) -> &Layout;
202 /// Get a reference to the node's final layout
203 fn set_final_layout(&mut self, node_id: NodeId, layout: &Layout);
204}
205
206/// Trait used by the `print_tree` method which prints a debug representation
207///
208/// As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
209pub trait PrintTree: TraverseTree {
210 /// Get a debug label for the node (typically the type of node: flexbox, grid, text, image, etc)
211 fn get_debug_label(&self, node_id: NodeId) -> &'static str;
212 /// Get a reference to the node's final layout
213 fn get_final_layout(&self, node_id: NodeId) -> &Layout;
214}
215
216#[cfg(feature = "flexbox")]
217/// Extends [`LayoutPartialTree`] with getters for the styles required for Flexbox layout
218pub trait LayoutFlexboxContainer: LayoutPartialTree {
219 /// The style type representing the Flexbox container's styles
220 type FlexboxContainerStyle<'a>: FlexboxContainerStyle
221 where
222 Self: 'a;
223 /// The style type representing each Flexbox item's styles
224 type FlexboxItemStyle<'a>: FlexboxItemStyle
225 where
226 Self: 'a;
227
228 /// Get the container's styles
229 fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_>;
230
231 /// Get the child's styles
232 fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_>;
233}
234
235#[cfg(feature = "grid")]
236/// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Grid layout
237pub trait LayoutGridContainer: LayoutPartialTree {
238 /// The style type representing the CSS Grid container's styles
239 type GridContainerStyle<'a>: GridContainerStyle
240 where
241 Self: 'a;
242
243 /// The style type representing each CSS Grid item's styles
244 type GridItemStyle<'a>: GridItemStyle
245 where
246 Self: 'a;
247
248 /// Get the container's styles
249 fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_>;
250
251 /// Get the child's styles
252 fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_>;
253}
254
255#[cfg(feature = "block_layout")]
256/// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Block layout
257pub trait LayoutBlockContainer: LayoutPartialTree {
258 /// The style type representing the CSS Block container's styles
259 type BlockContainerStyle<'a>: BlockContainerStyle
260 where
261 Self: 'a;
262 /// The style type representing each CSS Block item's styles
263 type BlockItemStyle<'a>: BlockItemStyle
264 where
265 Self: 'a;
266
267 /// Get the container's styles
268 fn get_block_container_style(&self, node_id: NodeId) -> Self::BlockContainerStyle<'_>;
269
270 /// Get the child's styles
271 fn get_block_child_style(&self, child_node_id: NodeId) -> Self::BlockItemStyle<'_>;
272}
273
274// --- PRIVATE TRAITS
275
276/// A private trait which allows us to add extra convenience methods to types which implement
277/// LayoutTree without making those methods public.
278pub(crate) trait LayoutPartialTreeExt: LayoutPartialTree {
279 /// Compute the size of the node given the specified constraints
280 #[inline(always)]
281 #[allow(clippy::too_many_arguments)]
282 fn measure_child_size(
283 &mut self,
284 node_id: NodeId,
285 known_dimensions: Size<Option<f32>>,
286 parent_size: Size<Option<f32>>,
287 available_space: Size<AvailableSpace>,
288 sizing_mode: SizingMode,
289 axis: AbsoluteAxis,
290 vertical_margins_are_collapsible: Line<bool>,
291 ) -> f32 {
292 self.compute_child_layout(
293 node_id,
294 LayoutInput {
295 known_dimensions,
296 parent_size,
297 available_space,
298 sizing_mode,
299 axis: axis.into(),
300 run_mode: RunMode::ComputeSize,
301 vertical_margins_are_collapsible,
302 },
303 )
304 .size
305 .get_abs(axis)
306 }
307
308 /// Perform a full layout on the node given the specified constraints
309 #[inline(always)]
310 fn perform_child_layout(
311 &mut self,
312 node_id: NodeId,
313 known_dimensions: Size<Option<f32>>,
314 parent_size: Size<Option<f32>>,
315 available_space: Size<AvailableSpace>,
316 sizing_mode: SizingMode,
317 vertical_margins_are_collapsible: Line<bool>,
318 ) -> LayoutOutput {
319 self.compute_child_layout(
320 node_id,
321 LayoutInput {
322 known_dimensions,
323 parent_size,
324 available_space,
325 sizing_mode,
326 axis: RequestedAxis::Both,
327 run_mode: RunMode::PerformLayout,
328 vertical_margins_are_collapsible,
329 },
330 )
331 }
332}
333
334impl<T: LayoutPartialTree> LayoutPartialTreeExt for T {}