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}