numcodecs_registry/
lib.rs1use std::{error::Error, sync::Arc};
23
24use numcodecs::{DynCodec, ErasedDynCodec, ErasedError};
25use serde::Deserializer;
26
27pub trait Registry: 'static + Send + Sync {
29 type Error: 'static + Send + Sync + Error;
32
33 fn get_codec<'de, D: Deserializer<'de>>(
43 &self,
44 config: D,
45 ) -> Result<ErasedDynCodec, Self::Error>;
46
47 fn get_codec_typed<'de, T: DynCodec, D: Deserializer<'de>>(
59 &self,
60 config: D,
61 ) -> Result<Option<T>, Self::Error> {
62 self.get_codec(config).map(|codec| codec.downcast().ok())
63 }
64}
65
66impl<R: Registry> Registry for Box<R> {
67 type Error = R::Error;
68
69 fn get_codec<'de, D: Deserializer<'de>>(
70 &self,
71 config: D,
72 ) -> Result<ErasedDynCodec, Self::Error> {
73 R::get_codec(self, config)
74 }
75
76 fn get_codec_typed<'de, T: DynCodec, D: Deserializer<'de>>(
77 &self,
78 config: D,
79 ) -> Result<Option<T>, Self::Error> {
80 R::get_codec_typed(self, config)
81 }
82}
83
84impl<R: Registry> Registry for Arc<R> {
85 type Error = R::Error;
86
87 fn get_codec<'de, D: Deserializer<'de>>(
88 &self,
89 config: D,
90 ) -> Result<ErasedDynCodec, Self::Error> {
91 R::get_codec(self, config)
92 }
93
94 fn get_codec_typed<'de, T: DynCodec, D: Deserializer<'de>>(
95 &self,
96 config: D,
97 ) -> Result<Option<T>, Self::Error> {
98 R::get_codec_typed(self, config)
99 }
100}
101
102pub struct ErasedRegistry {
104 registry: Box<dyn ErasedRegistryDispatch>,
105}
106
107impl ErasedRegistry {
108 pub fn new<T: Registry>(registry: T) -> Self {
110 Self {
111 registry: Box::new(registry),
112 }
113 }
114}
115
116impl Registry for ErasedRegistry {
117 type Error = ErasedError;
118
119 fn get_codec<'de, D: Deserializer<'de>>(
120 &self,
121 config: D,
122 ) -> Result<ErasedDynCodec, Self::Error> {
123 self.registry
124 .erased_get_codec(&mut <dyn erased_serde::Deserializer>::erase(config))
125 }
126}
127
128trait ErasedRegistryDispatch: 'static + Send + Sync {
129 fn erased_get_codec(
130 &self,
131 config: &mut dyn erased_serde::Deserializer,
132 ) -> Result<ErasedDynCodec, ErasedError>;
133}
134
135impl<T: Registry> ErasedRegistryDispatch for T {
136 fn erased_get_codec(
137 &self,
138 config: &mut dyn erased_serde::Deserializer,
139 ) -> Result<ErasedDynCodec, ErasedError> {
140 match self.get_codec(config) {
141 Ok(codec) => Ok(codec),
142 Err(err) => Err(ErasedError::new(err)),
143 }
144 }
145}
146
147pub struct GlobalRegistry;
155
156impl GlobalRegistry {
157 fn get() -> &'static ErasedRegistry {
158 #[expect(unsafe_code)]
159 unsafe extern "C" {
160 #[expect(improper_ctypes)]
161 safe fn _numcodecs_registry_get_global_registry() -> &'static ErasedRegistry;
162 }
163
164 _numcodecs_registry_get_global_registry()
165 }
166
167 pub fn codec_from_config<'de, D: Deserializer<'de>>(
178 config: D,
179 ) -> Result<ErasedDynCodec, D::Error> {
180 Self.get_codec(config).map_err(serde::de::Error::custom)
181 }
182}
183
184impl Registry for GlobalRegistry {
185 type Error = ErasedError;
186
187 fn get_codec<'de, D: Deserializer<'de>>(
188 &self,
189 config: D,
190 ) -> Result<ErasedDynCodec, Self::Error> {
191 Self::get().get_codec(config)
192 }
193
194 fn get_codec_typed<'de, T: DynCodec, D: Deserializer<'de>>(
195 &self,
196 config: D,
197 ) -> Result<Option<T>, Self::Error> {
198 Self::get().get_codec_typed(config)
199 }
200}
201
202#[macro_export]
203macro_rules! export_global {
209 (static REGISTRY: $ty:ty = $init:expr;) => {
210 const _: () = {
211 use std::sync::LazyLock;
212
213 use $crate::ErasedRegistry;
214
215 static _GLOBAL_REGISTRY: LazyLock<ErasedRegistry> =
216 LazyLock::new(|| ErasedRegistry::new($init));
217
218 #[allow(improper_ctypes, unsafe_code)]
219 #[unsafe(no_mangle)]
220 extern "C" fn _numcodecs_registry_get_global_registry() -> &'static ErasedRegistry {
221 LazyLock::force(&_GLOBAL_REGISTRY)
222 }
223 };
224 };
225}
226
227#[derive(Debug, thiserror::Error)]
228#[error("codec not found")]
229pub struct CodecNotFoundError;
231
232pub struct EmptyRegistry;
234
235impl Registry for EmptyRegistry {
236 type Error = CodecNotFoundError;
237
238 fn get_codec<'de, D: Deserializer<'de>>(
239 &self,
240 _config: D,
241 ) -> Result<ErasedDynCodec, Self::Error> {
242 Err(CodecNotFoundError)
243 }
244
245 fn get_codec_typed<'de, T: DynCodec, D: Deserializer<'de>>(
246 &self,
247 _config: D,
248 ) -> Result<Option<T>, Self::Error> {
249 Err(CodecNotFoundError)
250 }
251}