1
//! CSS list styling properties (`list-style-type` and `list-style-position`)
2

            
3
use alloc::string::{String, ToString};
4
use core::fmt;
5
use crate::corety::AzString;
6

            
7
use crate::{format_rust_code::FormatAsRustCode, props::formatter::PrintAsCssValue};
8

            
9
// --- list-style-type ---
10

            
11
/// CSS `list-style-type` property — controls the marker style for list items.
12
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13
#[repr(C)]
14
#[derive(Default)]
15
pub enum StyleListStyleType {
16
    None,
17
    #[default]
18
    Disc,
19
    Circle,
20
    Square,
21
    Decimal,
22
    DecimalLeadingZero,
23
    LowerRoman,
24
    UpperRoman,
25
    LowerGreek,
26
    UpperGreek,
27
    LowerAlpha,
28
    UpperAlpha,
29
}
30

            
31

            
32
impl PrintAsCssValue for StyleListStyleType {
33
    fn print_as_css_value(&self) -> String {
34
        use StyleListStyleType::*;
35
        String::from(match self {
36
            None => "none",
37
            Disc => "disc",
38
            Circle => "circle",
39
            Square => "square",
40
            Decimal => "decimal",
41
            DecimalLeadingZero => "decimal-leading-zero",
42
            LowerRoman => "lower-roman",
43
            UpperRoman => "upper-roman",
44
            LowerGreek => "lower-greek",
45
            UpperGreek => "upper-greek",
46
            LowerAlpha => "lower-alpha",
47
            UpperAlpha => "upper-alpha",
48
        })
49
    }
50
}
51

            
52
impl FormatAsRustCode for StyleListStyleType {
53
    fn format_as_rust_code(&self, _tabs: usize) -> String {
54
        use StyleListStyleType::*;
55
        format!(
56
            "StyleListStyleType::{}",
57
            match self {
58
                None => "None",
59
                Disc => "Disc",
60
                Circle => "Circle",
61
                Square => "Square",
62
                Decimal => "Decimal",
63
                DecimalLeadingZero => "DecimalLeadingZero",
64
                LowerRoman => "LowerRoman",
65
                UpperRoman => "UpperRoman",
66
                LowerGreek => "LowerGreek",
67
                UpperGreek => "UpperGreek",
68
                LowerAlpha => "LowerAlpha",
69
                UpperAlpha => "UpperAlpha",
70
            }
71
        )
72
    }
73
}
74

            
75
impl fmt::Display for StyleListStyleType {
76
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77
        write!(f, "{}", self.print_as_css_value())
78
    }
79
}
80

            
81
// --- list-style-position ---
82

            
83
/// CSS `list-style-position` property — controls whether the marker is inside or outside the list item box.
84
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
85
#[repr(C)]
86
#[derive(Default)]
87
pub enum StyleListStylePosition {
88
    Inside,
89
    #[default]
90
    Outside,
91
}
92

            
93

            
94
impl PrintAsCssValue for StyleListStylePosition {
95
    fn print_as_css_value(&self) -> String {
96
        use StyleListStylePosition::*;
97
        String::from(match self {
98
            Inside => "inside",
99
            Outside => "outside",
100
        })
101
    }
102
}
103

            
104
impl FormatAsRustCode for StyleListStylePosition {
105
    fn format_as_rust_code(&self, _tabs: usize) -> String {
106
        use StyleListStylePosition::*;
107
        format!(
108
            "StyleListStylePosition::{}",
109
            match self {
110
                Inside => "Inside",
111
                Outside => "Outside",
112
            }
113
        )
114
    }
115
}
116

            
117
impl fmt::Display for StyleListStylePosition {
118
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119
        write!(f, "{}", self.print_as_css_value())
120
    }
121
}
122

            
123
// --- Parsing Logic ---
124

            
125
#[cfg(feature = "parser")]
126
#[derive(Clone, PartialEq)]
127
pub enum StyleListStyleTypeParseError<'a> {
128
    InvalidValue(&'a str),
129
}
130

            
131
#[cfg(feature = "parser")]
132
impl_debug_as_display!(StyleListStyleTypeParseError<'a>);
133

            
134
#[cfg(feature = "parser")]
135
impl_display! { StyleListStyleTypeParseError<'a>, {
136
    InvalidValue(val) => format!("Invalid list-style-type value: \"{}\"", val),
137
}}
138

            
139
#[cfg(feature = "parser")]
140
#[derive(Debug, Clone, PartialEq)]
141
#[repr(C, u8)]
142
pub enum StyleListStyleTypeParseErrorOwned {
143
    InvalidValue(AzString),
144
}
145

            
146
#[cfg(feature = "parser")]
147
impl<'a> StyleListStyleTypeParseError<'a> {
148
    pub fn to_contained(&self) -> StyleListStyleTypeParseErrorOwned {
149
        match self {
150
            Self::InvalidValue(s) => StyleListStyleTypeParseErrorOwned::InvalidValue(s.to_string().into()),
151
        }
152
    }
153
}
154

            
155
#[cfg(feature = "parser")]
156
impl StyleListStyleTypeParseErrorOwned {
157
    pub fn to_shared<'a>(&'a self) -> StyleListStyleTypeParseError<'a> {
158
        match self {
159
            Self::InvalidValue(s) => StyleListStyleTypeParseError::InvalidValue(s.as_str()),
160
        }
161
    }
162
}
163

            
164
/// Parses a CSS `list-style-type` value from a string.
165
#[cfg(feature = "parser")]
166
pub fn parse_style_list_style_type<'a>(
167
    input: &'a str,
168
) -> Result<StyleListStyleType, StyleListStyleTypeParseError<'a>> {
169
    let input = input.trim();
170
    match input {
171
        "none" => Ok(StyleListStyleType::None),
172
        "disc" => Ok(StyleListStyleType::Disc),
173
        "circle" => Ok(StyleListStyleType::Circle),
174
        "square" => Ok(StyleListStyleType::Square),
175
        "decimal" => Ok(StyleListStyleType::Decimal),
176
        "decimal-leading-zero" => Ok(StyleListStyleType::DecimalLeadingZero),
177
        "lower-roman" => Ok(StyleListStyleType::LowerRoman),
178
        "upper-roman" => Ok(StyleListStyleType::UpperRoman),
179
        "lower-greek" => Ok(StyleListStyleType::LowerGreek),
180
        "upper-greek" => Ok(StyleListStyleType::UpperGreek),
181
        "lower-alpha" | "lower-latin" => Ok(StyleListStyleType::LowerAlpha),
182
        "upper-alpha" | "upper-latin" => Ok(StyleListStyleType::UpperAlpha),
183
        _ => Err(StyleListStyleTypeParseError::InvalidValue(input)),
184
    }
185
}
186

            
187
#[cfg(feature = "parser")]
188
#[derive(Clone, PartialEq)]
189
pub enum StyleListStylePositionParseError<'a> {
190
    InvalidValue(&'a str),
191
}
192

            
193
#[cfg(feature = "parser")]
194
impl_debug_as_display!(StyleListStylePositionParseError<'a>);
195

            
196
#[cfg(feature = "parser")]
197
impl_display! { StyleListStylePositionParseError<'a>, {
198
    InvalidValue(val) => format!("Invalid list-style-position value: \"{}\"", val),
199
}}
200

            
201
#[cfg(feature = "parser")]
202
#[derive(Debug, Clone, PartialEq)]
203
#[repr(C, u8)]
204
pub enum StyleListStylePositionParseErrorOwned {
205
    InvalidValue(AzString),
206
}
207

            
208
#[cfg(feature = "parser")]
209
impl<'a> StyleListStylePositionParseError<'a> {
210
    pub fn to_contained(&self) -> StyleListStylePositionParseErrorOwned {
211
        match self {
212
            Self::InvalidValue(s) => {
213
                StyleListStylePositionParseErrorOwned::InvalidValue(s.to_string().into())
214
            }
215
        }
216
    }
217
}
218

            
219
#[cfg(feature = "parser")]
220
impl StyleListStylePositionParseErrorOwned {
221
    pub fn to_shared<'a>(&'a self) -> StyleListStylePositionParseError<'a> {
222
        match self {
223
            Self::InvalidValue(s) => StyleListStylePositionParseError::InvalidValue(s.as_str()),
224
        }
225
    }
226
}
227

            
228
/// Parses a CSS `list-style-position` value from a string.
229
#[cfg(feature = "parser")]
230
pub fn parse_style_list_style_position<'a>(
231
    input: &'a str,
232
) -> Result<StyleListStylePosition, StyleListStylePositionParseError<'a>> {
233
    let input = input.trim();
234
    match input {
235
        "inside" => Ok(StyleListStylePosition::Inside),
236
        "outside" => Ok(StyleListStylePosition::Outside),
237
        _ => Err(StyleListStylePositionParseError::InvalidValue(input)),
238
    }
239
}