freya_core/values/
size.rs

1use nom::{
2    branch::alt,
3    bytes::complete::tag,
4    character::complete::multispace0,
5    combinator::map,
6    multi::many1,
7    number::complete::float,
8    sequence::{
9        preceded,
10        tuple,
11    },
12    IResult,
13};
14use torin::{
15    geometry::Length,
16    size::{
17        DynamicCalculation,
18        Size,
19    },
20};
21
22use crate::parsing::{
23    Parse,
24    ParseError,
25};
26
27impl Parse for Size {
28    fn parse(value: &str) -> Result<Self, ParseError> {
29        if value == "auto" {
30            Ok(Size::Inner)
31        } else if value == "flex" {
32            Ok(Size::Flex(Length::new(1.0)))
33        } else if value.contains("flex") {
34            Ok(Size::Flex(Length::new(
35                value
36                    .replace("flex(", "")
37                    .replace(')', "")
38                    .parse::<f32>()
39                    .map_err(|_| ParseError)?,
40            )))
41        } else if value == "fill" {
42            Ok(Size::Fill)
43        } else if value == "fill-min" {
44            Ok(Size::FillMinimum)
45        } else if value.contains("calc") {
46            Ok(Size::DynamicCalculations(1.0, Box::new(parse_calc(value)?)))
47        } else if value.contains('%') {
48            Ok(Size::Percentage(Length::new(
49                value
50                    .replace('%', "")
51                    .parse::<f32>()
52                    .map_err(|_| ParseError)?,
53            )))
54        } else if value.contains('v') {
55            Ok(Size::RootPercentage(Length::new(
56                value
57                    .replace('v', "")
58                    .parse::<f32>()
59                    .map_err(|_| ParseError)?,
60            )))
61        } else {
62            Ok(Size::Pixels(Length::new(
63                value.parse::<f32>().map_err(|_| ParseError)?,
64            )))
65        }
66    }
67}
68
69pub fn parse_calc(mut value: &str) -> Result<Vec<DynamicCalculation>, ParseError> {
70    // No need to parse this using nom
71
72    value = value
73        .strip_prefix("calc(")
74        .ok_or(ParseError)?
75        .strip_suffix(')')
76        .ok_or(ParseError)?;
77    fn inner_parse(value: &str) -> IResult<&str, Vec<DynamicCalculation>> {
78        many1(preceded(
79            multispace0,
80            alt((
81                map(tag("+"), |_| DynamicCalculation::Add),
82                map(tag("-"), |_| DynamicCalculation::Sub),
83                map(tag("*"), |_| DynamicCalculation::Mul),
84                map(tag("/"), |_| DynamicCalculation::Div),
85                map(tag("("), |_| DynamicCalculation::OpenParenthesis),
86                map(tag(")"), |_| DynamicCalculation::ClosedParenthesis),
87                map(tuple((float, tag("%"))), |(v, _)| {
88                    DynamicCalculation::Percentage(v)
89                }),
90                map(tuple((float, tag("v"))), |(v, _)| {
91                    DynamicCalculation::RootPercentage(v)
92                }),
93                map(float, DynamicCalculation::Pixels),
94            )),
95        ))(value)
96    }
97    let tokens = inner_parse(value).map_err(|_| ParseError)?.1;
98
99    Ok(tokens)
100}