taffy/tree/
traits.rs

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::{Layout, LayoutInput, LayoutOutput, NodeId, RequestedAxis, RunMode, SizingMode};
130#[cfg(feature = "detailed_layout_info")]
131use crate::debug::debug_log;
132use crate::geometry::{AbsoluteAxis, Line, Size};
133use crate::style::{AvailableSpace, CoreStyle};
134#[cfg(feature = "flexbox")]
135use crate::style::{FlexboxContainerStyle, FlexboxItemStyle};
136#[cfg(feature = "grid")]
137use crate::style::{GridContainerStyle, GridItemStyle};
138use crate::CheapCloneStr;
139#[cfg(feature = "block_layout")]
140use crate::{BlockContainerStyle, BlockContext, BlockItemStyle};
141
142#[cfg(all(feature = "grid", feature = "detailed_layout_info"))]
143use crate::compute::grid::DetailedGridInfo;
144
145/// Taffy's abstraction for downward tree traversal.
146///
147/// 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`.
148pub trait TraversePartialTree {
149    /// Type representing an iterator of the children of a node
150    type ChildIter<'a>: Iterator<Item = NodeId>
151    where
152        Self: 'a;
153
154    /// Get the list of children IDs for the given node
155    fn child_ids(&self, parent_node_id: NodeId) -> Self::ChildIter<'_>;
156
157    /// Get the number of children for the given node
158    fn child_count(&self, parent_node_id: NodeId) -> usize;
159
160    /// Get a specific child of a node, where the index represents the nth child
161    fn get_child_id(&self, parent_node_id: NodeId, child_index: usize) -> NodeId;
162}
163
164/// A marker trait which extends `TraversePartialTree`
165///
166/// Implementing this trait implies the additional guarantee that the child/children methods can be used to recurse
167/// infinitely down the tree. Is required by the `RoundTree` and the `PrintTree` traits.
168pub trait TraverseTree: TraversePartialTree {}
169
170/// Any type that implements [`LayoutPartialTree`] can be laid out using [Taffy's algorithms](crate::compute)
171///
172/// 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
173/// node that only has access to it's immediate children.
174pub trait LayoutPartialTree: TraversePartialTree {
175    /// The style type representing the core container styles that all containers should have
176    /// Used when laying out the root node of a tree
177    type CoreContainerStyle<'a>: CoreStyle<CustomIdent = Self::CustomIdent>
178    where
179        Self: 'a;
180
181    /// String type for representing "custom identifiers" (for example, named grid lines or areas)
182    /// If you are unsure what to use here then consider `Arc<str>`.
183    type CustomIdent: CheapCloneStr;
184
185    /// Get core style
186    fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_>;
187
188    /// Resolve calc value
189    #[inline(always)]
190    fn resolve_calc_value(&self, val: *const (), basis: f32) -> f32 {
191        let _ = val;
192        let _ = basis;
193        0.0
194    }
195
196    /// Set the node's unrounded layout
197    fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout);
198
199    /// Compute the specified node's size or full layout given the specified constraints
200    fn compute_child_layout(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput;
201}
202
203/// Trait used by the `compute_cached_layout` method which allows cached layout results to be stored and retrieved.
204///
205/// The `Cache` struct implements a per-node cache that is compatible with this trait.
206pub trait CacheTree {
207    /// Try to retrieve a cached result from the cache
208    fn cache_get(&self, node_id: NodeId, input: &LayoutInput) -> Option<LayoutOutput>;
209
210    /// Store a computed size in the cache
211    fn cache_store(&mut self, node_id: NodeId, input: &LayoutInput, layout_output: LayoutOutput);
212
213    /// Clear all cache entries for the node
214    fn cache_clear(&mut self, node_id: NodeId);
215}
216
217/// Trait used by the `round_layout` method which takes a tree of unrounded float-valued layouts and performs
218/// rounding to snap the values to the pixel grid.
219///
220/// As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
221pub trait RoundTree: TraverseTree {
222    /// Get the node's unrounded layout
223    fn get_unrounded_layout(&self, node_id: NodeId) -> Layout;
224    /// Get a reference to the node's final layout
225    fn set_final_layout(&mut self, node_id: NodeId, layout: &Layout);
226}
227
228/// Trait used by the `print_tree` method which prints a debug representation
229///
230/// As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
231pub trait PrintTree: TraverseTree {
232    /// Get a debug label for the node (typically the type of node: flexbox, grid, text, image, etc)
233    fn get_debug_label(&self, node_id: NodeId) -> &'static str;
234    /// Get a reference to the node's final layout
235    fn get_final_layout(&self, node_id: NodeId) -> Layout;
236}
237
238#[cfg(feature = "flexbox")]
239/// Extends [`LayoutPartialTree`] with getters for the styles required for Flexbox layout
240pub trait LayoutFlexboxContainer: LayoutPartialTree {
241    /// The style type representing the Flexbox container's styles
242    type FlexboxContainerStyle<'a>: FlexboxContainerStyle
243    where
244        Self: 'a;
245    /// The style type representing each Flexbox item's styles
246    type FlexboxItemStyle<'a>: FlexboxItemStyle
247    where
248        Self: 'a;
249
250    /// Get the container's styles
251    fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_>;
252
253    /// Get the child's styles
254    fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_>;
255}
256
257#[cfg(feature = "grid")]
258/// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Grid layout
259pub trait LayoutGridContainer: LayoutPartialTree {
260    /// The style type representing the CSS Grid container's styles
261    type GridContainerStyle<'a>: GridContainerStyle<CustomIdent = Self::CustomIdent>
262    where
263        Self: 'a;
264
265    /// The style type representing each CSS Grid item's styles
266    type GridItemStyle<'a>: GridItemStyle<CustomIdent = Self::CustomIdent>
267    where
268        Self: 'a;
269
270    /// Get the container's styles
271    fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_>;
272
273    /// Get the child's styles
274    fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_>;
275
276    /// Set the node's detailed grid information
277    ///
278    /// Implementing this method is optional. Doing so allows you to access details about the the grid such as
279    /// the computed size of each grid track and the computed placement of each grid item.
280    #[cfg(feature = "detailed_layout_info")]
281    fn set_detailed_grid_info(&mut self, _node_id: NodeId, _detailed_grid_info: DetailedGridInfo) {
282        debug_log!("LayoutGridContainer::set_detailed_grid_info called");
283    }
284}
285
286#[cfg(feature = "block_layout")]
287/// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Block layout
288pub trait LayoutBlockContainer: LayoutPartialTree {
289    /// The style type representing the CSS Block container's styles
290    type BlockContainerStyle<'a>: BlockContainerStyle
291    where
292        Self: 'a;
293    /// The style type representing each CSS Block item's styles
294    type BlockItemStyle<'a>: BlockItemStyle
295    where
296        Self: 'a;
297
298    /// Get the container's styles
299    fn get_block_container_style(&self, node_id: NodeId) -> Self::BlockContainerStyle<'_>;
300
301    /// Get the child's styles
302    fn get_block_child_style(&self, child_node_id: NodeId) -> Self::BlockItemStyle<'_>;
303
304    /// Compute the specified node's size or full layout given the specified constraints
305    #[cfg(feature = "block_layout")]
306    fn compute_block_child_layout(
307        &mut self,
308        node_id: NodeId,
309        inputs: LayoutInput,
310        block_ctx: Option<&mut BlockContext<'_>>,
311    ) -> LayoutOutput {
312        let _ = block_ctx;
313        self.compute_child_layout(node_id, inputs)
314    }
315}
316
317// --- PRIVATE TRAITS
318
319/// A private trait which allows us to add extra convenience methods to types which implement
320/// LayoutTree without making those methods public.
321pub(crate) trait LayoutPartialTreeExt: LayoutPartialTree {
322    /// Compute the size of the node given the specified constraints
323    #[inline(always)]
324    #[allow(clippy::too_many_arguments)]
325    fn measure_child_size(
326        &mut self,
327        node_id: NodeId,
328        known_dimensions: Size<Option<f32>>,
329        parent_size: Size<Option<f32>>,
330        available_space: Size<AvailableSpace>,
331        sizing_mode: SizingMode,
332        axis: AbsoluteAxis,
333        vertical_margins_are_collapsible: Line<bool>,
334    ) -> f32 {
335        self.compute_child_layout(
336            node_id,
337            LayoutInput {
338                known_dimensions,
339                parent_size,
340                available_space,
341                sizing_mode,
342                axis: axis.into(),
343                run_mode: RunMode::ComputeSize,
344                vertical_margins_are_collapsible,
345            },
346        )
347        .size
348        .get_abs(axis)
349    }
350
351    /// Compute the size of the node given the specified constraints
352    #[inline(always)]
353    #[allow(clippy::too_many_arguments)]
354    fn measure_child_size_both(
355        &mut self,
356        node_id: NodeId,
357        known_dimensions: Size<Option<f32>>,
358        parent_size: Size<Option<f32>>,
359        available_space: Size<AvailableSpace>,
360        sizing_mode: SizingMode,
361        vertical_margins_are_collapsible: Line<bool>,
362    ) -> Size<f32> {
363        self.compute_child_layout(
364            node_id,
365            LayoutInput {
366                known_dimensions,
367                parent_size,
368                available_space,
369                sizing_mode,
370                axis: RequestedAxis::Both,
371                run_mode: RunMode::ComputeSize,
372                vertical_margins_are_collapsible,
373            },
374        )
375        .size
376    }
377
378    /// Perform a full layout on the node given the specified constraints
379    #[inline(always)]
380    fn perform_child_layout(
381        &mut self,
382        node_id: NodeId,
383        known_dimensions: Size<Option<f32>>,
384        parent_size: Size<Option<f32>>,
385        available_space: Size<AvailableSpace>,
386        sizing_mode: SizingMode,
387        vertical_margins_are_collapsible: Line<bool>,
388    ) -> LayoutOutput {
389        self.compute_child_layout(
390            node_id,
391            LayoutInput {
392                known_dimensions,
393                parent_size,
394                available_space,
395                sizing_mode,
396                axis: RequestedAxis::Both,
397                run_mode: RunMode::PerformLayout,
398                vertical_margins_are_collapsible,
399            },
400        )
401    }
402
403    /// Alias to `resolve_calc_value` with a shorter function name
404    #[inline(always)]
405    #[cfg(feature = "calc")]
406    fn calc(&self, val: *const (), basis: f32) -> f32 {
407        self.resolve_calc_value(val, basis)
408    }
409
410    /// Alias to `resolve_calc_value` with a shorter function name
411    #[inline(always)]
412    #[cfg(not(feature = "calc"))]
413    fn calc(&self, _val: *const (), _basis: f32) -> f32 {
414        0.0
415    }
416}
417
418impl<T: LayoutPartialTree> LayoutPartialTreeExt for T {}