Add inherent method constructors to style dimension types (#788)
1//! Style types for representing lengths / sizes
2use super::CompactLength;
3use crate::geometry::Rect;
4use crate::style_helpers::{FromLength, FromPercent, TaffyAuto, TaffyZero};
5
6/// A unit of linear measurement
7///
8/// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size<T>`](crate::geometry::Size).
9#[derive(Copy, Clone, PartialEq, Debug)]
10#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11pub struct LengthPercentage(pub(crate) CompactLength);
12impl TaffyZero for LengthPercentage {
13 const ZERO: Self = Self(CompactLength::ZERO);
14}
15impl FromLength for LengthPercentage {
16 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
17 Self::length(value.into())
18 }
19}
20impl FromPercent for LengthPercentage {
21 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
22 Self::percent(value.into())
23 }
24}
25impl LengthPercentage {
26 /// An absolute length in some abstract units. Users of Taffy may define what they correspond
27 /// to in their application (pixels, logical pixels, mm, etc) as they see fit.
28 #[inline(always)]
29 pub const fn length(val: f32) -> Self {
30 Self(CompactLength::length(val))
31 }
32
33 /// A percentage length relative to the size of the containing block.
34 ///
35 /// **NOTE: percentages are represented as a f32 value in the range [0.0, 1.0] NOT the range [0.0, 100.0]**
36 #[inline(always)]
37 pub const fn percent(val: f32) -> Self {
38 Self(CompactLength::percent(val))
39 }
40
41 /// A `calc()` value. The value passed here is treated as an opaque handle to
42 /// the actual calc representation and may be a pointer, index, etc.
43 ///
44 /// The low 3 bits are used as a tag value and will be returned as 0.
45 #[inline]
46 pub fn calc(ptr: *const ()) -> Self {
47 Self(CompactLength::calc(ptr))
48 }
49
50 /// Create a LengthPercentage from a raw `CompactLength`.
51 /// # Safety
52 /// CompactLength must represent a valid variant for LengthPercentage
53 #[allow(unsafe_code)]
54 pub unsafe fn from_raw(val: CompactLength) -> Self {
55 Self(val)
56 }
57
58 /// Get the underlying `CompactLength` representation of the value
59 pub fn into_raw(self) -> CompactLength {
60 self.0
61 }
62}
63
64/// A unit of linear measurement
65///
66/// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size<T>`](crate::geometry::Size).
67#[derive(Copy, Clone, PartialEq, Debug)]
68#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
69pub struct LengthPercentageAuto(pub(crate) CompactLength);
70impl TaffyZero for LengthPercentageAuto {
71 const ZERO: Self = Self(CompactLength::ZERO);
72}
73impl TaffyAuto for LengthPercentageAuto {
74 const AUTO: Self = Self(CompactLength::AUTO);
75}
76impl FromLength for LengthPercentageAuto {
77 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
78 Self::length(value.into())
79 }
80}
81impl FromPercent for LengthPercentageAuto {
82 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
83 Self::percent(value.into())
84 }
85}
86impl From<LengthPercentage> for LengthPercentageAuto {
87 fn from(input: LengthPercentage) -> Self {
88 Self(input.0)
89 }
90}
91
92impl LengthPercentageAuto {
93 /// An absolute length in some abstract units. Users of Taffy may define what they correspond
94 /// to in their application (pixels, logical pixels, mm, etc) as they see fit.
95 #[inline(always)]
96 pub const fn length(val: f32) -> Self {
97 Self(CompactLength::length(val))
98 }
99
100 /// A percentage length relative to the size of the containing block.
101 ///
102 /// **NOTE: percentages are represented as a f32 value in the range [0.0, 1.0] NOT the range [0.0, 100.0]**
103 #[inline(always)]
104 pub const fn percent(val: f32) -> Self {
105 Self(CompactLength::percent(val))
106 }
107
108 /// The dimension should be automatically computed according to algorithm-specific rules
109 /// regarding the default size of boxes.
110 #[inline(always)]
111 pub const fn auto() -> Self {
112 Self(CompactLength::auto())
113 }
114
115 /// A `calc()` value. The value passed here is treated as an opaque handle to
116 /// the actual calc representation and may be a pointer, index, etc.
117 ///
118 /// The low 3 bits are used as a tag value and will be returned as 0.
119 #[inline]
120 pub fn calc(ptr: *const ()) -> Self {
121 Self(CompactLength::calc(ptr))
122 }
123
124 /// Create a LengthPercentageAuto from a raw `CompactLength`.
125 /// # Safety
126 /// CompactLength must represent a valid variant for LengthPercentageAuto
127 #[allow(unsafe_code)]
128 pub unsafe fn from_raw(val: CompactLength) -> Self {
129 Self(val)
130 }
131
132 /// Get the underlying `CompactLength` representation of the value
133 pub fn into_raw(self) -> CompactLength {
134 self.0
135 }
136
137 /// Returns:
138 /// - Some(length) for Length variants
139 /// - Some(resolved) using the provided context for Percent variants
140 /// - None for Auto variants
141 #[inline(always)]
142 pub fn resolve_to_option(self, context: f32, calc_resolver: impl Fn(u64, f32) -> f32) -> Option<f32> {
143 match self.0.tag() {
144 CompactLength::LENGTH_TAG => Some(self.0.value()),
145 CompactLength::PERCENT_TAG => Some(context * self.0.value()),
146 CompactLength::AUTO_TAG => None,
147 _ if self.0.is_calc() => Some(calc_resolver(self.0.calc_value(), context)),
148 _ => unreachable!("LengthPercentageAuto values cannot be constructed with other tags"),
149 }
150 }
151
152 /// Returns true if value is LengthPercentageAuto::Auto
153 #[inline(always)]
154 pub fn is_auto(self) -> bool {
155 self.0.is_auto()
156 }
157}
158
159/// A unit of linear measurement
160///
161/// This is commonly combined with [`Rect`], [`Point`](crate::geometry::Point) and [`Size<T>`](crate::geometry::Size).
162#[derive(Copy, Clone, PartialEq, Debug)]
163#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
164pub struct Dimension(pub(crate) CompactLength);
165impl TaffyZero for Dimension {
166 const ZERO: Self = Self(CompactLength::ZERO);
167}
168impl TaffyAuto for Dimension {
169 const AUTO: Self = Self(CompactLength::AUTO);
170}
171impl FromLength for Dimension {
172 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
173 Self::length(value.into())
174 }
175}
176impl FromPercent for Dimension {
177 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
178 Self::percent(value.into())
179 }
180}
181impl From<LengthPercentage> for Dimension {
182 fn from(input: LengthPercentage) -> Self {
183 Self(input.0)
184 }
185}
186impl From<LengthPercentageAuto> for Dimension {
187 fn from(input: LengthPercentageAuto) -> Self {
188 Self(input.0)
189 }
190}
191
192impl Dimension {
193 /// An absolute length in some abstract units. Users of Taffy may define what they correspond
194 /// to in their application (pixels, logical pixels, mm, etc) as they see fit.
195 #[inline(always)]
196 pub const fn length(val: f32) -> Self {
197 Self(CompactLength::length(val))
198 }
199
200 /// A percentage length relative to the size of the containing block.
201 ///
202 /// **NOTE: percentages are represented as a f32 value in the range [0.0, 1.0] NOT the range [0.0, 100.0]**
203 #[inline(always)]
204 pub const fn percent(val: f32) -> Self {
205 Self(CompactLength::percent(val))
206 }
207
208 /// The dimension should be automatically computed according to algorithm-specific rules
209 /// regarding the default size of boxes.
210 #[inline(always)]
211 pub const fn auto() -> Self {
212 Self(CompactLength::auto())
213 }
214
215 /// A `calc()` value. The value passed here is treated as an opaque handle to
216 /// the actual calc representation and may be a pointer, index, etc.
217 ///
218 /// The low 3 bits are used as a tag value and will be returned as 0.
219 #[inline]
220 pub fn calc(ptr: *const ()) -> Self {
221 Self(CompactLength::calc(ptr))
222 }
223
224 /// Create a LengthPercentageAuto from a raw `CompactLength`.
225 /// # Safety
226 /// CompactLength must represent a valid variant for LengthPercentageAuto
227 #[allow(unsafe_code)]
228 pub unsafe fn from_raw(val: CompactLength) -> Self {
229 Self(val)
230 }
231
232 /// Get the underlying `CompactLength` representation of the value
233 pub fn into_raw(self) -> CompactLength {
234 self.0
235 }
236
237 /// Get Length value if value is Length variant
238 #[cfg(feature = "grid")]
239 pub fn into_option(self) -> Option<f32> {
240 match self.0.tag() {
241 CompactLength::LENGTH_TAG => Some(self.0.value()),
242 _ => None,
243 }
244 }
245 /// Returns true if value is Auto
246 #[inline(always)]
247 pub fn is_auto(self) -> bool {
248 self.0.is_auto()
249 }
250
251 /// Get the raw `CompactLength` tag
252 pub fn tag(self) -> u64 {
253 self.0.tag()
254 }
255
256 /// Get the raw `CompactLength` value for non-calc variants that have a numeric parameter
257 pub fn value(self) -> f32 {
258 self.0.value()
259 }
260}
261
262impl Rect<Dimension> {
263 /// Create a new Rect with length values
264 #[must_use]
265 pub const fn from_length(start: f32, end: f32, top: f32, bottom: f32) -> Self {
266 Rect {
267 left: Dimension(CompactLength::length(start)),
268 right: Dimension(CompactLength::length(end)),
269 top: Dimension(CompactLength::length(top)),
270 bottom: Dimension(CompactLength::length(bottom)),
271 }
272 }
273
274 /// Create a new Rect with percentage values
275 #[must_use]
276 pub const fn from_percent(start: f32, end: f32, top: f32, bottom: f32) -> Self {
277 Rect {
278 left: Dimension(CompactLength::percent(start)),
279 right: Dimension(CompactLength::percent(end)),
280 top: Dimension(CompactLength::percent(top)),
281 bottom: Dimension(CompactLength::percent(bottom)),
282 }
283 }
284}