1use core::{fmt::Debug, hash::Hash};
3
4use alloc::vec::Vec;
5
6use crate::encoding::Value;
7
8pub trait DynTable: Debug + Eq + Clone + PartialEq {
12 fn name(&self) -> &str;
14
15 fn number_of_columns(&self) -> usize;
17
18 fn write_pk_flags(&self, buf: &mut [u8]);
33}
34
35impl<T: DynTable> DynTable for &T {
36 #[inline]
37 fn name(&self) -> &str {
38 T::name(self)
39 }
40
41 #[inline]
42 fn number_of_columns(&self) -> usize {
43 T::number_of_columns(self)
44 }
45
46 #[inline]
47 fn write_pk_flags(&self, buf: &mut [u8]) {
48 T::write_pk_flags(self, buf);
49 }
50}
51
52pub(crate) trait IndexableValues {
54 type Text: Clone;
56 type Binary: Clone;
58
59 fn get(&self, col_idx: usize) -> Option<Value<Self::Text, Self::Binary>>;
69}
70
71impl<S: Clone, B: Clone> IndexableValues for Vec<Value<S, B>> {
72 type Text = S;
73 type Binary = B;
74
75 #[inline]
76 fn get(&self, col_idx: usize) -> Option<Value<Self::Text, Self::Binary>> {
77 <&[Value<S, B>]>::get(&self.as_slice(), col_idx)
78 }
79}
80
81impl<S: Clone, B: Clone> IndexableValues for &[Value<S, B>] {
82 type Text = S;
83 type Binary = B;
84
85 #[inline]
86 fn get(&self, col_idx: usize) -> Option<Value<Self::Text, Self::Binary>> {
87 <[Value<S, B>]>::get(self, col_idx).cloned()
88 }
89}
90
91impl<S: Clone, B: Clone> IndexableValues for Vec<Option<Value<S, B>>> {
92 type Text = S;
93 type Binary = B;
94
95 #[inline]
96 fn get(&self, col_idx: usize) -> Option<Value<Self::Text, Self::Binary>> {
97 <&[Option<Value<S, B>>]>::get(&self.as_slice(), col_idx)
98 }
99}
100
101impl<S: Clone, B: Clone> IndexableValues for &[Option<Value<S, B>>] {
102 type Text = S;
103 type Binary = B;
104
105 #[inline]
106 fn get(&self, col_idx: usize) -> Option<Value<Self::Text, Self::Binary>> {
107 <[Option<Value<S, B>>]>::get(self, col_idx).map(|v| {
108 if let Some(value) = v {
109 value.clone()
110 } else {
111 Value::Null
112 }
113 })
114 }
115}
116
117impl<O, S: Clone, B: Clone> IndexableValues for Vec<(O, Option<Value<S, B>>)> {
118 type Text = S;
119 type Binary = B;
120
121 #[inline]
122 fn get(&self, col_idx: usize) -> Option<Value<Self::Text, Self::Binary>> {
123 <&[(O, Option<Value<S, B>>)]>::get(&self.as_slice(), col_idx)
124 }
125}
126
127impl<O, S: Clone, B: Clone> IndexableValues for &[(O, Option<Value<S, B>>)] {
128 type Text = S;
129 type Binary = B;
130
131 #[inline]
132 fn get(&self, col_idx: usize) -> Option<Value<Self::Text, Self::Binary>> {
133 <[(O, Option<Value<S, B>>)]>::get(self, col_idx).map(|(_old, new)| {
134 if let Some(value) = new {
135 value.clone()
136 } else {
137 Value::Null
138 }
139 })
140 }
141}
142
143pub trait SchemaWithPK: DynTable + Clone + Hash {
155 fn number_of_primary_keys(&self) -> usize;
157
158 fn primary_key_index(&self, col_idx: usize) -> Option<usize>;
160
161 fn extract_pk<S: Clone, B: Clone>(
170 &self,
171 values: &impl IndexableValues<Text = S, Binary = B>,
172 ) -> alloc::vec::Vec<Value<S, B>>;
173}
174
175impl<T: SchemaWithPK> SchemaWithPK for &T {
176 fn number_of_primary_keys(&self) -> usize {
177 T::number_of_primary_keys(self)
178 }
179
180 fn primary_key_index(&self, col_idx: usize) -> Option<usize> {
181 T::primary_key_index(self, col_idx)
182 }
183
184 fn extract_pk<S: Clone, B: Clone>(
185 &self,
186 values: &impl IndexableValues<Text = S, Binary = B>,
187 ) -> alloc::vec::Vec<Value<S, B>> {
188 T::extract_pk(self, values)
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::{DynTable, IndexableValues, SchemaWithPK};
195 use crate::encoding::Value;
196 use crate::schema::SimpleTable;
197 use alloc::string::String;
198 use alloc::vec;
199 use alloc::vec::Vec;
200
201 fn users() -> SimpleTable {
202 SimpleTable::new("users", &["id", "name", "email"], &[0, 2])
203 }
204
205 #[test]
206 fn test_dyntable_ref_forwards() {
207 let t = users();
208 let r: &SimpleTable = &t;
209 assert_eq!(<&SimpleTable as DynTable>::name(&r), t.name());
210 assert_eq!(
211 <&SimpleTable as DynTable>::number_of_columns(&r),
212 t.number_of_columns()
213 );
214 let mut buf_ref = [0u8; 3];
215 let mut buf_direct = [0u8; 3];
216 <&SimpleTable as DynTable>::write_pk_flags(&r, &mut buf_ref);
217 t.write_pk_flags(&mut buf_direct);
218 assert_eq!(buf_ref, buf_direct);
219 }
220
221 #[test]
222 fn test_schema_with_pk_ref_forwards() {
223 let t = users();
224 let r: &SimpleTable = &t;
225 assert_eq!(
226 <&SimpleTable as SchemaWithPK>::number_of_primary_keys(&r),
227 t.number_of_primary_keys()
228 );
229 for idx in 0..t.number_of_columns() {
230 assert_eq!(
231 <&SimpleTable as SchemaWithPK>::primary_key_index(&r, idx),
232 t.primary_key_index(idx)
233 );
234 }
235 let values: Vec<Value<String, Vec<u8>>> = vec![
236 Value::Integer(1),
237 Value::Text("alice".into()),
238 Value::Text("a@x".into()),
239 ];
240 let pk_ref = <&SimpleTable as SchemaWithPK>::extract_pk(&r, &values);
241 let pk_direct = t.extract_pk(&values);
242 assert_eq!(pk_ref, pk_direct);
243 }
244
245 #[test]
246 fn test_indexable_values_vec_option() {
247 let v: Vec<Option<Value<String, Vec<u8>>>> =
249 vec![Some(Value::Integer(7)), None, Some(Value::Text("x".into()))];
250 assert_eq!(
251 <Vec<Option<Value<String, Vec<u8>>>> as IndexableValues>::get(&v, 0),
252 Some(Value::Integer(7))
253 );
254 assert_eq!(
255 <Vec<Option<Value<String, Vec<u8>>>> as IndexableValues>::get(&v, 1),
256 Some(Value::Null)
257 );
258 assert_eq!(
259 <Vec<Option<Value<String, Vec<u8>>>> as IndexableValues>::get(&v, 2),
260 Some(Value::Text("x".into()))
261 );
262 assert_eq!(
263 <Vec<Option<Value<String, Vec<u8>>>> as IndexableValues>::get(&v, 99),
264 None
265 );
266 }
267
268 #[test]
269 fn test_indexable_values_slice_option() {
270 let owned: Vec<Option<Value<String, Vec<u8>>>> = vec![Some(Value::Integer(1)), None];
271 let slice: &[Option<Value<String, Vec<u8>>>] = &owned;
272 assert_eq!(
273 <&[Option<Value<String, Vec<u8>>>] as IndexableValues>::get(&slice, 0),
274 Some(Value::Integer(1))
275 );
276 assert_eq!(
277 <&[Option<Value<String, Vec<u8>>>] as IndexableValues>::get(&slice, 1),
278 Some(Value::Null)
279 );
280 assert_eq!(
281 <&[Option<Value<String, Vec<u8>>>] as IndexableValues>::get(&slice, 5),
282 None
283 );
284 }
285
286 type PairVec = Vec<(u8, Option<Value<String, Vec<u8>>>)>;
287
288 #[test]
289 fn test_indexable_values_vec_pair() {
290 let v: PairVec = vec![(0, Some(Value::Integer(2))), (1, None)];
292 assert_eq!(
293 <PairVec as IndexableValues>::get(&v, 0),
294 Some(Value::Integer(2))
295 );
296 assert_eq!(<PairVec as IndexableValues>::get(&v, 1), Some(Value::Null));
297 assert_eq!(<PairVec as IndexableValues>::get(&v, 2), None);
298 }
299
300 type PairSlice<'a> = &'a [(u8, Option<Value<String, Vec<u8>>>)];
301
302 #[test]
303 fn test_indexable_values_slice_pair() {
304 let owned: PairVec = vec![(0, Some(Value::Text("y".into()))), (1, None)];
305 let slice: PairSlice<'_> = &owned;
306 assert_eq!(
307 <PairSlice<'_> as IndexableValues>::get(&slice, 0),
308 Some(Value::Text("y".into()))
309 );
310 assert_eq!(
311 <PairSlice<'_> as IndexableValues>::get(&slice, 1),
312 Some(Value::Null)
313 );
314 assert_eq!(<PairSlice<'_> as IndexableValues>::get(&slice, 3), None);
315 }
316}