spreadsheet_ods/
condition.rs1use get_size::GetSize;
4use get_size_derive::GetSize;
5use std::fmt::{Display, Formatter};
6
7use crate::CellRange;
8
9#[derive(Clone, Debug)]
11pub struct Value {
12 val: String,
13}
14
15fn quote(val: &str) -> String {
16 let mut buf = String::new();
17 buf.push('"');
18 for c in val.chars() {
19 if c == '"' {
20 buf.push('"');
21 buf.push('"');
22 } else {
23 buf.push(c);
24 }
25 }
26 buf.push('"');
27 buf
28}
29
30impl Display for Value {
31 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
32 write!(f, "{}", self.val)
33 }
34}
35
36impl From<&str> for Value {
37 fn from(s: &str) -> Self {
38 Value { val: quote(s) }
39 }
40}
41
42impl From<&&str> for Value {
43 fn from(s: &&str) -> Self {
44 Value { val: quote(s) }
45 }
46}
47
48impl From<String> for Value {
49 fn from(s: String) -> Self {
50 Value {
51 val: quote(s.as_str()),
52 }
53 }
54}
55
56impl From<&String> for Value {
57 fn from(s: &String) -> Self {
58 Value {
59 val: quote(s.as_str()),
60 }
61 }
62}
63
64macro_rules! from_x_conditionvalue {
65 ($int:ty) => {
66 impl From<$int> for Value {
67 fn from(v: $int) -> Self {
68 Value { val: v.to_string() }
69 }
70 }
71
72 impl From<&$int> for Value {
73 fn from(v: &$int) -> Self {
74 Value { val: v.to_string() }
75 }
76 }
77 };
78}
79
80from_x_conditionvalue!(i8);
81from_x_conditionvalue!(i16);
82from_x_conditionvalue!(i32);
83from_x_conditionvalue!(i64);
84from_x_conditionvalue!(u8);
85from_x_conditionvalue!(u16);
86from_x_conditionvalue!(u32);
87from_x_conditionvalue!(u64);
88from_x_conditionvalue!(f32);
89from_x_conditionvalue!(f64);
90from_x_conditionvalue!(bool);
91
92#[derive(Default, Clone, Debug, GetSize)]
94pub struct ValueCondition {
95 cond: String,
96}
97
98impl Display for ValueCondition {
99 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
100 write!(f, "{}", self.cond)
101 }
102}
103
104impl ValueCondition {
105 pub(crate) fn new<S: Into<String>>(str: S) -> Self {
107 Self { cond: str.into() }
108 }
109
110 pub fn value_eq<V: Into<Value>>(value: V) -> ValueCondition {
112 let mut buf = String::new();
113 buf.push_str("value()=");
114 buf.push_str(value.into().to_string().as_str());
115 ValueCondition { cond: buf }
116 }
117
118 pub fn value_ne<V: Into<Value>>(value: V) -> ValueCondition {
120 let mut buf = String::new();
121 buf.push_str("value()!=");
122 buf.push_str(value.into().to_string().as_str());
123 ValueCondition { cond: buf }
124 }
125
126 pub fn value_lt<V: Into<Value>>(value: V) -> ValueCondition {
128 let mut buf = String::new();
129 buf.push_str("value()<");
130 buf.push_str(value.into().to_string().as_str());
131 ValueCondition { cond: buf }
132 }
133
134 pub fn value_gt<V: Into<Value>>(value: V) -> ValueCondition {
136 let mut buf = String::new();
137 buf.push_str("value()>");
138 buf.push_str(value.into().to_string().as_str());
139 ValueCondition { cond: buf }
140 }
141
142 pub fn value_le<V: Into<Value>>(value: V) -> ValueCondition {
144 let mut buf = String::new();
145 buf.push_str("value()<=");
146 buf.push_str(value.into().to_string().as_str());
147 ValueCondition { cond: buf }
148 }
149
150 pub fn value_ge<V: Into<Value>>(value: V) -> ValueCondition {
152 let mut buf = String::new();
153 buf.push_str("value()>=");
154 buf.push_str(value.into().to_string().as_str());
155 ValueCondition { cond: buf }
156 }
157}
158
159#[derive(Default, Clone, Debug, GetSize)]
161pub struct Condition {
162 cond: String,
163}
164
165impl Display for Condition {
166 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
167 write!(f, "{}", self.cond)
168 }
169}
170
171impl Condition {
172 pub(crate) fn new<S: Into<String>>(str: S) -> Self {
174 Self { cond: str.into() }
175 }
176
177 pub fn content_eq<V: Into<Value>>(value: V) -> Condition {
179 let mut buf = String::new();
180 buf.push_str("cell-content()=");
181 buf.push_str(value.into().to_string().as_str());
182 Condition { cond: buf }
183 }
184
185 pub fn content_ne<V: Into<Value>>(value: V) -> Condition {
187 let mut buf = String::new();
188 buf.push_str("cell-content()!=");
189 buf.push_str(value.into().to_string().as_str());
190 Condition { cond: buf }
191 }
192
193 pub fn content_lt<V: Into<Value>>(value: V) -> Condition {
195 let mut buf = String::new();
196 buf.push_str("cell-content()<");
197 buf.push_str(value.into().to_string().as_str());
198 Condition { cond: buf }
199 }
200
201 pub fn content_gt<V: Into<Value>>(value: V) -> Condition {
203 let mut buf = String::new();
204 buf.push_str("cell-content()>");
205 buf.push_str(value.into().to_string().as_str());
206 Condition { cond: buf }
207 }
208
209 pub fn content_le<V: Into<Value>>(value: V) -> Condition {
211 let mut buf = String::new();
212 buf.push_str("cell-content()<=");
213 buf.push_str(value.into().to_string().as_str());
214 Condition { cond: buf }
215 }
216
217 pub fn content_ge<V: Into<Value>>(value: V) -> Condition {
219 let mut buf = String::new();
220 buf.push_str("cell-content()>=");
221 buf.push_str(value.into().to_string().as_str());
222 Condition { cond: buf }
223 }
224
225 pub fn content_text_length_eq(len: u32) -> Condition {
227 let mut buf = String::new();
228 buf.push_str("cell-content-text-length()=");
229 buf.push_str(len.to_string().as_str());
230 Condition { cond: buf }
231 }
232
233 pub fn content_text_length_ne(len: u32) -> Condition {
235 let mut buf = String::new();
236 buf.push_str("cell-content-text-length()!=");
237 buf.push_str(len.to_string().as_str());
238 Condition { cond: buf }
239 }
240
241 pub fn content_text_length_lt(len: u32) -> Condition {
243 let mut buf = String::new();
244 buf.push_str("cell-content-text-length()<");
245 buf.push_str(len.to_string().as_str());
246 Condition { cond: buf }
247 }
248
249 pub fn content_text_length_gt(len: u32) -> Condition {
251 let mut buf = String::new();
252 buf.push_str("cell-content-text-length()>");
253 buf.push_str(len.to_string().as_str());
254 Condition { cond: buf }
255 }
256
257 pub fn content_text_length_le(len: u32) -> Condition {
259 let mut buf = String::new();
260 buf.push_str("cell-content-text-length()<=");
261 buf.push_str(len.to_string().as_str());
262 Condition { cond: buf }
263 }
264
265 pub fn content_text_length_ge(len: u32) -> Condition {
267 let mut buf = String::new();
268 buf.push_str("cell-content-text-length()>=");
269 buf.push_str(len.to_string().as_str());
270 Condition { cond: buf }
271 }
272
273 pub fn content_text_length_is_between(from: u32, to: u32) -> Condition {
275 let mut buf = String::new();
276 buf.push_str("cell-content-text-length-is-between(");
277 buf.push_str(from.to_string().as_str());
278 buf.push_str(", ");
279 buf.push_str(to.to_string().as_str());
280 buf.push(')');
281 Condition { cond: buf }
282 }
283
284 pub fn content_text_length_is_not_between(from: u32, to: u32) -> Condition {
286 let mut buf = String::new();
287 buf.push_str("cell-content-text-length-is-not-between(");
288 buf.push_str(from.to_string().as_str());
289 buf.push_str(", ");
290 buf.push_str(to.to_string().as_str());
291 buf.push(')');
292 Condition { cond: buf }
293 }
294
295 pub fn content_is_in_list<'a, V>(list: &'a [V]) -> Condition
297 where
298 Value: From<&'a V>,
299 {
300 let mut buf = String::new();
301 buf.push_str("cell-content-is-in-list(");
302
303 let mut sep = false;
304 for v in list {
305 if sep {
306 buf.push(';');
307 }
308 let vv: Value = v.into();
309 let vstr = vv.to_string();
310 if !vstr.starts_with('"') {
311 buf.push('"');
312 }
313 buf.push_str(vstr.as_str());
314 if !vstr.starts_with('"') {
315 buf.push('"');
316 }
317 sep = true;
318 }
319
320 buf.push(')');
321 Condition { cond: buf }
322 }
323
324 pub fn content_is_in_cellrange(range: CellRange) -> Condition {
332 let mut buf = String::new();
333 buf.push_str("cell-content-is-in-list(");
334 buf.push_str(range.to_formula().as_str());
335 buf.push(')');
336 Condition { cond: buf }
337 }
338
339 pub fn content_is_date_and(vcond: Condition) -> Condition {
343 let mut buf = String::new();
344 buf.push_str("cell-content-is-date()");
345 buf.push_str(" and ");
346 buf.push_str(vcond.to_string().as_str());
347 Condition { cond: buf }
348 }
349
350 pub fn content_is_time_and(vcond: Condition) -> Condition {
353 let mut buf = String::new();
354 buf.push_str("cell-content-is-time()");
355 buf.push_str(" and ");
356 buf.push_str(vcond.to_string().as_str());
357 Condition { cond: buf }
358 }
359
360 pub fn content_is_decimal_number_and(vcond: Condition) -> Condition {
362 let mut buf = String::new();
363 buf.push_str("cell-content-is-decimal-number()");
364 buf.push_str(" and ");
365 buf.push_str(vcond.to_string().as_str());
366 Condition { cond: buf }
367 }
368
369 pub fn content_is_whole_number_and(vcond: Condition) -> Condition {
371 let mut buf = String::new();
372 buf.push_str("cell-content-is-whole-number()");
373 buf.push_str(" and ");
374 buf.push_str(vcond.to_string().as_str());
375 Condition { cond: buf }
376 }
377
378 pub fn is_true_formula<S: AsRef<str>>(formula: S) -> Condition {
380 let mut buf = String::new();
381 buf.push_str("is-true-formula(");
382 buf.push_str(formula.as_ref());
383 buf.push(')');
384 Condition { cond: buf }
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use crate::condition::{Condition, ValueCondition};
391 use crate::CellRange;
392
393 #[test]
394 fn test_valuecondition() {
395 let c = ValueCondition::value_eq(5);
396 assert_eq!(c.to_string(), "value()=5");
397 let c = ValueCondition::value_ne(5);
398 assert_eq!(c.to_string(), "value()!=5");
399 let c = ValueCondition::value_lt(5);
400 assert_eq!(c.to_string(), "value()<5");
401 let c = ValueCondition::value_gt(5);
402 assert_eq!(c.to_string(), "value()>5");
403 let c = ValueCondition::value_le(5);
404 assert_eq!(c.to_string(), "value()<=5");
405 let c = ValueCondition::value_ge(5);
406 assert_eq!(c.to_string(), "value()>=5");
407 }
408
409 #[test]
410 fn test_condition() {
411 let c = Condition::content_text_length_eq(7);
412 assert_eq!(c.to_string(), "cell-content-text-length()=7");
413 let c = Condition::content_text_length_is_between(5, 7);
414 assert_eq!(c.to_string(), "cell-content-text-length-is-between(5, 7)");
415 let c = Condition::content_text_length_is_not_between(5, 7);
416 assert_eq!(
417 c.to_string(),
418 "cell-content-text-length-is-not-between(5, 7)"
419 );
420 let c = Condition::content_is_in_list(&[1, 2, 3, 4, 5]);
421 assert_eq!(
422 c.to_string(),
423 r#"cell-content-is-in-list("1";"2";"3";"4";"5")"#
424 );
425 let c = Condition::content_is_in_list(&["a", "b", "c"]);
426 assert_eq!(c.to_string(), r#"cell-content-is-in-list("a";"b";"c")"#);
427 let c = Condition::content_is_in_cellrange(CellRange::remote("other", 0, 0, 10, 0));
428 assert_eq!(c.to_string(), "cell-content-is-in-list([other.A1:.A11])");
429
430 let c = Condition::content_is_date_and(Condition::content_eq(0));
431 assert_eq!(c.to_string(), "cell-content-is-date() and cell-content()=0");
432 let c = Condition::content_is_time_and(Condition::content_eq(0));
433 assert_eq!(c.to_string(), "cell-content-is-time() and cell-content()=0");
434 let c = Condition::content_is_decimal_number_and(Condition::content_eq(0));
435 assert_eq!(
436 c.to_string(),
437 "cell-content-is-decimal-number() and cell-content()=0"
438 );
439 let c = Condition::content_is_whole_number_and(Condition::content_eq(0));
440 assert_eq!(
441 c.to_string(),
442 "cell-content-is-whole-number() and cell-content()=0"
443 );
444
445 let c = Condition::is_true_formula("formula");
446 assert_eq!(c.to_string(), "is-true-formula(formula)");
447 }
448}