1use super::CompactLength;
3use crate::geometry::Rect;
4use crate::style_helpers::{FromLength, FromPercent, TaffyAuto, TaffyZero};
5#[cfg(feature = "parse")]
6use crate::util::parse::{from_str_from_css, parse_css_str_entirely, CssParseResult, FromCss, Parser, Token};
7
8#[derive(Copy, Clone, PartialEq, Debug)]
12#[cfg_attr(feature = "serde", derive(Serialize))]
13pub struct LengthPercentage(pub(crate) CompactLength);
14impl TaffyZero for LengthPercentage {
15 const ZERO: Self = Self(CompactLength::ZERO);
16}
17impl FromLength for LengthPercentage {
18 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
19 Self::length(value.into())
20 }
21}
22impl FromPercent for LengthPercentage {
23 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
24 Self::percent(value.into())
25 }
26}
27
28#[cfg(feature = "parse")]
29impl FromCss for LengthPercentage {
30 fn from_css<'i>(parser: &mut Parser<'i, '_>) -> CssParseResult<'i, Self> {
31 match parser.next()?.clone() {
32 Token::Percentage { unit_value, .. } => Ok(Self::percent(unit_value)),
33 Token::Dimension { unit, value, .. } if unit == "px" => Ok(Self::length(value)),
34 token => Err(parser.new_unexpected_token_error(token))?,
35 }
36 }
37}
38#[cfg(feature = "parse")]
39from_str_from_css!(LengthPercentage);
40
41impl LengthPercentage {
42 #[inline(always)]
45 pub const fn length(val: f32) -> Self {
46 Self(CompactLength::length(val))
47 }
48
49 #[inline(always)]
53 pub const fn percent(val: f32) -> Self {
54 Self(CompactLength::percent(val))
55 }
56
57 #[inline(always)]
62 #[cfg(feature = "calc")]
63 pub fn calc(ptr: *const ()) -> Self {
64 Self(CompactLength::calc(ptr))
65 }
66
67 #[allow(unsafe_code)]
71 pub const unsafe fn from_raw(val: CompactLength) -> Self {
72 Self(val)
73 }
74
75 pub const fn into_raw(self) -> CompactLength {
77 self.0
78 }
79}
80
81#[cfg(feature = "serde")]
82impl<'de> serde::Deserialize<'de> for LengthPercentage {
83 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
84 where
85 D: serde::Deserializer<'de>,
86 {
87 let inner = CompactLength::deserialize(deserializer)?;
88 if matches!(inner.tag(), CompactLength::LENGTH_TAG | CompactLength::PERCENT_TAG) {
90 Ok(Self(inner))
91 } else {
92 Err(serde::de::Error::custom("Invalid tag"))
93 }
94 }
95}
96
97#[derive(Copy, Clone, PartialEq, Debug)]
101#[cfg_attr(feature = "serde", derive(Serialize))]
102pub struct LengthPercentageAuto(pub(crate) CompactLength);
103impl TaffyZero for LengthPercentageAuto {
104 const ZERO: Self = Self(CompactLength::ZERO);
105}
106impl TaffyAuto for LengthPercentageAuto {
107 const AUTO: Self = Self(CompactLength::AUTO);
108}
109impl FromLength for LengthPercentageAuto {
110 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
111 Self::length(value.into())
112 }
113}
114impl FromPercent for LengthPercentageAuto {
115 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
116 Self::percent(value.into())
117 }
118}
119impl From<LengthPercentage> for LengthPercentageAuto {
120 fn from(input: LengthPercentage) -> Self {
121 Self(input.0)
122 }
123}
124
125#[cfg(feature = "parse")]
126impl FromCss for LengthPercentageAuto {
127 fn from_css<'i>(parser: &mut Parser<'i, '_>) -> CssParseResult<'i, Self> {
128 match parser.next()?.clone() {
129 Token::Percentage { unit_value, .. } => Ok(Self::percent(unit_value)),
130 Token::Dimension { unit, value, .. } if unit == "px" => Ok(Self::length(value)),
131 Token::Ident(ident) if ident == "auto" => Ok(Self::auto()),
132 token => Err(parser.new_unexpected_token_error(token))?,
133 }
134 }
135}
136#[cfg(feature = "parse")]
137from_str_from_css!(LengthPercentageAuto);
138
139impl LengthPercentageAuto {
140 #[inline(always)]
143 pub const fn length(val: f32) -> Self {
144 Self(CompactLength::length(val))
145 }
146
147 #[inline(always)]
151 pub const fn percent(val: f32) -> Self {
152 Self(CompactLength::percent(val))
153 }
154
155 #[inline(always)]
158 pub const fn auto() -> Self {
159 Self(CompactLength::auto())
160 }
161
162 #[inline]
167 #[cfg(feature = "calc")]
168 pub fn calc(ptr: *const ()) -> Self {
169 Self(CompactLength::calc(ptr))
170 }
171
172 #[allow(unsafe_code)]
176 pub const unsafe fn from_raw(val: CompactLength) -> Self {
177 Self(val)
178 }
179
180 pub const fn into_raw(self) -> CompactLength {
182 self.0
183 }
184
185 #[inline(always)]
190 pub fn resolve_to_option(self, context: f32, calc_resolver: impl Fn(*const (), f32) -> f32) -> Option<f32> {
191 match self.0.tag() {
192 CompactLength::LENGTH_TAG => Some(self.0.value()),
193 CompactLength::PERCENT_TAG => Some(context * self.0.value()),
194 CompactLength::AUTO_TAG => None,
195 #[cfg(feature = "calc")]
196 _ if self.0.is_calc() => Some(calc_resolver(self.0.calc_value(), context)),
197 _ => unreachable!("LengthPercentageAuto values cannot be constructed with other tags"),
198 }
199 }
200
201 #[inline(always)]
203 pub fn is_auto(self) -> bool {
204 self.0.is_auto()
205 }
206}
207
208#[cfg(feature = "serde")]
209impl<'de> serde::Deserialize<'de> for LengthPercentageAuto {
210 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
211 where
212 D: serde::Deserializer<'de>,
213 {
214 let inner = CompactLength::deserialize(deserializer)?;
215 if matches!(inner.tag(), CompactLength::LENGTH_TAG | CompactLength::PERCENT_TAG | CompactLength::AUTO_TAG) {
217 Ok(Self(inner))
218 } else {
219 Err(serde::de::Error::custom("Invalid tag"))
220 }
221 }
222}
223
224#[derive(Copy, Clone, PartialEq, Debug)]
228#[cfg_attr(feature = "serde", derive(Serialize))]
229pub struct Dimension(pub(crate) CompactLength);
230impl TaffyZero for Dimension {
231 const ZERO: Self = Self(CompactLength::ZERO);
232}
233impl TaffyAuto for Dimension {
234 const AUTO: Self = Self(CompactLength::AUTO);
235}
236impl FromLength for Dimension {
237 fn from_length<Input: Into<f32> + Copy>(value: Input) -> Self {
238 Self::length(value.into())
239 }
240}
241impl FromPercent for Dimension {
242 fn from_percent<Input: Into<f32> + Copy>(value: Input) -> Self {
243 Self::percent(value.into())
244 }
245}
246impl From<LengthPercentage> for Dimension {
247 fn from(input: LengthPercentage) -> Self {
248 Self(input.0)
249 }
250}
251impl From<LengthPercentageAuto> for Dimension {
252 fn from(input: LengthPercentageAuto) -> Self {
253 Self(input.0)
254 }
255}
256
257#[cfg(feature = "parse")]
258impl FromCss for Dimension {
259 fn from_css<'i>(parser: &mut Parser<'i, '_>) -> CssParseResult<'i, Self> {
260 match parser.next()?.clone() {
261 Token::Percentage { unit_value, .. } => Ok(Self::percent(unit_value)),
262 Token::Dimension { unit, value, .. } if unit == "px" => Ok(Self::length(value)),
263 Token::Ident(ident) if ident == "auto" => Ok(Self::auto()),
264 token => Err(parser.new_unexpected_token_error(token))?,
265 }
266 }
267}
268#[cfg(feature = "parse")]
269from_str_from_css!(Dimension);
270
271impl Dimension {
272 #[inline(always)]
275 pub const fn length(val: f32) -> Self {
276 Self(CompactLength::length(val))
277 }
278
279 #[inline(always)]
283 pub const fn percent(val: f32) -> Self {
284 Self(CompactLength::percent(val))
285 }
286
287 #[inline(always)]
290 pub const fn auto() -> Self {
291 Self(CompactLength::auto())
292 }
293
294 #[inline]
299 #[cfg(feature = "calc")]
300 pub fn calc(ptr: *const ()) -> Self {
301 Self(CompactLength::calc(ptr))
302 }
303
304 #[allow(unsafe_code)]
308 pub const unsafe fn from_raw(val: CompactLength) -> Self {
309 Self(val)
310 }
311
312 pub const fn into_raw(self) -> CompactLength {
314 self.0
315 }
316
317 #[cfg(feature = "grid")]
319 pub fn into_option(self) -> Option<f32> {
320 match self.0.tag() {
321 CompactLength::LENGTH_TAG => Some(self.0.value()),
322 _ => None,
323 }
324 }
325 #[inline(always)]
327 pub fn is_auto(self) -> bool {
328 self.0.is_auto()
329 }
330
331 pub fn tag(self) -> usize {
333 self.0.tag()
334 }
335
336 pub fn value(self) -> f32 {
338 self.0.value()
339 }
340}
341
342#[cfg(feature = "serde")]
343impl<'de> serde::Deserialize<'de> for Dimension {
344 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
345 where
346 D: serde::Deserializer<'de>,
347 {
348 let inner = CompactLength::deserialize(deserializer)?;
349 if matches!(inner.tag(), CompactLength::LENGTH_TAG | CompactLength::PERCENT_TAG | CompactLength::AUTO_TAG) {
351 Ok(Self(inner))
352 } else {
353 Err(serde::de::Error::custom("Invalid tag"))
354 }
355 }
356}
357
358impl Rect<Dimension> {
359 #[must_use]
361 pub const fn from_length(start: f32, end: f32, top: f32, bottom: f32) -> Self {
362 Rect {
363 left: Dimension(CompactLength::length(start)),
364 right: Dimension(CompactLength::length(end)),
365 top: Dimension(CompactLength::length(top)),
366 bottom: Dimension(CompactLength::length(bottom)),
367 }
368 }
369
370 #[must_use]
372 pub const fn from_percent(start: f32, end: f32, top: f32, bottom: f32) -> Self {
373 Rect {
374 left: Dimension(CompactLength::percent(start)),
375 right: Dimension(CompactLength::percent(end)),
376 top: Dimension(CompactLength::percent(top)),
377 bottom: Dimension(CompactLength::percent(bottom)),
378 }
379 }
380}