numcodecs_python/registry.rs
1use pyo3::{prelude::*, sync::GILOnceCell, types::PyDict};
2
3#[expect(unused_imports)] // FIXME: use expect, only used in docs
4use crate::PyCodecClassMethods;
5use crate::{PyCodec, PyCodecClass};
6
7/// Dynamic registry of codec classes.
8pub struct PyCodecRegistry {
9 _private: (),
10}
11
12impl PyCodecRegistry {
13 /// Instantiate a codec from a configuration dictionary.
14 ///
15 /// The config *must* include the `id` field with the
16 /// [`PyCodecClassMethods::codec_id`].
17 ///
18 /// # Errors
19 ///
20 /// Errors if no codec with a matching `id` has been registered, or if
21 /// constructing the codec fails.
22 pub fn get_codec<'py>(config: Borrowed<'_, 'py, PyDict>) -> Result<Bound<'py, PyCodec>, PyErr> {
23 static GET_CODEC: GILOnceCell<Py<PyAny>> = GILOnceCell::new();
24
25 let py = config.py();
26
27 let get_codec = GET_CODEC.import(py, "numcodecs.registry", "get_codec")?;
28
29 get_codec.call1((config,))?.extract()
30 }
31
32 /// Register a codec class.
33 ///
34 /// If the `codec_id` is provided, it is used instead of
35 /// [`PyCodecClassMethods::codec_id`].
36 ///
37 /// This function maintains a mapping from codec identifiers to codec
38 /// classes. When a codec class is registered, it will replace any class
39 /// previously registered under the same codec identifier, if present.
40 ///
41 /// # Errors
42 ///
43 /// Errors if registering the codec class fails.
44 pub fn register_codec(
45 class: Borrowed<PyCodecClass>,
46 codec_id: Option<&str>,
47 ) -> Result<(), PyErr> {
48 static REGISTER_CODEC: GILOnceCell<Py<PyAny>> = GILOnceCell::new();
49
50 let py = class.py();
51
52 let register_codec = REGISTER_CODEC.import(py, "numcodecs.registry", "register_codec")?;
53
54 register_codec.call1((class, codec_id))?;
55
56 Ok(())
57 }
58}