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