azul_css/props/style/
content.rs1use alloc::string::{String, ToString};
4
5use crate::{corety::AzString, props::formatter::PrintAsCssValue};
6
7#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
11#[repr(C)]
12pub struct Content {
13 pub inner: AzString,
14}
15
16impl Default for Content {
17 fn default() -> Self {
18 Self {
19 inner: "normal".into(),
20 }
21 }
22}
23
24impl PrintAsCssValue for Content {
25 fn print_as_css_value(&self) -> String {
26 self.inner.as_str().to_string()
27 }
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
32#[repr(C)]
33pub struct CounterReset {
34 pub counter_name: AzString,
35 pub value: i32,
36}
37
38impl CounterReset {
39 pub const fn new(counter_name: AzString, value: i32) -> Self {
40 Self {
41 counter_name,
42 value,
43 }
44 }
45
46 pub const fn none() -> Self {
47 Self {
48 counter_name: AzString::from_const_str("none"),
49 value: 0,
50 }
51 }
52
53 pub const fn list_item() -> Self {
54 Self {
55 counter_name: AzString::from_const_str("list-item"),
56 value: 0,
57 }
58 }
59}
60
61impl Default for CounterReset {
62 fn default() -> Self {
63 Self::none()
64 }
65}
66
67impl PrintAsCssValue for CounterReset {
68 fn print_as_css_value(&self) -> String {
69 if self.counter_name.as_str() == "none" {
70 "none".to_string()
71 } else {
72 alloc::format!("{} {}", self.counter_name.as_str(), self.value)
73 }
74 }
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
79#[repr(C)]
80pub struct CounterIncrement {
81 pub counter_name: AzString,
82 pub value: i32,
83}
84
85impl CounterIncrement {
86 pub const fn new(counter_name: AzString, value: i32) -> Self {
87 Self {
88 counter_name,
89 value,
90 }
91 }
92
93 pub const fn none() -> Self {
94 Self {
95 counter_name: AzString::from_const_str("none"),
96 value: 0,
97 }
98 }
99
100 pub const fn list_item() -> Self {
101 Self {
102 counter_name: AzString::from_const_str("list-item"),
103 value: 1,
104 }
105 }
106}
107
108impl Default for CounterIncrement {
109 fn default() -> Self {
110 Self::none()
111 }
112}
113
114impl PrintAsCssValue for CounterIncrement {
115 fn print_as_css_value(&self) -> String {
116 if self.counter_name.as_str() == "none" {
117 "none".to_string()
118 } else {
119 alloc::format!("{} {}", self.counter_name.as_str(), self.value)
120 }
121 }
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
125#[repr(C)]
126pub struct StringSet {
127 pub inner: AzString,
128}
129impl Default for StringSet {
130 fn default() -> Self {
131 Self {
132 inner: "none".into(),
133 }
134 }
135}
136impl PrintAsCssValue for StringSet {
137 fn print_as_css_value(&self) -> String {
138 self.inner.as_str().to_string()
139 }
140}
141
142impl crate::format_rust_code::FormatAsRustCode for Content {
144 fn format_as_rust_code(&self, _tabs: usize) -> String {
145 format!("Content {{ inner: String::from({:?}) }}", self.inner)
146 }
147}
148
149impl crate::format_rust_code::FormatAsRustCode for CounterReset {
150 fn format_as_rust_code(&self, _tabs: usize) -> String {
151 alloc::format!(
152 "CounterReset {{ counter_name: AzString::from_const_str({:?}), value: {} }}",
153 self.counter_name.as_str(),
154 self.value
155 )
156 }
157}
158
159impl crate::format_rust_code::FormatAsRustCode for CounterIncrement {
160 fn format_as_rust_code(&self, _tabs: usize) -> String {
161 alloc::format!(
162 "CounterIncrement {{ counter_name: AzString::from_const_str({:?}), value: {} }}",
163 self.counter_name.as_str(),
164 self.value
165 )
166 }
167}
168
169impl crate::format_rust_code::FormatAsRustCode for StringSet {
170 fn format_as_rust_code(&self, _tabs: usize) -> String {
171 format!("StringSet {{ inner: String::from({:?}) }}", self.inner)
172 }
173}
174
175#[cfg(feature = "parser")]
178mod parser {
179 use super::*;
180
181 pub fn parse_content(input: &str) -> Result<Content, ()> {
183 Ok(Content {
184 inner: input.trim().into(),
185 })
186 }
187
188 pub fn parse_counter_reset(input: &str) -> Result<CounterReset, ()> {
189 let trimmed = input.trim();
190
191 if trimmed == "none" {
192 return Ok(CounterReset::none());
193 }
194
195 let parts: Vec<&str> = trimmed.split_whitespace().collect();
198
199 if parts.is_empty() {
200 return Err(());
201 }
202
203 let counter_name = parts[0].into();
204 let value = if parts.len() > 1 {
205 parts[1].parse::<i32>().map_err(|_| ())?
206 } else {
207 0 };
209
210 Ok(CounterReset::new(counter_name, value))
211 }
212
213 pub fn parse_counter_increment(input: &str) -> Result<CounterIncrement, ()> {
214 let trimmed = input.trim();
215
216 if trimmed == "none" {
217 return Ok(CounterIncrement::none());
218 }
219
220 let parts: Vec<&str> = trimmed.split_whitespace().collect();
223
224 if parts.is_empty() {
225 return Err(());
226 }
227
228 let counter_name = parts[0].into();
229 let value = if parts.len() > 1 {
230 parts[1].parse::<i32>().map_err(|_| ())?
231 } else {
232 1 };
234
235 Ok(CounterIncrement::new(counter_name, value))
236 }
237
238 pub fn parse_string_set(input: &str) -> Result<StringSet, ()> {
239 Ok(StringSet {
240 inner: input.trim().into(),
241 })
242 }
243}
244
245#[cfg(feature = "parser")]
246pub use parser::*;
247
248#[cfg(all(test, feature = "parser"))]
249mod tests {
250 use super::*;
251
252 #[test]
253 fn test_simple_content_parser() {
254 assert_eq!(parse_content("'Hello'").unwrap().inner.as_str(), "'Hello'");
255
256 let reset = parse_counter_reset("page 1").unwrap();
258 assert_eq!(reset.counter_name.as_str(), "page");
259 assert_eq!(reset.value, 1);
260
261 let reset = parse_counter_reset("list-item 0").unwrap();
262 assert_eq!(reset.counter_name.as_str(), "list-item");
263 assert_eq!(reset.value, 0);
264
265 let reset = parse_counter_reset("none").unwrap();
266 assert_eq!(reset.counter_name.as_str(), "none");
267
268 let inc = parse_counter_increment("section").unwrap();
270 assert_eq!(inc.counter_name.as_str(), "section");
271 assert_eq!(inc.value, 1); let inc = parse_counter_increment("list-item 2").unwrap();
274 assert_eq!(inc.counter_name.as_str(), "list-item");
275 assert_eq!(inc.value, 2);
276
277 assert_eq!(
278 parse_string_set("chapter-title content()")
279 .unwrap()
280 .inner
281 .as_str(),
282 "chapter-title content()"
283 );
284 }
285}