matugen_parser/filters/
helpers.rs1use colorsys::{Hsl, Rgb};
2
3use crate::Value;
4
5#[cfg(feature = "filter-docs")]
6#[derive(Debug, Clone)]
7pub struct FilterDoc {
8 pub name: &'static str,
9 pub category: &'static str,
10 pub description: &'static str,
11}
12
13#[cfg(feature = "filter-docs")]
14use std::sync::{Mutex, OnceLock};
15
16#[cfg(feature = "filter-docs")]
17pub static FILTER_DOCS: OnceLock<Mutex<Vec<FilterDoc>>> = OnceLock::new();
18
19#[cfg(feature = "filter-docs")]
20pub fn filter_docs() -> Vec<FilterDoc> {
21 FILTER_DOCS
22 .get_or_init(|| Mutex::new(Vec::new()))
23 .lock()
24 .unwrap()
25 .clone()
26}
27
28#[cfg(feature = "filter-docs")]
29#[macro_export]
30macro_rules! __register_filter_doc {
31 ($name:expr, $category:expr, $doc:expr) => {{
32 $crate::parser::helpers::FILTER_DOCS
33 .get_or_init(|| std::sync::Mutex::new(Vec::new()))
34 .lock()
35 .unwrap()
36 .push($crate::parser::helpers::FilterDoc {
37 name: $name,
38 category: $category,
39 description: $doc,
40 });
41 }};
42}
43
44#[cfg(not(feature = "filter-docs"))]
45#[macro_export]
46macro_rules! __register_filter_doc {
47 ($name:expr, $category:expr, $doc:expr) => {};
48}
49
50#[macro_export]
51macro_rules! register_filters {
52 (($engine:expr) {
53 $(
54 $category:literal => {
55 $(
56 $(#[doc = $doc:literal])*
57 $name:literal => $func:path
58 ),* $(,)?
59 }
60 ),* $(,)?
61 }) => {{
62 $(
63 $(
64 $engine.add_filter($name, $func);
65
66 $crate::__register_filter_doc!(
67 $name,
68 $category,
69 concat!($($doc, "\n"),*)
70 );
71 )*
72 )*
73 }};
74}
75
76#[cfg(feature = "filter-docs")]
94pub fn filters_to_html() -> String {
95 use std::collections::BTreeMap;
96
97 let mut grouped: BTreeMap<&str, Vec<&FilterDoc>> = BTreeMap::new();
98 let docs = filter_docs();
99
100 for doc in docs.iter() {
101 grouped.entry(doc.category).or_default().push(doc);
102 }
103
104 let mut out = String::new();
105
106 for (category, docs) in grouped {
107 out.push_str(&format!("<h2>{}</h2><md-divider></md-divider>\n", category));
108
109 for doc in docs {
110 out.push_str(&format!(
111 "<div class='filter-doc'>
112 <h3>{}</h3>
113 {}
114</div>\n",
115 doc.name, doc.description
116 ));
117 }
118 }
119
120 out
121}
122
123#[macro_export]
124macro_rules! expect_args {
125 ($args:expr, $( $ty:ty ),* $(,)?) => {{
126 let expected_len = [$(
127 stringify!($ty)
128 ),*].len();
129 if $args.len() < expected_len {
130 return Err(
131 $crate::FilterError::NotEnoughArguments,
132 );
133 }
134
135 let mut _i = 0;
136 (
137 $(
138 {
139 let spanned = &$args[_i];
140 _i += 1;
141 match <$ty as $crate::helpers::ExpectFromValue>::expect_from(&spanned.value) {
142 Ok(v) => v,
143 Err(actual) => {
144 return Err(
145 $crate::FilterError::InvalidArgumentType {
146 span: spanned.span,
147 expected: stringify!($ty).to_string(),
148 actual,
149 }
150 )
151 }}
152 }
153 ),*
154 )
155 }};
156}
157
158pub trait ExpectFromValue: Sized {
159 fn expect_from(value: &Value) -> Result<Self, String>;
160}
161
162impl ExpectFromValue for String {
163 fn expect_from(value: &Value) -> Result<Self, String> {
164 match value {
165 Value::Ident(s) => Ok(s.clone()),
166 other => Err(other.variant_name()),
167 }
168 }
169}
170
171impl ExpectFromValue for i64 {
172 fn expect_from(value: &Value) -> Result<Self, String> {
173 match value {
174 Value::Int(i) => Ok(*i),
175 other => Err(other.variant_name()),
176 }
177 }
178}
179
180impl ExpectFromValue for f64 {
181 fn expect_from(value: &Value) -> Result<Self, String> {
182 match value {
183 Value::Float(f) => Ok(*f),
184 Value::Int(i) => Ok(*i as f64),
185 other => Err(other.variant_name()),
186 }
187 }
188}
189
190impl ExpectFromValue for Rgb {
191 fn expect_from(value: &Value) -> Result<Self, String> {
192 match value {
193 Value::Color(color) => Ok(color.clone()),
194 Value::LazyColor { color, scheme: _ } => Ok(color.clone()),
195 other => Err(other.variant_name()),
196 }
197 }
198}
199
200impl ExpectFromValue for Hsl {
201 fn expect_from(value: &Value) -> Result<Self, String> {
202 match value {
203 Value::HslColor(color) => Ok(color.clone()),
204 other => Err(other.variant_name()),
205 }
206 }
207}