ferroui_markup/markup/parsers/
container_query_parser.rs1use super::{ContainerQueryGrammar, ContainerQuerySyntax};
5use ferroui_base::data::core::ExpressionParseException;
6use ferroui_base::styling::{StyleQueries, StyleQuery};
7use std::fmt;
8
9#[derive(Clone, Debug, PartialEq, Eq)]
12pub enum ContainerQueryParserError {
13 Parse(ExpressionParseException),
15 NotSupported(String),
18}
19
20impl fmt::Display for ContainerQueryParserError {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 match self {
23 ContainerQueryParserError::Parse(error) => error.fmt(f),
24 ContainerQueryParserError::NotSupported(message) => f.write_str(message),
25 }
26 }
27}
28
29impl std::error::Error for ContainerQueryParserError {}
30
31impl From<ExpressionParseException> for ContainerQueryParserError {
32 fn from(error: ExpressionParseException) -> Self {
33 ContainerQueryParserError::Parse(error)
34 }
35}
36
37#[derive(Clone, Copy, Debug, Default)]
39pub struct ContainerQueryParser;
40
41impl ContainerQueryParser {
42 pub fn new() -> Self {
44 Self
45 }
46
47 pub fn parse(&self, s: &str) -> Result<Option<StyleQuery>, ContainerQueryParserError> {
49 let syntax = ContainerQueryGrammar::parse(s)?;
50 self.create(&syntax)
51 }
52
53 fn create(&self, syntax: &[ContainerQuerySyntax]) -> Result<Option<StyleQuery>, ContainerQueryParserError> {
54 let mut result: Option<StyleQuery> = None;
55 let mut results: Option<Vec<StyleQuery>> = None;
56
57 for i in syntax {
58 match i {
59 ContainerQuerySyntax::Width { value, operator } => {
60 result = Some(StyleQueries::width(result, *operator, *value));
61 }
62 ContainerQuerySyntax::Height { value, operator } => {
63 result = Some(StyleQueries::height(result, *operator, *value));
64 }
65 ContainerQuerySyntax::Or | ContainerQuerySyntax::And => {
66 let query = result
67 .take()
68 .ok_or_else(|| ContainerQueryParserError::NotSupported("Invalid query!".to_string()))?;
69 results.get_or_insert_with(Vec::new).push(query);
70 }
71 }
72 }
73
74 if let Some(mut results) = results {
75 if let Some(result) = result.take() {
76 results.push(result);
77 }
78
79 result = if results.len() > 1 { Some(StyleQueries::or(results)) } else { results.into_iter().next() };
80 }
81
82 Ok(result)
83 }
84}