1use super::CompactLength;
3use crate::geometry::Rect;
4use crate::style_helpers::{FromLength, FromPercent, TaffyAuto, TaffyZero};
5
6#[derive(Copy, Clone, PartialEq, Debug)]
10#[cfg_attr(feature = "serde", derive(Serialize))]
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 #[inline(always)]
29 pub const fn length(val: f32) -> Self {
30 Self(CompactLength::length(val))
31 }
32
33 #[inline(always)]
37 pub const fn percent(val: f32) -> Self {
38 Self(CompactLength::percent(val))
39 }
40
41 #[inline(always)]
46 #[cfg(feature = "calc")]
47 pub fn calc(ptr: *const ()) -> Self {
48 Self(CompactLength::calc(ptr))
49 }
50
51 #[allow(unsafe_code)]
55 pub unsafe fn from_raw(val: CompactLength) -> Self {
56 Self(val)
57 }
58
59 pub fn into_raw(self) -> CompactLength {
61 self.0
62 }
63}
64
65#[cfg(feature = "serde")]
66impl<'de> serde::Deserialize<'de> for LengthPercentage {
67 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
68 where
69 D: serde::Deserializer<'de>,
70 {
71 let inner = CompactLength::deserialize(deserializer)?;
72 if matches!(inner.tag(), CompactLength::LENGTH_TAG | CompactLength::PERCENT_TAG) {
74 Ok(Self(inner))
75 } else {
76 Err(serde::de::Error::custom("Invalid tag"))
77 }
78 }
79}
80
81#[derive(Copy, Clone, PartialEq, Debug)]
85#[cfg_attr(feature = "serde", derive(Serialize))]
86pub struct LengthPercentageAuto(pub(crate) CompactLength);
87impl TaffyZero for LengthPercentageAuto {
88 const ZERO: Self = Self(CompactLength::ZERO);
89}
90impl TaffyAuto for LengthPercentageAuto {
91 const AUTO: Self = Self(CompactLength::AUTO);
92}
93impl FromLength for LengthPercentageAuto {
94 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
95 Self::length(value.into())
96 }
97}
98impl FromPercent for LengthPercentageAuto {
99 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
100 Self::percent(value.into())
101 }
102}
103impl From<LengthPercentage> for LengthPercentageAuto {
104 fn from(input: LengthPercentage) -> Self {
105 Self(input.0)
106 }
107}
108
109impl LengthPercentageAuto {
110 #[inline(always)]
113 pub const fn length(val: f32) -> Self {
114 Self(CompactLength::length(val))
115 }
116
117 #[inline(always)]
121 pub const fn percent(val: f32) -> Self {
122 Self(CompactLength::percent(val))
123 }
124
125 #[inline(always)]
128 pub const fn auto() -> Self {
129 Self(CompactLength::auto())
130 }
131
132 #[inline]
137 #[cfg(feature = "calc")]
138 pub fn calc(ptr: *const ()) -> Self {
139 Self(CompactLength::calc(ptr))
140 }
141
142 #[allow(unsafe_code)]
146 pub unsafe fn from_raw(val: CompactLength) -> Self {
147 Self(val)
148 }
149
150 pub fn into_raw(self) -> CompactLength {
152 self.0
153 }
154
155 #[inline(always)]
160 pub fn resolve_to_option(self, context: f32, calc_resolver: impl Fn(*const (), f32) -> f32) -> Option<f32> {
161 match self.0.tag() {
162 CompactLength::LENGTH_TAG => Some(self.0.value()),
163 CompactLength::PERCENT_TAG => Some(context * self.0.value()),
164 CompactLength::AUTO_TAG => None,
165 #[cfg(feature = "calc")]
166 _ if self.0.is_calc() => Some(calc_resolver(self.0.calc_value(), context)),
167 _ => unreachable!("LengthPercentageAuto values cannot be constructed with other tags"),
168 }
169 }
170
171 #[inline(always)]
173 pub fn is_auto(self) -> bool {
174 self.0.is_auto()
175 }
176}
177
178#[cfg(feature = "serde")]
179impl<'de> serde::Deserialize<'de> for LengthPercentageAuto {
180 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
181 where
182 D: serde::Deserializer<'de>,
183 {
184 let inner = CompactLength::deserialize(deserializer)?;
185 if matches!(inner.tag(), CompactLength::LENGTH_TAG | CompactLength::PERCENT_TAG | CompactLength::AUTO_TAG) {
187 Ok(Self(inner))
188 } else {
189 Err(serde::de::Error::custom("Invalid tag"))
190 }
191 }
192}
193
194#[derive(Copy, Clone, PartialEq, Debug)]
198#[cfg_attr(feature = "serde", derive(Serialize))]
199pub struct Dimension(pub(crate) CompactLength);
200impl TaffyZero for Dimension {
201 const ZERO: Self = Self(CompactLength::ZERO);
202}
203impl TaffyAuto for Dimension {
204 const AUTO: Self = Self(CompactLength::AUTO);
205}
206impl FromLength for Dimension {
207 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
208 Self::length(value.into())
209 }
210}
211impl FromPercent for Dimension {
212 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
213 Self::percent(value.into())
214 }
215}
216impl From<LengthPercentage> for Dimension {
217 fn from(input: LengthPercentage) -> Self {
218 Self(input.0)
219 }
220}
221impl From<LengthPercentageAuto> for Dimension {
222 fn from(input: LengthPercentageAuto) -> Self {
223 Self(input.0)
224 }
225}
226
227impl Dimension {
228 #[inline(always)]
231 pub const fn length(val: f32) -> Self {
232 Self(CompactLength::length(val))
233 }
234
235 #[inline(always)]
239 pub const fn percent(val: f32) -> Self {
240 Self(CompactLength::percent(val))
241 }
242
243 #[inline(always)]
246 pub const fn auto() -> Self {
247 Self(CompactLength::auto())
248 }
249
250 #[inline]
255 #[cfg(feature = "calc")]
256 pub fn calc(ptr: *const ()) -> Self {
257 Self(CompactLength::calc(ptr))
258 }
259
260 #[allow(unsafe_code)]
264 pub unsafe fn from_raw(val: CompactLength) -> Self {
265 Self(val)
266 }
267
268 pub fn into_raw(self) -> CompactLength {
270 self.0
271 }
272
273 #[cfg(feature = "grid")]
275 pub fn into_option(self) -> Option<f32> {
276 match self.0.tag() {
277 CompactLength::LENGTH_TAG => Some(self.0.value()),
278 _ => None,
279 }
280 }
281 #[inline(always)]
283 pub fn is_auto(self) -> bool {
284 self.0.is_auto()
285 }
286
287 pub fn tag(self) -> usize {
289 self.0.tag()
290 }
291
292 pub fn value(self) -> f32 {
294 self.0.value()
295 }
296}
297
298#[cfg(feature = "serde")]
299impl<'de> serde::Deserialize<'de> for Dimension {
300 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
301 where
302 D: serde::Deserializer<'de>,
303 {
304 let inner = CompactLength::deserialize(deserializer)?;
305 if matches!(inner.tag(), CompactLength::LENGTH_TAG | CompactLength::PERCENT_TAG | CompactLength::AUTO_TAG) {
307 Ok(Self(inner))
308 } else {
309 Err(serde::de::Error::custom("Invalid tag"))
310 }
311 }
312}
313
314impl Rect<Dimension> {
315 #[must_use]
317 pub const fn from_length(start: f32, end: f32, top: f32, bottom: f32) -> Self {
318 Rect {
319 left: Dimension(CompactLength::length(start)),
320 right: Dimension(CompactLength::length(end)),
321 top: Dimension(CompactLength::length(top)),
322 bottom: Dimension(CompactLength::length(bottom)),
323 }
324 }
325
326 #[must_use]
328 pub const fn from_percent(start: f32, end: f32, top: f32, bottom: f32) -> Self {
329 Rect {
330 left: Dimension(CompactLength::percent(start)),
331 right: Dimension(CompactLength::percent(end)),
332 top: Dimension(CompactLength::percent(top)),
333 bottom: Dimension(CompactLength::percent(bottom)),
334 }
335 }
336}