1use super::{Expr, ExprSet, Value};
11use assert_struct::Like;
12use uuid::Uuid;
13
14fn extract_exprs_from_record(expr: &Expr) -> Option<Vec<Expr>> {
16 match expr {
17 Expr::Value(Value::Record(record)) => {
18 Some(record.fields.iter().cloned().map(Into::into).collect())
19 }
20 Expr::Record(record) => Some(record.fields.clone()),
21 _ => None,
22 }
23}
24
25impl Like<Value> for Expr {
26 fn like(&self, other: &Value) -> bool {
27 match (self, other) {
28 (Expr::Value(value), rhs) => value == rhs,
29 (Expr::Record(lhs), Value::Record(rhs)) => {
30 lhs.len() == rhs.len()
31 && lhs
32 .fields
33 .iter()
34 .zip(rhs.fields.iter())
35 .all(|(lhs, rhs)| lhs.like(rhs))
36 }
37 _ => false,
38 }
39 }
40}
41
42impl Like<Vec<Value>> for Expr {
44 fn like(&self, pattern: &Vec<Value>) -> bool {
45 self.like(&&pattern[..])
46 }
47}
48
49impl<const N: usize> Like<[Value; N]> for Expr {
51 fn like(&self, pattern: &[Value; N]) -> bool {
52 self.like(&&pattern[..])
53 }
54}
55
56impl Like<&[Value]> for Expr {
57 fn like(&self, other: &&[Value]) -> bool {
58 if let Some(values) = extract_exprs_from_record(self) {
59 values.len() == other.len()
60 && values
61 .iter()
62 .zip(*other)
63 .all(|(value, expected)| value.like(expected))
64 } else {
65 false
66 }
67 }
68}
69
70impl Like<&str> for Value {
71 fn like(&self, pattern: &&str) -> bool {
72 matches!(self, Value::String(value) if value == pattern)
73 }
74}
75
76impl Like<&str> for Expr {
77 fn like(&self, pattern: &&str) -> bool {
78 matches!(self, Expr::Value(value) if value.like(pattern))
79 }
80}
81
82impl Like<&[u8]> for Value {
83 fn like(&self, pattern: &&[u8]) -> bool {
84 matches!(self, Value::Bytes(value) if value == pattern)
85 }
86}
87
88impl Like<&[u8]> for Expr {
89 fn like(&self, pattern: &&[u8]) -> bool {
90 matches!(self, Expr::Value(value) if value.like(pattern))
91 }
92}
93
94impl Like<String> for Value {
96 fn like(&self, pattern: &String) -> bool {
97 matches!(self, Value::String(s) if s == pattern)
98 }
99}
100
101impl Like<&String> for Value {
102 fn like(&self, pattern: &&String) -> bool {
103 self.like(&**pattern)
104 }
105}
106
107impl Like<String> for Expr {
109 fn like(&self, pattern: &String) -> bool {
110 self == pattern
111 }
112}
113
114impl Like<&String> for Expr {
115 fn like(&self, pattern: &&String) -> bool {
116 self == *pattern
117 }
118}
119
120impl Like<Uuid> for Value {
121 fn like(&self, other: &Uuid) -> bool {
122 matches!(self, Value::Uuid(value) if value == other)
123 }
124}
125
126impl Like<Uuid> for Expr {
127 fn like(&self, other: &Uuid) -> bool {
128 matches!(self, Expr::Value(value) if value.like(other))
129 }
130}
131
132macro_rules! impl_like_tuple {
137 ($($idx:tt $t:ident),+) => {
138 #[allow(non_snake_case)]
139 impl<$($t),+> Like<($($t,)+)> for Expr
140 where
141 $(Expr: Like<$t>),+
142 {
143 fn like(&self, pattern: &($($t,)+)) -> bool {
144 if let Some(exprs) = extract_exprs_from_record(self) {
145 exprs.len() == impl_like_tuple!(@count $($t)+) && $(
146 exprs[$idx].like(&pattern.$idx)
147 )&&+
148 } else {
149 false
150 }
151 }
152 }
153
154 #[allow(non_snake_case)]
155 impl<$($t),+> Like<($($t,)+)> for Value
156 where
157 $(Value: Like<$t>),+
158 {
159 fn like(&self, pattern: &($($t,)+)) -> bool {
160 if let Value::Record(record) = self {
161 record.fields.len() == impl_like_tuple!(@count $($t)+) && $(
162 record.fields[$idx].like(&pattern.$idx)
163 )&&+
164 } else {
165 false
166 }
167 }
168 }
169 };
170
171 (@count $t:ident) => (1);
173 (@count $t:ident $($ts:ident)+) => (1 + impl_like_tuple!(@count $($ts)+));
174}
175
176impl_like_tuple!(0 T1);
179impl_like_tuple!(0 T1, 1 T2);
180impl_like_tuple!(0 T1, 1 T2, 2 T3);
181impl_like_tuple!(0 T1, 1 T2, 2 T3, 3 T4);
182impl_like_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5);
183impl_like_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6);
184impl_like_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7);
185impl_like_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8);
186impl_like_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9);
187impl_like_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9, 9 T10);
188impl_like_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9, 9 T10, 10 T11);
189impl_like_tuple!(0 T1, 1 T2, 2 T3, 3 T4, 4 T5, 5 T6, 6 T7, 7 T8, 8 T9, 9 T10, 10 T11, 11 T12);
190
191impl<T, const N: usize> Like<[T; N]> for ExprSet
193where
194 Expr: Like<T>,
195{
196 fn like(&self, pattern: &[T; N]) -> bool {
197 match self {
198 ExprSet::Values(values) => {
199 values.rows.len() == N
200 && values
201 .rows
202 .iter()
203 .zip(pattern)
204 .all(|(expr, p)| expr.like(p))
205 }
206 _ => false,
207 }
208 }
209}
210
211impl<T> Like<Vec<T>> for ExprSet
213where
214 Expr: Like<T>,
215{
216 fn like(&self, pattern: &Vec<T>) -> bool {
217 match self {
218 ExprSet::Values(values) => {
219 values.rows.len() == pattern.len()
220 && values
221 .rows
222 .iter()
223 .zip(pattern)
224 .all(|(expr, p)| expr.like(p))
225 }
226 _ => false,
227 }
228 }
229}
230
231impl<const N: usize> Like<[&str; N]> for Expr {
232 fn like(&self, other: &[&str; N]) -> bool {
233 match self {
234 Expr::Value(Value::Record(v)) if v.len() == other.len() => {
235 v.iter().zip(other.iter()).all(|(lhs, rhs)| lhs.like(rhs))
236 }
237 Expr::Record(v) if v.len() == other.len() => {
238 v.iter().zip(other.iter()).all(|(lhs, rhs)| lhs.like(rhs))
239 }
240 _ => false,
241 }
242 }
243}
244
245impl<const N: usize> Like<&[u8; N]> for Expr {
246 fn like(&self, other: &&[u8; N]) -> bool {
247 self.like(&&other[..])
248 }
249}