numcodecs_python/
codec_class.rs1use pyo3::{
2 ffi::PyTypeObject,
3 intern,
4 prelude::*,
5 types::{DerefToPyAny, PyDict, PyType},
6 PyTypeInfo,
7};
8
9use crate::{sealed::Sealed, PyCodec};
10
11#[repr(transparent)]
17pub struct PyCodecClass {
18 _class: PyType,
19}
20
21pub trait PyCodecClassMethods<'py>: Sealed {
23 fn codec_id(&self) -> Result<String, PyErr>;
29
30 fn codec_from_config(
38 &self,
39 config: Borrowed<'_, 'py, PyDict>,
40 ) -> Result<Bound<'py, PyCodec>, PyErr>;
41
42 fn as_type(&self) -> &Bound<'py, PyType>;
44}
45
46impl<'py> PyCodecClassMethods<'py> for Bound<'py, PyCodecClass> {
47 fn codec_id(&self) -> Result<String, PyErr> {
48 let py = self.py();
49
50 let codec_id = self.as_any().getattr(intern!(py, "codec_id"))?.extract()?;
51
52 Ok(codec_id)
53 }
54
55 fn codec_from_config(
56 &self,
57 config: Borrowed<'_, 'py, PyDict>,
58 ) -> Result<Bound<'py, PyCodec>, PyErr> {
59 let py = self.py();
60
61 self.as_any()
62 .call_method1(intern!(py, "from_config"), (config,))?
63 .extract()
64 }
65
66 fn as_type(&self) -> &Bound<'py, PyType> {
67 #[expect(unsafe_code)]
68 unsafe {
70 self.downcast_unchecked()
71 }
72 }
73}
74
75impl Sealed for Bound<'_, PyCodecClass> {}
76
77#[doc(hidden)]
78impl DerefToPyAny for PyCodecClass {}
79
80#[doc(hidden)]
81#[expect(unsafe_code)]
82unsafe impl PyTypeInfo for PyCodecClass {
83 const MODULE: Option<&'static str> = Some("numcodecs.abc");
84 const NAME: &'static str = "Codec";
85
86 #[inline]
87 fn type_object_raw(py: Python) -> *mut PyTypeObject {
88 PyType::type_object_raw(py)
89 }
90
91 #[inline]
92 fn is_type_of(object: &Bound<'_, PyAny>) -> bool {
93 let Ok(ty) = object.downcast::<PyType>() else {
94 return false;
95 };
96
97 ty.is_subclass_of::<PyCodec>().unwrap_or(false)
98 }
99
100 #[inline]
101 fn is_exact_type_of(object: &Bound<'_, PyAny>) -> bool {
102 object.as_ptr() == PyCodec::type_object_raw(object.py()).cast()
103 }
104}