icydb_core/value/ops/
collection.rs1use crate::value::{Value, ops::text};
8
9fn normalize_list_ref(value: &Value) -> Vec<&Value> {
10 match value {
11 Value::List(values) => values.iter().collect(),
12 value => vec![value],
13 }
14}
15
16fn contains_by<F>(value: &Value, needle: &Value, eq: F) -> Option<bool>
17where
18 F: Fn(&Value, &Value) -> bool,
19{
20 value
21 .as_list()
22 .map(|items| items.iter().any(|item| eq(item, needle)))
23}
24
25#[expect(clippy::unnecessary_wraps)]
26fn contains_any_by<F>(value: &Value, needles: &Value, eq: F) -> Option<bool>
27where
28 F: Fn(&Value, &Value) -> bool,
29{
30 let needles = normalize_list_ref(needles);
31 match value {
32 Value::List(items) => Some(
33 needles
34 .iter()
35 .any(|needle| items.iter().any(|item| eq(item, needle))),
36 ),
37 scalar => Some(needles.iter().any(|needle| eq(scalar, needle))),
38 }
39}
40
41#[expect(clippy::unnecessary_wraps)]
42fn contains_all_by<F>(value: &Value, needles: &Value, eq: F) -> Option<bool>
43where
44 F: Fn(&Value, &Value) -> bool,
45{
46 let needles = normalize_list_ref(needles);
47 match value {
48 Value::List(items) => Some(
49 needles
50 .iter()
51 .all(|needle| items.iter().any(|item| eq(item, needle))),
52 ),
53 scalar => Some(needles.len() == 1 && eq(scalar, needles[0])),
54 }
55}
56
57fn in_list_by<F>(value: &Value, haystack: &Value, eq: F) -> Option<bool>
58where
59 F: Fn(&Value, &Value) -> bool,
60{
61 if let Value::List(items) = haystack {
62 Some(items.iter().any(|item| eq(item, value)))
63 } else {
64 None
65 }
66}
67
68#[must_use]
70pub const fn is_empty(value: &Value) -> Option<bool> {
71 match value {
72 Value::List(values) => Some(values.is_empty()),
73 Value::Map(entries) => Some(entries.is_empty()),
74 Value::Text(text) => Some(text.is_empty()),
75 Value::Blob(blob) => Some(blob.is_empty()),
76
77 Value::Null => Some(true),
79
80 _ => None,
81 }
82}
83
84#[must_use]
86pub fn is_not_empty(value: &Value) -> Option<bool> {
87 is_empty(value).map(|empty| !empty)
88}
89
90#[must_use]
92pub fn contains(value: &Value, needle: &Value) -> Option<bool> {
93 contains_by(value, needle, |left, right| left == right)
94}
95
96#[must_use]
98pub fn contains_any(value: &Value, needles: &Value) -> Option<bool> {
99 contains_any_by(value, needles, |left, right| left == right)
100}
101
102#[must_use]
104pub fn contains_all(value: &Value, needles: &Value) -> Option<bool> {
105 contains_all_by(value, needles, |left, right| left == right)
106}
107
108#[must_use]
110pub fn in_list(value: &Value, haystack: &Value) -> Option<bool> {
111 in_list_by(value, haystack, |left, right| left == right)
112}
113
114#[must_use]
116pub fn contains_ci(value: &Value, needle: &Value) -> Option<bool> {
117 match value {
118 Value::List(_) => contains_by(value, needle, text::eq_ci),
119 _ => Some(text::eq_ci(value, needle)),
120 }
121}
122
123#[must_use]
125pub fn contains_any_ci(value: &Value, needles: &Value) -> Option<bool> {
126 contains_any_by(value, needles, text::eq_ci)
127}
128
129#[must_use]
131pub fn contains_all_ci(value: &Value, needles: &Value) -> Option<bool> {
132 contains_all_by(value, needles, text::eq_ci)
133}
134
135#[must_use]
137pub fn in_list_ci(value: &Value, haystack: &Value) -> Option<bool> {
138 in_list_by(value, haystack, text::eq_ci)
139}
140
141impl Value {
142 #[must_use]
143 pub const fn is_empty(&self) -> Option<bool> {
144 is_empty(self)
145 }
146
147 #[must_use]
149 pub fn is_not_empty(&self) -> Option<bool> {
150 is_not_empty(self)
151 }
152
153 #[must_use]
155 pub fn contains(&self, needle: &Self) -> Option<bool> {
156 contains(self, needle)
157 }
158
159 #[must_use]
161 pub fn contains_any(&self, needles: &Self) -> Option<bool> {
162 contains_any(self, needles)
163 }
164
165 #[must_use]
167 pub fn contains_all(&self, needles: &Self) -> Option<bool> {
168 contains_all(self, needles)
169 }
170
171 #[must_use]
173 pub fn in_list(&self, haystack: &Self) -> Option<bool> {
174 in_list(self, haystack)
175 }
176
177 #[must_use]
179 pub fn contains_ci(&self, needle: &Self) -> Option<bool> {
180 contains_ci(self, needle)
181 }
182
183 #[must_use]
185 pub fn contains_any_ci(&self, needles: &Self) -> Option<bool> {
186 contains_any_ci(self, needles)
187 }
188
189 #[must_use]
191 pub fn contains_all_ci(&self, needles: &Self) -> Option<bool> {
192 contains_all_ci(self, needles)
193 }
194
195 #[must_use]
197 pub fn in_list_ci(&self, haystack: &Self) -> Option<bool> {
198 in_list_ci(self, haystack)
199 }
200}