1use bytes::Bytes;
4
5use crate::{Error, Format, Path, Record, Value};
6
7pub trait Reader: Send + Sync {
54 fn read(&mut self, from: &Path) -> Result<Option<Record>, Error>;
60
61 fn read_children(&mut self, from: &Path) -> Result<Option<Vec<String>>, Error> {
71 let Some(record) = self.read(from)? else {
72 return Ok(None);
73 };
74 match record.as_value() {
75 Some(Value::Map(map)) => Ok(Some(map.keys().cloned().collect())),
76 Some(Value::Array(arr)) => Ok(Some((0..arr.len()).map(|i| i.to_string()).collect())),
77 Some(_) => Ok(Some(Vec::new())),
78 None => Err(Error::store(
79 "reader",
80 "read_children",
81 "cannot enumerate children of a raw record; the store must override read_children",
82 )),
83 }
84 }
85}
86
87pub trait Writer: Send + Sync {
98 fn write(&mut self, to: &Path, data: Record) -> Result<Path, Error>;
104}
105
106pub trait Store: Reader + Writer {}
108impl<T: Reader + Writer> Store for T {}
109
110pub trait Codec: Send + Sync {
148 fn decode(&self, bytes: &Bytes, format: &Format) -> Result<Value, Error>;
150
151 fn encode(&self, value: &Value, format: &Format) -> Result<Bytes, Error>;
153
154 fn supports(&self, format: &Format) -> bool;
156}
157
158pub struct NoCodec;
162
163impl Codec for NoCodec {
164 fn decode(&self, _bytes: &Bytes, format: &Format) -> Result<Value, Error> {
165 Err(Error::UnsupportedFormat(format.clone()))
166 }
167
168 fn encode(&self, _value: &Value, format: &Format) -> Result<Bytes, Error> {
169 Err(Error::UnsupportedFormat(format.clone()))
170 }
171
172 fn supports(&self, _format: &Format) -> bool {
173 false
174 }
175}
176
177impl<T: Reader + ?Sized> Reader for &mut T {
180 fn read(&mut self, from: &Path) -> Result<Option<Record>, Error> {
181 (*self).read(from)
182 }
183
184 fn read_children(&mut self, from: &Path) -> Result<Option<Vec<String>>, Error> {
185 (*self).read_children(from)
186 }
187}
188
189impl<T: Writer + ?Sized> Writer for &mut T {
190 fn write(&mut self, to: &Path, data: Record) -> Result<Path, Error> {
191 (*self).write(to, data)
192 }
193}
194
195impl<T: Reader + ?Sized> Reader for Box<T> {
196 fn read(&mut self, from: &Path) -> Result<Option<Record>, Error> {
197 self.as_mut().read(from)
198 }
199
200 fn read_children(&mut self, from: &Path) -> Result<Option<Vec<String>>, Error> {
201 self.as_mut().read_children(from)
202 }
203}
204
205impl<T: Writer + ?Sized> Writer for Box<T> {
206 fn write(&mut self, to: &Path, data: Record) -> Result<Path, Error> {
207 self.as_mut().write(to, data)
208 }
209}
210
211impl<T: Codec + ?Sized> Codec for Box<T> {
212 fn decode(&self, bytes: &Bytes, format: &Format) -> Result<Value, Error> {
213 self.as_ref().decode(bytes, format)
214 }
215
216 fn encode(&self, value: &Value, format: &Format) -> Result<Bytes, Error> {
217 self.as_ref().encode(value, format)
218 }
219
220 fn supports(&self, format: &Format) -> bool {
221 self.as_ref().supports(format)
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228 use std::collections::HashMap;
229
230 struct TestStore {
232 data: HashMap<Path, Record>,
233 }
234
235 impl TestStore {
236 fn new() -> Self {
237 Self {
238 data: HashMap::new(),
239 }
240 }
241 }
242
243 impl Reader for TestStore {
244 fn read(&mut self, from: &Path) -> Result<Option<Record>, Error> {
245 Ok(self.data.get(from).cloned())
246 }
247 }
248
249 impl Writer for TestStore {
250 fn write(&mut self, to: &Path, data: Record) -> Result<Path, Error> {
251 self.data.insert(to.clone(), data);
252 Ok(to.clone())
253 }
254 }
255
256 #[test]
257 fn basic_store_works() {
258 use crate::path;
259
260 let mut store = TestStore::new();
261
262 let path = path!("users/123");
263 let record = Record::parsed(Value::from("Alice"));
264
265 store.write(&path, record.clone()).unwrap();
266
267 let result = store.read(&path).unwrap();
268 assert!(result.is_some());
269 }
270
271 #[test]
272 fn object_safety_works() {
273 use crate::path;
274
275 let mut store = TestStore::new();
276 let boxed: &mut dyn Store = &mut store;
277
278 let path = path!("test");
279 boxed
280 .write(&path, Record::parsed(Value::from("hello")))
281 .unwrap();
282
283 let result = boxed.read(&path).unwrap();
284 assert!(result.is_some());
285 }
286
287 #[test]
288 fn no_codec_decode_fails() {
289 let codec = NoCodec;
290 let bytes = Bytes::from_static(b"hello");
291 let result = codec.decode(&bytes, &Format::JSON);
292 assert!(matches!(result, Err(Error::UnsupportedFormat(_))));
293 }
294
295 #[test]
296 fn no_codec_encode_fails() {
297 let codec = NoCodec;
298 let value = Value::from("test");
299 let result = codec.encode(&value, &Format::JSON);
300 assert!(matches!(result, Err(Error::UnsupportedFormat(_))));
301 }
302
303 #[test]
304 fn no_codec_supports_nothing() {
305 let codec = NoCodec;
306 assert!(!codec.supports(&Format::JSON));
307 assert!(!codec.supports(&Format::PROTOBUF));
308 assert!(!codec.supports(&Format::OCTET_STREAM));
309 }
310
311 #[test]
312 fn ref_mut_reader_works() {
313 use crate::path;
314
315 let mut store = TestStore::new();
316 let path = path!("test");
317 store
318 .write(&path, Record::parsed(Value::from("value")))
319 .unwrap();
320
321 let store_ref: &mut TestStore = &mut store;
323 let result = store_ref.read(&path).unwrap();
324 assert!(result.is_some());
325 }
326
327 #[test]
328 fn ref_mut_writer_works() {
329 use crate::path;
330
331 let mut store = TestStore::new();
332
333 let store_ref: &mut TestStore = &mut store;
335 let path = path!("test");
336 let result = store_ref.write(&path, Record::parsed(Value::from("data")));
337 assert!(result.is_ok());
338
339 let read_result = store.read(&path).unwrap();
341 assert!(read_result.is_some());
342 }
343
344 #[test]
345 fn boxed_reader_works() {
346 use crate::path;
347
348 let mut store = TestStore::new();
349 let path = path!("boxed_test");
350 store
351 .write(&path, Record::parsed(Value::from("boxed_value")))
352 .unwrap();
353
354 let mut boxed: Box<TestStore> = Box::new(store);
356 let result = boxed.read(&path).unwrap();
357 assert!(result.is_some());
358 }
359
360 #[test]
361 fn boxed_writer_works() {
362 use crate::path;
363
364 let store = TestStore::new();
365 let mut boxed: Box<TestStore> = Box::new(store);
366
367 let path = path!("boxed_write");
368 let result = boxed.write(&path, Record::parsed(Value::from("data")));
369 assert!(result.is_ok());
370
371 let read_result = boxed.read(&path).unwrap();
373 assert!(read_result.is_some());
374 }
375
376 #[test]
377 fn boxed_codec_works() {
378 struct TestCodec;
380
381 impl Codec for TestCodec {
382 fn decode(&self, bytes: &Bytes, _format: &Format) -> Result<Value, Error> {
383 let s = String::from_utf8_lossy(bytes);
385 Ok(Value::String(s.to_string()))
386 }
387
388 fn encode(&self, value: &Value, _format: &Format) -> Result<Bytes, Error> {
389 match value {
390 Value::String(s) => Ok(Bytes::from(s.clone())),
391 _ => Err(Error::encode(Format::OCTET_STREAM, "only strings")),
392 }
393 }
394
395 fn supports(&self, format: &Format) -> bool {
396 format == &Format::OCTET_STREAM
397 }
398 }
399
400 let boxed: Box<dyn Codec> = Box::new(TestCodec);
401
402 assert!(boxed.supports(&Format::OCTET_STREAM));
404 assert!(!boxed.supports(&Format::JSON));
405
406 let decoded = boxed
408 .decode(&Bytes::from_static(b"hello"), &Format::OCTET_STREAM)
409 .unwrap();
410 assert_eq!(decoded, Value::String("hello".to_string()));
411
412 let encoded = boxed
414 .encode(&Value::String("world".to_string()), &Format::OCTET_STREAM)
415 .unwrap();
416 assert_eq!(encoded.as_ref(), b"world");
417 }
418
419 #[test]
420 fn store_trait_auto_impl() {
421 fn requires_store<S: Store>(_s: &mut S) {}
423
424 let mut store = TestStore::new();
425 requires_store(&mut store); }
427
428 #[test]
429 fn read_missing_returns_none() {
430 use crate::path;
431
432 let mut store = TestStore::new();
433 let result = store.read(&path!("nonexistent")).unwrap();
434 assert!(result.is_none());
435 }
436
437 #[test]
438 fn read_children_default_impl() {
439 use crate::path;
440 use std::collections::BTreeMap;
441
442 let mut store = TestStore::new();
443
444 let mut map = BTreeMap::new();
446 map.insert("alice".to_string(), Value::from(1i64));
447 map.insert("bob".to_string(), Value::from(2i64));
448 store
449 .write(&path!("users"), Record::parsed(Value::Map(map)))
450 .unwrap();
451 assert_eq!(
452 store.read_children(&path!("users")).unwrap(),
453 Some(vec!["alice".to_string(), "bob".to_string()])
454 );
455
456 store
458 .write(
459 &path!("items"),
460 Record::parsed(Value::Array(vec![Value::from("a"), Value::from("b")])),
461 )
462 .unwrap();
463 assert_eq!(
464 store.read_children(&path!("items")).unwrap(),
465 Some(vec!["0".to_string(), "1".to_string()])
466 );
467
468 store
470 .write(&path!("leaf"), Record::parsed(Value::from("scalar")))
471 .unwrap();
472 assert_eq!(store.read_children(&path!("leaf")).unwrap(), Some(vec![]));
473
474 assert_eq!(store.read_children(&path!("missing")).unwrap(), None);
476 }
477
478 #[test]
479 fn read_children_raw_record_errors() {
480 use crate::path;
481
482 let mut store = TestStore::new();
483 store
484 .write(
485 &path!("raw"),
486 Record::raw(Bytes::from_static(b"{}"), Format::JSON),
487 )
488 .unwrap();
489 assert!(store.read_children(&path!("raw")).is_err());
490 }
491
492 #[test]
493 fn read_children_delegates_through_wrappers() {
494 use crate::path;
495
496 struct ListingStore;
498
499 impl Reader for ListingStore {
500 fn read(&mut self, _from: &Path) -> Result<Option<Record>, Error> {
501 Ok(None)
502 }
503
504 fn read_children(&mut self, _from: &Path) -> Result<Option<Vec<String>>, Error> {
505 Ok(Some(vec!["custom".to_string()]))
506 }
507 }
508
509 let mut store = ListingStore;
510 let by_ref: &mut dyn Reader = &mut store;
511 assert_eq!(
512 by_ref.read_children(&path!("x")).unwrap(),
513 Some(vec!["custom".to_string()])
514 );
515
516 let mut boxed: Box<dyn Reader> = Box::new(ListingStore);
517 assert_eq!(
518 boxed.read_children(&path!("x")).unwrap(),
519 Some(vec!["custom".to_string()])
520 );
521 }
522}