1use std::{borrow::Cow, error::Error, marker::PhantomData};
2
3use schemars::{generate::SchemaSettings, JsonSchema, Schema};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use serde_json::Value;
6
7use crate::{AnyArray, AnyArrayView, AnyArrayViewMut, AnyCowArray};
8
9pub trait Codec: 'static + Send + Sync + Clone {
12 type Error: 'static + Send + Sync + Error;
15
16 fn encode(&self, data: AnyCowArray) -> Result<AnyArray, Self::Error>;
22
23 fn decode(&self, encoded: AnyCowArray) -> Result<AnyArray, Self::Error>;
29
30 fn decode_into(
39 &self,
40 encoded: AnyArrayView,
41 decoded: AnyArrayViewMut,
42 ) -> Result<(), Self::Error>;
43}
44
45pub trait StaticCodec: Codec {
47 const CODEC_ID: &'static str;
49
50 type Config<'de>: Serialize + Deserialize<'de> + JsonSchema;
56
57 fn from_config(config: Self::Config<'_>) -> Self;
59
60 fn get_config(&self) -> StaticCodecConfig<Self>;
65}
66
67pub trait DynCodec: Codec {
71 type Type: DynCodecType;
73
74 fn ty(&self) -> Self::Type;
76
77 fn get_config<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>;
89}
90
91pub trait DynCodecType: 'static + Send + Sync {
93 type Codec: DynCodec<Type = Self>;
95
96 fn codec_id(&self) -> &str;
98
99 fn codec_config_schema(&self) -> Schema;
101
102 fn codec_from_config<'de, D: Deserializer<'de>>(
113 &self,
114 config: D,
115 ) -> Result<Self::Codec, D::Error>;
116}
117
118impl<T: StaticCodec> DynCodec for T {
119 type Type = StaticCodecType<Self>;
120
121 fn ty(&self) -> Self::Type {
122 StaticCodecType::of()
123 }
124
125 fn get_config<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
126 <T as StaticCodec>::get_config(self).serialize(serializer)
127 }
128}
129
130pub struct StaticCodecType<T: StaticCodec> {
132 _marker: PhantomData<T>,
133}
134
135impl<T: StaticCodec> StaticCodecType<T> {
136 #[must_use]
138 pub const fn of() -> Self {
139 Self {
140 _marker: PhantomData::<T>,
141 }
142 }
143}
144
145impl<T: StaticCodec> DynCodecType for StaticCodecType<T> {
146 type Codec = T;
147
148 fn codec_id(&self) -> &str {
149 T::CODEC_ID
150 }
151
152 fn codec_config_schema(&self) -> Schema {
153 let mut settings = SchemaSettings::draft2020_12();
154 settings.inline_subschemas = true;
157 settings
158 .into_generator()
159 .into_root_schema_for::<T::Config<'static>>()
160 }
161
162 fn codec_from_config<'de, D: Deserializer<'de>>(
163 &self,
164 config: D,
165 ) -> Result<Self::Codec, D::Error> {
166 let config = T::Config::deserialize(config)?;
167 Ok(T::from_config(config))
168 }
169}
170
171#[derive(Serialize, Deserialize)]
174#[serde(bound = "")]
175pub struct StaticCodecConfig<'a, T: StaticCodec> {
176 #[serde(default)]
177 id: StaticCodecId<T>,
178 #[serde(flatten)]
180 #[serde(borrow)]
181 pub config: T::Config<'a>,
182}
183
184impl<'a, T: StaticCodec> StaticCodecConfig<'a, T> {
185 #[must_use]
188 pub const fn new(config: T::Config<'a>) -> Self {
189 Self {
190 id: StaticCodecId::of(),
191 config,
192 }
193 }
194}
195
196impl<'a, T: StaticCodec> From<&T::Config<'a>> for StaticCodecConfig<'a, T>
197where
198 T::Config<'a>: Clone,
199{
200 fn from(config: &T::Config<'a>) -> Self {
201 Self::new(config.clone())
202 }
203}
204
205struct StaticCodecId<T: StaticCodec>(PhantomData<T>);
206
207impl<T: StaticCodec> StaticCodecId<T> {
208 #[must_use]
209 pub const fn of() -> Self {
210 Self(PhantomData::<T>)
211 }
212}
213
214impl<T: StaticCodec> Default for StaticCodecId<T> {
215 fn default() -> Self {
216 Self::of()
217 }
218}
219
220impl<T: StaticCodec> Serialize for StaticCodecId<T> {
221 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
222 T::CODEC_ID.serialize(serializer)
223 }
224}
225
226impl<'de, T: StaticCodec> Deserialize<'de> for StaticCodecId<T> {
227 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
228 let id = Cow::<str>::deserialize(deserializer)?;
229 let id = &*id;
230
231 if id != T::CODEC_ID {
232 return Err(serde::de::Error::custom(format!(
233 "expected codec id {:?} but found {id:?}",
234 T::CODEC_ID,
235 )));
236 }
237
238 Ok(Self::of())
239 }
240}
241
242pub fn serialize_codec_config_with_id<T: Serialize, C: DynCodec, S: Serializer>(
252 config: &T,
253 codec: &C,
254 serializer: S,
255) -> Result<S::Ok, S::Error> {
256 #[derive(Serialize)]
257 struct DynCodecConfigWithId<'a, T> {
258 id: &'a str,
259 #[serde(flatten)]
260 config: &'a T,
261 }
262
263 DynCodecConfigWithId {
264 id: codec.ty().codec_id(),
265 config,
266 }
267 .serialize(serializer)
268}
269
270pub fn codec_from_config_with_id<'de, T: DynCodecType, D: Deserializer<'de>>(
280 ty: &T,
281 config: D,
282) -> Result<T::Codec, D::Error> {
283 let mut config = Value::deserialize(config)?;
284
285 if let Some(config) = config.as_object_mut() {
286 if let Some(id) = config.remove("id") {
287 let codec_id = ty.codec_id();
288
289 if !matches!(id, Value::String(ref id) if id == codec_id) {
290 return Err(serde::de::Error::custom(format!(
291 "expected codec id {codec_id:?} but found {id}"
292 )));
293 }
294 }
295 }
296
297 ty.codec_from_config(config)
298 .map_err(serde::de::Error::custom)
299}