Upgrade rand and rand_chacha (bench deps) to 0.9 (#798)
1#![allow(dead_code)]
2
3use rand::distr::uniform::SampleRange;
4use rand::Rng;
5use rand_chacha::ChaCha8Rng;
6use slotmap::{DefaultKey, SlotMap};
7
8use super::{BuildTree, BuildTreeExt, GenStyle};
9
10pub mod yg {
11 pub use ordered_float::OrderedFloat;
12 pub use slotmap::{DefaultKey, SlotMap};
13 pub use yoga::types::*;
14 pub use yoga::Node;
15
16 pub type NodeId = DefaultKey;
17 pub type YogaTree = SlotMap<DefaultKey, Node>;
18}
19mod tf {
20 pub use taffy::prelude::*;
21}
22use tf::Style as TaffyStyle;
23
24pub struct YogaTreeBuilder<R: Rng, G: GenStyle<TaffyStyle>> {
25 rng: R,
26 style_generator: G,
27 tree: yg::YogaTree,
28 root: yg::DefaultKey,
29}
30
31// Implement the BuildTree trait
32impl<R: Rng, G: GenStyle<TaffyStyle>> BuildTree<R, G> for YogaTreeBuilder<R, G> {
33 const NAME: &'static str = "Yoga";
34 type Tree = yg::YogaTree;
35 type Node = DefaultKey;
36
37 fn with_rng(mut rng: R, mut style_generator: G) -> Self {
38 let mut tree = SlotMap::new();
39 let root = create_yg_node(&mut tree, &style_generator.create_root_style(&mut rng), &[]);
40 YogaTreeBuilder { rng, style_generator, tree, root }
41 }
42
43 fn compute_layout_inner(&mut self, available_width: Option<f32>, available_height: Option<f32>) {
44 self.tree[self.root].calculate_layout(
45 available_width.unwrap_or(f32::INFINITY),
46 available_height.unwrap_or(f32::INFINITY),
47 yg::Direction::LTR,
48 )
49 }
50
51 fn random_usize(&mut self, range: impl SampleRange<usize>) -> usize {
52 self.rng.random_range(range)
53 }
54
55 fn create_leaf_node(&mut self) -> Self::Node {
56 let style = self.style_generator.create_leaf_style(&mut self.rng);
57 create_yg_node(&mut self.tree, &style, &[])
58 }
59
60 fn create_container_node(&mut self, children: &[Self::Node]) -> Self::Node {
61 let style = self.style_generator.create_container_style(&mut self.rng);
62 create_yg_node(&mut self.tree, &style, &children)
63 }
64
65 fn set_root_children(&mut self, children: &[Self::Node]) {
66 set_node_children(&mut self.tree, self.root, &children);
67 }
68
69 fn total_node_count(&mut self) -> usize {
70 self.tree.len()
71 }
72
73 fn into_tree_and_root(self) -> (Self::Tree, Self::Node) {
74 (self.tree, self.root)
75 }
76}
77
78impl<G: GenStyle<TaffyStyle>> BuildTreeExt<G> for YogaTreeBuilder<ChaCha8Rng, G> {}
79
80// impl<R: Rng, G: GenStyle<TaffyStyle>> YogaTreeBuilder<R, G> {
81// /// Create a YogaTreeBuilder with a standard rng from a style generator
82// fn new<NG: GenStyle<TaffyStyle>>(mut style_generator: NG) -> YogaTreeBuilder<ChaCha8Rng, NG> {
83// let mut rng = ChaCha8Rng::seed_from_u64(STANDARD_RNG_SEED);
84// let mut tree = SlotMap::new();
85// let root = create_yg_node(&mut tree, &style_generator.create_root_style(&mut rng), &[]);
86// YogaTreeBuilder { rng, style_generator, tree, root }
87// }
88
89// /// Create a YogaTreeBuilder with a standard rng from a style generator
90// fn with_seed<NG: GenStyle<TaffyStyle>>(seed: u64, mut style_generator: NG) -> YogaTreeBuilder<ChaCha8Rng, NG> {
91// let mut rng = ChaCha8Rng::seed_from_u64(seed);
92// let mut tree = SlotMap::new();
93// let root = create_yg_node(&mut tree, &style_generator.create_root_style(&mut rng), &[]);
94// YogaTreeBuilder { rng, style_generator, tree, root }
95// }
96
97// /// Create a YogaTreeBuilder from a random number generator and a style generator
98// fn with_rng<NR: Rng, NG: GenStyle<TaffyStyle>>(mut rng: NR, mut style_generator: NG) -> YogaTreeBuilder<NR, NG> {
99// let mut tree = SlotMap::new();
100// let root = create_yg_node(&mut tree, &style_generator.create_root_style(&mut rng), &[]);
101// YogaTreeBuilder { rng, style_generator, tree, root }
102// }
103// }
104
105fn create_yg_node(tree: &mut yg::YogaTree, style: &tf::Style, children: &[yg::DefaultKey]) -> yg::DefaultKey {
106 let mut node = yg::Node::new();
107 apply_taffy_style(&mut node, &style);
108 for (i, child) in children.into_iter().enumerate() {
109 node.insert_child(&mut tree[*child], i);
110 }
111 tree.insert(node)
112}
113
114pub fn new_default_style_with_children(tree: &mut yg::YogaTree, children: &[yg::DefaultKey]) -> yg::DefaultKey {
115 let mut node = yg::Node::new();
116 for (i, child) in children.into_iter().enumerate() {
117 node.insert_child(&mut tree[*child], i);
118 }
119 tree.insert(node)
120}
121
122fn set_node_children(tree: &mut yg::YogaTree, node_id: yg::DefaultKey, children: &[yg::DefaultKey]) {
123 // TODO: clear existing children.
124 for (i, child_id) in children.into_iter().enumerate() {
125 let [node, child] = tree.get_disjoint_mut([node_id, *child_id]).unwrap();
126 node.insert_child(child, i);
127 }
128}
129
130fn into_yg_units(dim: impl Into<tf::Dimension>) -> yg::StyleUnit {
131 let dim: tf::Dimension = dim.into();
132 let val = dim.into_raw().value();
133 match dim.into_raw().tag() {
134 tf::CompactLength::AUTO_TAG => yg::StyleUnit::Auto,
135 tf::CompactLength::LENGTH_TAG => yg::StyleUnit::Point(yg::OrderedFloat(val)),
136 tf::CompactLength::PERCENT_TAG => yg::StyleUnit::Percent(yg::OrderedFloat(val)),
137 _ => unreachable!(),
138 }
139}
140
141fn into_pixels(dim: impl Into<tf::Dimension>) -> f32 {
142 dim.into().into_option().unwrap_or(0.0)
143}
144
145fn items_into_align(align: Option<tf::AlignSelf>) -> yg::Align {
146 match align {
147 None => yg::Align::Auto,
148 Some(tf::AlignSelf::FlexStart) => yg::Align::FlexStart,
149 Some(tf::AlignSelf::FlexEnd) => yg::Align::FlexEnd,
150 Some(tf::AlignSelf::Center) => yg::Align::Center,
151 Some(tf::AlignSelf::Baseline) => yg::Align::Baseline,
152 Some(tf::AlignSelf::Stretch) => yg::Align::Stretch,
153 Some(tf::AlignSelf::Start) => unimplemented!(),
154 Some(tf::AlignSelf::End) => unimplemented!(),
155 }
156}
157
158fn content_into_align(align: Option<tf::AlignContent>) -> yg::Align {
159 match align {
160 None => yg::Align::Auto,
161 Some(tf::AlignContent::FlexStart) => yg::Align::FlexStart,
162 Some(tf::AlignContent::Start) => yg::Align::FlexStart,
163 Some(tf::AlignContent::FlexEnd) => yg::Align::FlexEnd,
164 Some(tf::AlignContent::End) => yg::Align::FlexEnd,
165 Some(tf::AlignContent::Center) => yg::Align::Center,
166 Some(tf::AlignContent::Stretch) => yg::Align::Stretch,
167 Some(tf::AlignContent::SpaceBetween) => yg::Align::SpaceBetween,
168 Some(tf::AlignContent::SpaceAround) => yg::Align::SpaceAround,
169 Some(tf::AlignContent::SpaceEvenly) => unimplemented!(),
170 }
171}
172
173fn content_into_justify(align: Option<tf::JustifyContent>) -> yg::Justify {
174 match align {
175 None => yg::Justify::FlexStart,
176 Some(tf::JustifyContent::FlexStart) => yg::Justify::FlexStart,
177 Some(tf::JustifyContent::Start) => yg::Justify::FlexStart,
178 Some(tf::JustifyContent::FlexEnd) => yg::Justify::FlexEnd,
179 Some(tf::JustifyContent::End) => yg::Justify::FlexEnd,
180 Some(tf::JustifyContent::Center) => yg::Justify::Center,
181 Some(tf::JustifyContent::SpaceBetween) => yg::Justify::SpaceBetween,
182 Some(tf::JustifyContent::SpaceAround) => yg::Justify::SpaceAround,
183 Some(tf::JustifyContent::Stretch) => unimplemented!(),
184 Some(tf::JustifyContent::SpaceEvenly) => unimplemented!(),
185 }
186}
187
188fn apply_taffy_style(node: &mut yg::Node, style: &tf::Style) {
189 // display
190 node.set_display(match style.display {
191 tf::Display::None => yg::Display::None,
192 tf::Display::Flex => yg::Display::Flex,
193 tf::Display::Grid => panic!("Yoga does not support CSS Grid layout"),
194 tf::Display::Block => panic!("Yoga does not support CSS Block layout"),
195 });
196
197 // box_sizing
198 node.set_box_sizing(match style.box_sizing {
199 tf::BoxSizing::BorderBox => yg::BoxSizing::BorderBox,
200 tf::BoxSizing::ContentBox => yg::BoxSizing::ContentBox,
201 });
202
203 // position
204 node.set_position_type(match style.position {
205 tf::Position::Relative => yg::PositionType::Relative,
206 tf::Position::Absolute => yg::PositionType::Absolute,
207 });
208 // inset
209 node.set_position(yg::Edge::Left, into_yg_units(style.inset.left));
210 node.set_position(yg::Edge::Right, into_yg_units(style.inset.right));
211 node.set_position(yg::Edge::Top, into_yg_units(style.inset.top));
212 node.set_position(yg::Edge::Bottom, into_yg_units(style.inset.bottom));
213
214 // sizes
215 node.set_width(into_yg_units(style.size.width));
216 node.set_height(into_yg_units(style.size.height));
217 node.set_min_width(into_yg_units(style.min_size.width));
218 node.set_min_height(into_yg_units(style.min_size.height));
219 node.set_max_width(into_yg_units(style.max_size.width));
220 node.set_max_height(into_yg_units(style.max_size.height));
221
222 // aspect_ratio
223 if let Some(aspect_ratio) = style.aspect_ratio {
224 node.set_aspect_ratio(aspect_ratio);
225 }
226
227 // spacing
228 node.set_padding(yg::Edge::Left, into_yg_units(style.padding.left));
229 node.set_padding(yg::Edge::Right, into_yg_units(style.padding.right));
230 node.set_padding(yg::Edge::Top, into_yg_units(style.padding.top));
231 node.set_padding(yg::Edge::Bottom, into_yg_units(style.padding.bottom));
232 node.set_margin(yg::Edge::Left, into_yg_units(style.margin.left));
233 node.set_margin(yg::Edge::Right, into_yg_units(style.margin.right));
234 node.set_margin(yg::Edge::Top, into_yg_units(style.margin.top));
235 node.set_margin(yg::Edge::Bottom, into_yg_units(style.margin.bottom));
236 node.set_border(yg::Edge::Left, into_pixels(style.border.left));
237 node.set_border(yg::Edge::Right, into_pixels(style.border.right));
238 node.set_border(yg::Edge::Top, into_pixels(style.border.top));
239 node.set_border(yg::Edge::Bottom, into_pixels(style.border.bottom));
240
241 // alignment
242 node.set_align_items(items_into_align(style.align_items));
243 node.set_align_self(items_into_align(style.align_self));
244 node.set_align_content(content_into_align(style.align_content));
245 node.set_justify_content(content_into_justify(style.justify_content));
246
247 // gap
248 node.set_column_gap(into_yg_units(style.gap.width));
249 node.set_row_gap(into_yg_units(style.gap.height));
250
251 // flex
252 node.set_flex_direction(match style.flex_direction {
253 tf::FlexDirection::Row => yg::FlexDirection::Row,
254 tf::FlexDirection::Column => yg::FlexDirection::Column,
255 tf::FlexDirection::RowReverse => yg::FlexDirection::RowReverse,
256 tf::FlexDirection::ColumnReverse => yg::FlexDirection::ColumnReverse,
257 });
258 node.set_flex_wrap(match style.flex_wrap {
259 tf::FlexWrap::NoWrap => yg::Wrap::NoWrap,
260 tf::FlexWrap::Wrap => yg::Wrap::Wrap,
261 tf::FlexWrap::WrapReverse => yg::Wrap::WrapReverse,
262 });
263 node.set_flex_basis(into_yg_units(style.flex_basis));
264 node.set_flex_grow(style.flex_grow);
265 node.set_flex_shrink(style.flex_shrink);
266}