1use bytes::Bytes;
26use structfs_ll_store::{LLError, LLPath, LLReader, LLWriter};
27
28use crate::{Codec, Error, Format, Path, PathError, Reader, Record, Writer};
29
30pub struct LLToCore<T, C> {
37 inner: T,
38 codec: C,
39 read_format: Format,
41 write_format: Format,
43}
44
45impl<T, C> LLToCore<T, C> {
46 pub fn new(inner: T, codec: C, format: Format) -> Self {
48 Self {
49 inner,
50 codec,
51 read_format: format.clone(),
52 write_format: format,
53 }
54 }
55
56 pub fn with_formats(inner: T, codec: C, read_format: Format, write_format: Format) -> Self {
58 Self {
59 inner,
60 codec,
61 read_format,
62 write_format,
63 }
64 }
65
66 pub fn inner(&self) -> &T {
68 &self.inner
69 }
70
71 pub fn inner_mut(&mut self) -> &mut T {
73 &mut self.inner
74 }
75
76 pub fn into_inner(self) -> T {
78 self.inner
79 }
80}
81
82impl<T: LLReader, C: Send + Sync> Reader for LLToCore<T, C> {
83 fn read(&mut self, from: &Path) -> Result<Option<Record>, Error> {
84 let components: Vec<&[u8]> = from.as_ll().as_byte_refs();
86
87 let bytes = match self.inner.ll_read(&components) {
89 Ok(Some(b)) => b,
90 Ok(None) => return Ok(None),
91 Err(e) => return Err(Error::Ll(e)),
92 };
93
94 Ok(Some(Record::raw(bytes, self.read_format.clone())))
96 }
97}
98
99impl<T: LLWriter, C: Codec + Send + Sync> Writer for LLToCore<T, C> {
100 fn write(&mut self, to: &Path, data: Record) -> Result<Path, Error> {
101 let bytes = data.into_bytes(&self.codec, &self.write_format)?;
103
104 let components: Vec<&[u8]> = to.as_ll().as_byte_refs();
106
107 let result_path = self.inner.ll_write(&components, bytes).map_err(Error::Ll)?;
109
110 path_from_ll(&result_path)
112 }
113}
114
115pub struct CoreToLL<T, C> {
122 inner: T,
123 codec: C,
124 format: Format,
125}
126
127impl<T, C> CoreToLL<T, C> {
128 pub fn new(inner: T, codec: C, format: Format) -> Self {
130 Self {
131 inner,
132 codec,
133 format,
134 }
135 }
136
137 pub fn inner(&self) -> &T {
139 &self.inner
140 }
141
142 pub fn inner_mut(&mut self) -> &mut T {
144 &mut self.inner
145 }
146
147 pub fn into_inner(self) -> T {
149 self.inner
150 }
151}
152
153impl<T: Reader, C: Codec + Send + Sync> LLReader for CoreToLL<T, C> {
154 fn ll_read(&mut self, path: &[&[u8]]) -> Result<Option<Bytes>, LLError> {
155 let path = path_from_bytes(path).map_err(|e| LLError::Protocol {
157 code: 1,
158 detail: Bytes::copy_from_slice(e.to_string().as_bytes()),
159 })?;
160
161 let record = match self.inner.read(&path) {
163 Ok(Some(r)) => r,
164 Ok(None) => return Ok(None),
165 Err(e) => {
166 return Err(LLError::Protocol {
167 code: 2,
168 detail: Bytes::copy_from_slice(e.to_string().as_bytes()),
169 })
170 }
171 };
172
173 let bytes =
175 record
176 .into_bytes(&self.codec, &self.format)
177 .map_err(|e| LLError::Protocol {
178 code: 3,
179 detail: Bytes::copy_from_slice(e.to_string().as_bytes()),
180 })?;
181
182 Ok(Some(bytes))
183 }
184}
185
186impl<T: Writer, C: Send + Sync> LLWriter for CoreToLL<T, C> {
187 fn ll_write(&mut self, path: &[&[u8]], data: Bytes) -> Result<LLPath, LLError> {
188 let path = path_from_bytes(path).map_err(|e| LLError::Protocol {
190 code: 1,
191 detail: Bytes::copy_from_slice(e.to_string().as_bytes()),
192 })?;
193
194 let record = Record::raw(data, self.format.clone());
196
197 let result_path = self
199 .inner
200 .write(&path, record)
201 .map_err(|e| LLError::Protocol {
202 code: 2,
203 detail: Bytes::copy_from_slice(e.to_string().as_bytes()),
204 })?;
205
206 Ok(result_path.into_ll())
208 }
209}
210
211pub(crate) fn path_from_bytes(components: &[&[u8]]) -> Result<Path, PathError> {
213 let mut strings = Vec::with_capacity(components.len());
214 for (i, bytes) in components.iter().enumerate() {
215 let s = std::str::from_utf8(bytes).map_err(|_| PathError::InvalidComponent {
216 component: format!("{:?}", bytes),
217 position: i,
218 message: "not valid UTF-8".to_string(),
219 })?;
220 strings.push(s.to_string());
221 }
222 Path::try_from_components(strings)
223}
224
225pub(crate) fn path_from_ll(components: &[Bytes]) -> Result<Path, Error> {
227 let refs: Vec<&[u8]> = components.iter().map(|b| b.as_ref()).collect();
228 path_from_bytes(&refs).map_err(Error::Path)
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234 use crate::{path, NoCodec};
235 use std::collections::HashMap;
236
237 struct TestLLStore {
239 data: HashMap<Vec<Vec<u8>>, Bytes>,
240 }
241
242 impl TestLLStore {
243 fn new() -> Self {
244 Self {
245 data: HashMap::new(),
246 }
247 }
248 }
249
250 impl LLReader for TestLLStore {
251 fn ll_read(&mut self, path: &[&[u8]]) -> Result<Option<Bytes>, LLError> {
252 let key: Vec<Vec<u8>> = path.iter().map(|c| c.to_vec()).collect();
253 Ok(self.data.get(&key).cloned())
254 }
255 }
256
257 impl LLWriter for TestLLStore {
258 fn ll_write(&mut self, path: &[&[u8]], data: Bytes) -> Result<LLPath, LLError> {
259 let key: Vec<Vec<u8>> = path.iter().map(|c| c.to_vec()).collect();
260 self.data.insert(key, data);
261 Ok(path.iter().map(|c| Bytes::copy_from_slice(c)).collect())
262 }
263 }
264
265 struct TestCoreStore {
267 data: HashMap<Path, Record>,
268 }
269
270 impl TestCoreStore {
271 fn new() -> Self {
272 Self {
273 data: HashMap::new(),
274 }
275 }
276 }
277
278 impl Reader for TestCoreStore {
279 fn read(&mut self, from: &Path) -> Result<Option<Record>, Error> {
280 Ok(self.data.get(from).cloned())
281 }
282 }
283
284 impl Writer for TestCoreStore {
285 fn write(&mut self, to: &Path, data: Record) -> Result<Path, Error> {
286 self.data.insert(to.clone(), data);
287 Ok(to.clone())
288 }
289 }
290
291 #[test]
292 fn ll_to_core_read() {
293 let mut ll = TestLLStore::new();
294 ll.data.insert(
295 vec![b"users".to_vec(), b"123".to_vec()],
296 Bytes::from_static(b"hello"),
297 );
298
299 let mut bridge = LLToCore::new(ll, NoCodec, Format::OCTET_STREAM);
300
301 let result = bridge.read(&path!("users/123")).unwrap();
302 assert!(result.is_some());
303 assert_eq!(
304 result.unwrap().as_bytes(),
305 Some(&Bytes::from_static(b"hello"))
306 );
307 }
308
309 #[test]
310 fn ll_to_core_write() {
311 let ll = TestLLStore::new();
312 let mut bridge = LLToCore::new(ll, NoCodec, Format::OCTET_STREAM);
313
314 let record = Record::raw(Bytes::from_static(b"data"), Format::OCTET_STREAM);
315 bridge.write(&path!("test/path"), record).unwrap();
316
317 let key = vec![b"test".to_vec(), b"path".to_vec()];
319 assert!(bridge.inner().data.contains_key(&key));
320 }
321
322 #[test]
323 fn core_to_ll_read() {
324 let mut core = TestCoreStore::new();
325 core.data.insert(
326 path!("users/123"),
327 Record::raw(Bytes::from_static(b"hello"), Format::OCTET_STREAM),
328 );
329
330 let mut bridge = CoreToLL::new(core, NoCodec, Format::OCTET_STREAM);
331
332 let result = bridge.ll_read(&[b"users", b"123"]).unwrap();
333 assert_eq!(result, Some(Bytes::from_static(b"hello")));
334 }
335
336 #[test]
337 fn core_to_ll_write() {
338 let core = TestCoreStore::new();
339 let mut bridge = CoreToLL::new(core, NoCodec, Format::OCTET_STREAM);
340
341 bridge
342 .ll_write(&[b"test", b"path"], Bytes::from_static(b"data"))
343 .unwrap();
344
345 assert!(bridge.inner().data.contains_key(&path!("test/path")));
347 }
348
349 #[test]
350 fn invalid_utf8_path_rejected() {
351 let core = TestCoreStore::new();
352 let mut bridge = CoreToLL::new(core, NoCodec, Format::OCTET_STREAM);
353
354 let result = bridge.ll_read(&[&[0xFF, 0xFE]]);
356 assert!(matches!(result, Err(LLError::Protocol { .. })));
357 }
358
359 #[test]
360 fn ll_to_core_with_formats() {
361 let ll = TestLLStore::new();
362 let bridge = LLToCore::with_formats(ll, NoCodec, Format::JSON, Format::OCTET_STREAM);
363 assert_eq!(bridge.read_format, Format::JSON);
364 assert_eq!(bridge.write_format, Format::OCTET_STREAM);
365 }
366
367 #[test]
368 fn ll_to_core_inner_methods() {
369 let ll = TestLLStore::new();
370 let mut bridge = LLToCore::new(ll, NoCodec, Format::OCTET_STREAM);
371
372 assert!(bridge.inner().data.is_empty());
374
375 bridge
377 .inner_mut()
378 .data
379 .insert(vec![b"key".to_vec()], Bytes::from_static(b"value"));
380 assert!(!bridge.inner().data.is_empty());
381
382 let ll = bridge.into_inner();
384 assert!(!ll.data.is_empty());
385 }
386
387 #[test]
388 fn core_to_ll_inner_methods() {
389 let core = TestCoreStore::new();
390 let mut bridge = CoreToLL::new(core, NoCodec, Format::OCTET_STREAM);
391
392 assert!(bridge.inner().data.is_empty());
394
395 bridge.inner_mut().data.insert(
397 path!("key"),
398 Record::raw(Bytes::from_static(b"value"), Format::OCTET_STREAM),
399 );
400 assert!(!bridge.inner().data.is_empty());
401
402 let core = bridge.into_inner();
404 assert!(!core.data.is_empty());
405 }
406
407 #[test]
408 fn ll_to_core_read_none() {
409 let ll = TestLLStore::new();
410 let mut bridge = LLToCore::new(ll, NoCodec, Format::OCTET_STREAM);
411
412 let result = bridge.read(&path!("nonexistent")).unwrap();
413 assert!(result.is_none());
414 }
415
416 #[test]
417 fn core_to_ll_read_none() {
418 let core = TestCoreStore::new();
419 let mut bridge = CoreToLL::new(core, NoCodec, Format::OCTET_STREAM);
420
421 let result = bridge.ll_read(&[b"nonexistent"]).unwrap();
422 assert!(result.is_none());
423 }
424
425 #[test]
426 fn core_to_ll_write_invalid_utf8() {
427 let core = TestCoreStore::new();
428 let mut bridge = CoreToLL::new(core, NoCodec, Format::OCTET_STREAM);
429
430 let result = bridge.ll_write(&[&[0xFF, 0xFE]], Bytes::from_static(b"data"));
432 assert!(matches!(result, Err(LLError::Protocol { code: 1, .. })));
433 }
434
435 #[test]
436 fn path_from_bytes_empty() {
437 let result = path_from_bytes(&[]).unwrap();
438 assert!(result.is_empty());
439 }
440
441 #[test]
442 fn path_from_bytes_single_component() {
443 let result = path_from_bytes(&[b"users"]).unwrap();
444 assert_eq!(result.to_string(), "users");
445 }
446
447 #[test]
448 fn path_from_bytes_multiple_components() {
449 let result = path_from_bytes(&[b"users", b"123", b"profile"]).unwrap();
450 assert_eq!(result.to_string(), "users/123/profile");
451 }
452
453 #[test]
454 fn path_from_ll_works() {
455 let ll_path = vec![Bytes::from_static(b"a"), Bytes::from_static(b"b")];
456 let result = path_from_ll(&ll_path).unwrap();
457 assert_eq!(result.to_string(), "a/b");
458 }
459
460 #[test]
461 fn path_from_ll_invalid_utf8() {
462 let ll_path = vec![Bytes::from_static(&[0xFF, 0xFE])];
463 let result = path_from_ll(&ll_path);
464 assert!(result.is_err());
465 }
466
467 struct ErrorCoreStore;
469
470 impl Reader for ErrorCoreStore {
471 fn read(&mut self, _from: &Path) -> Result<Option<Record>, Error> {
472 Err(Error::store("test", "read", "read error"))
473 }
474 }
475
476 impl Writer for ErrorCoreStore {
477 fn write(&mut self, _to: &Path, _data: Record) -> Result<Path, Error> {
478 Err(Error::store("test", "write", "write error"))
479 }
480 }
481
482 #[test]
483 fn core_to_ll_read_error() {
484 let core = ErrorCoreStore;
485 let mut bridge = CoreToLL::new(core, NoCodec, Format::OCTET_STREAM);
486
487 let result = bridge.ll_read(&[b"any"]);
488 assert!(matches!(result, Err(LLError::Protocol { code: 2, .. })));
489 }
490
491 #[test]
492 fn core_to_ll_write_error() {
493 let core = ErrorCoreStore;
494 let mut bridge = CoreToLL::new(core, NoCodec, Format::OCTET_STREAM);
495
496 let result = bridge.ll_write(&[b"any"], Bytes::from_static(b"data"));
497 assert!(matches!(result, Err(LLError::Protocol { code: 2, .. })));
498 }
499
500 struct ErrorLLStore;
502
503 impl LLReader for ErrorLLStore {
504 fn ll_read(&mut self, _path: &[&[u8]]) -> Result<Option<Bytes>, LLError> {
505 Err(LLError::Protocol {
506 code: 99,
507 detail: Bytes::from_static(b"ll error"),
508 })
509 }
510 }
511
512 impl LLWriter for ErrorLLStore {
513 fn ll_write(&mut self, _path: &[&[u8]], _data: Bytes) -> Result<LLPath, LLError> {
514 Err(LLError::Protocol {
515 code: 99,
516 detail: Bytes::from_static(b"ll write error"),
517 })
518 }
519 }
520
521 #[test]
522 fn ll_to_core_read_error() {
523 let ll = ErrorLLStore;
524 let mut bridge = LLToCore::new(ll, NoCodec, Format::OCTET_STREAM);
525
526 let result = bridge.read(&path!("any"));
527 assert!(result.is_err());
528 assert!(result.unwrap_err().to_string().contains("ll error"));
529 }
530
531 #[test]
532 fn ll_to_core_write_error() {
533 let ll = ErrorLLStore;
534 let mut bridge = LLToCore::new(ll, NoCodec, Format::OCTET_STREAM);
535
536 let result = bridge.write(
537 &path!("any"),
538 Record::raw(Bytes::from_static(b"data"), Format::OCTET_STREAM),
539 );
540 assert!(result.is_err());
541 }
542}