osom_lib_strings/immutable/serde/
seeded.rs1#![allow(clippy::elidable_lifetime_names)]
2
3use osom_lib_alloc::traits::Allocator;
4use serde::de;
5
6use crate::immutable::ImmutableString;
7
8#[repr(transparent)]
10#[derive(Debug, PartialEq, Eq, Hash)]
11#[must_use]
12pub struct CacheError {
13 message: &'static str,
14}
15
16impl CacheError {
17 #[inline(always)]
18 pub const fn new(message: &'static str) -> Self {
19 Self { message }
20 }
21}
22
23impl core::fmt::Display for CacheError {
24 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
25 write!(f, "CacheError: {}", self.message)
26 }
27}
28
29impl AsRef<str> for CacheError {
30 fn as_ref(&self) -> &str {
31 self.message
32 }
33}
34
35#[must_use]
37pub trait StringCache {
38 type TAllocator: Allocator;
39
40 fn get_and_cache(&mut self, value: &str) -> Result<ImmutableString<Self::TAllocator>, CacheError>;
46}
47
48#[must_use]
50pub struct CachedStringSeed<'a, TStringCache: StringCache> {
51 cache: &'a mut TStringCache,
52}
53
54impl<'a, TStringCache: StringCache> CachedStringSeed<'a, TStringCache> {
55 pub fn new(cache: &'a mut TStringCache) -> Self {
56 Self { cache }
57 }
58}
59
60impl<'a, TStringCache: StringCache> de::Visitor<'_> for CachedStringSeed<'a, TStringCache> {
61 type Value = ImmutableString<TStringCache::TAllocator>;
62
63 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
64 formatter.write_str("a string")
65 }
66
67 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
68 where
69 E: de::Error,
70 {
71 let value = self.cache.get_and_cache(v).map_err(E::custom)?;
72 Ok(value)
73 }
74
75 #[cfg(feature = "std")]
76 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
77 where
78 E: de::Error,
79 {
80 let value = self.cache.get_and_cache(&v).map_err(E::custom)?;
81 Ok(value)
82 }
83
84 fn visit_borrowed_str<E>(self, v: &str) -> Result<Self::Value, E>
85 where
86 E: de::Error,
87 {
88 let value = self.cache.get_and_cache(v).map_err(E::custom)?;
89 Ok(value)
90 }
91}
92
93impl<'de, 'a, TStringCache: StringCache> de::DeserializeSeed<'de> for CachedStringSeed<'a, TStringCache> {
94 type Value = ImmutableString<TStringCache::TAllocator>;
95
96 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
97 where
98 D: de::Deserializer<'de>,
99 {
100 let visitor = CachedStringSeed::new(self.cache);
101 let result = deserializer.deserialize_string(visitor)?;
102 Ok(result)
103 }
104}