icydb_core/value/ops/
text.rs1use crate::value::{TextMode, Value};
8use std::borrow::Cow;
9
10pub(crate) fn fold_ci(s: &str) -> Cow<'_, str> {
11 if s.is_ascii() {
12 return Cow::Owned(s.to_ascii_lowercase());
13 }
14 Cow::Owned(s.to_lowercase())
17}
18
19fn text_with_mode(s: &'_ str, mode: TextMode) -> Cow<'_, str> {
20 match mode {
21 TextMode::Cs => Cow::Borrowed(s),
22 TextMode::Ci => fold_ci(s),
23 }
24}
25
26fn text_op(
27 left: &Value,
28 right: &Value,
29 mode: TextMode,
30 f: impl Fn(&str, &str) -> bool,
31) -> Option<bool> {
32 let (a, b) = (left.as_text()?, right.as_text()?);
33 let a = text_with_mode(a, mode);
34 let b = text_with_mode(b, mode);
35 Some(f(&a, &b))
36}
37
38pub(crate) fn ci_key(value: &Value) -> Option<String> {
39 match value {
40 Value::Text(s) => Some(fold_ci(s).into_owned()),
41 Value::Ulid(u) => Some(u.to_string().to_ascii_lowercase()),
42 Value::Principal(p) => Some(p.to_string().to_ascii_lowercase()),
43 Value::Account(a) => Some(a.to_string().to_ascii_lowercase()),
44 _ => None,
45 }
46}
47
48pub(crate) fn eq_ci(left: &Value, right: &Value) -> bool {
49 if let (Some(left_key), Some(right_key)) = (ci_key(left), ci_key(right)) {
50 return left_key == right_key;
51 }
52
53 left == right
54}
55
56#[must_use]
58pub fn text_eq(left: &Value, right: &Value, mode: TextMode) -> Option<bool> {
59 text_op(left, right, mode, |a, b| a == b)
60}
61
62#[must_use]
64pub fn text_contains(value: &Value, needle: &Value, mode: TextMode) -> Option<bool> {
65 text_op(value, needle, mode, |a, b| a.contains(b))
66}
67
68#[must_use]
70pub fn text_starts_with(value: &Value, needle: &Value, mode: TextMode) -> Option<bool> {
71 text_op(value, needle, mode, |a, b| a.starts_with(b))
72}
73
74#[must_use]
76pub fn text_ends_with(value: &Value, needle: &Value, mode: TextMode) -> Option<bool> {
77 text_op(value, needle, mode, |a, b| a.ends_with(b))
78}
79
80impl Value {
81 #[must_use]
83 pub fn text_eq(&self, other: &Self, mode: TextMode) -> Option<bool> {
84 text_eq(self, other, mode)
85 }
86
87 #[must_use]
89 pub fn text_contains(&self, needle: &Self, mode: TextMode) -> Option<bool> {
90 text_contains(self, needle, mode)
91 }
92
93 #[must_use]
95 pub fn text_starts_with(&self, needle: &Self, mode: TextMode) -> Option<bool> {
96 text_starts_with(self, needle, mode)
97 }
98
99 #[must_use]
101 pub fn text_ends_with(&self, needle: &Self, mode: TextMode) -> Option<bool> {
102 text_ends_with(self, needle, mode)
103 }
104}