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