# pyclass_init.rs - source
Source of the Rust file `/home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/pyo3-0.13.2/src/pyclass_init.rs`.
Keywords: rust, rustlang, rust-lang

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193

    //! Initialization utilities for `#[pyclass]`.
    use crate::callback::IntoPyCallbackOutput;
    use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo};
    use crate::{PyCell, PyClass, PyResult, Python};
    use std::marker::PhantomData;

    /// Initializer for Python types.
    ///
    /// This trait is intended to use internally for distinguishing `#[pyclass]` and
    /// Python native types.
    pub trait PyObjectInit<T: PyTypeInfo>: Sized {
        fn init_class<L: PyLayout<T>>(self, layout: &mut L);
        private_decl! {}
    }

    /// Initializer for Python native type, like `PyDict`.
    pub struct PyNativeTypeInitializer<T: PyTypeInfo>(PhantomData<T>);

    impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
        fn init_class<L: PyLayout<T>>(self, _layout: &mut L) {}
        private_impl! {}
    }

    /// Initializer for our `#[pyclass]` system.
    ///
    /// You can use this type to initalize complicatedly nested `#[pyclass]`.
    ///
    /// # Example
    ///
    /// ```
    /// # use pyo3::prelude::*;
    /// # use pyo3::py_run;
    /// #[pyclass(subclass)]
    /// struct BaseClass {
    ///     #[pyo3(get)]
    ///     basename: &'static str,
    /// }
    /// #[pyclass(extends=BaseClass, subclass)]
    /// struct SubClass {
    ///     #[pyo3(get)]
    ///     subname: &'static str,
    /// }
    /// #[pyclass(extends=SubClass)]
    /// struct SubSubClass {
    ///     #[pyo3(get)]
    ///     subsubname: &'static str,
    /// }
    ///
    /// #[pymethods]
    /// impl SubSubClass {
    ///     #[new]
    ///     fn new() -> PyClassInitializer<Self> {
    ///         PyClassInitializer::from(BaseClass { basename: "base" })
    ///             .add_subclass(SubClass { subname: "sub" })
    ///             .add_subclass(SubSubClass { subsubname: "subsub" })
    ///     }
    /// }
    /// let gil = Python::acquire_gil();
    /// let py = gil.python();
    /// let typeobj = py.get_type::<SubSubClass>();
    /// let inst = typeobj.call((), None).unwrap();
    /// py_run!(py, inst, r#"
    ///         assert inst.basename == 'base'
    ///         assert inst.subname == 'sub'
    ///         assert inst.subsubname == 'subsub'"#);
    /// ```
    pub struct PyClassInitializer<T: PyClass> {
        init: T,
        super_init: <T::BaseType as PyTypeInfo>::Initializer,
    }

    impl<T: PyClass> PyClassInitializer<T> {
        /// Construct new initializer from value `T` and base class' initializer.
        ///
        /// We recommend to mainly use `add_subclass`, instead of directly call `new`.
        pub fn new(init: T, super_init: <T::BaseType as PyTypeInfo>::Initializer) -> Self {
            Self { init, super_init }
        }

        /// Constructs a new initializer from base class' initializer.
        ///
        /// # Example
        /// ```
        /// # use pyo3::prelude::*;
        /// #[pyclass]
        /// struct BaseClass {
        ///     value: u32,
        /// }
        ///
        /// impl BaseClass {
        ///     fn new(value: i32) -> PyResult<Self> {
        ///         Ok(Self {
        ///             value: std::convert::TryFrom::try_from(value)?,
        ///         })
        ///     }
        /// }
        /// #[pyclass(extends=BaseClass)]
        /// struct SubClass {}
        ///
        /// #[pymethods]
        /// impl SubClass {
        ///     #[new]
        ///     fn new(value: i32) -> PyResult<PyClassInitializer<Self>> {
        ///         let base_init = PyClassInitializer::from(BaseClass::new(value)?);
        ///         Ok(base_init.add_subclass(SubClass {}))
        ///     }
        /// }
        /// ```
        pub fn add_subclass<S>(self, subclass_value: S) -> PyClassInitializer<S>
        where
            S: PyClass + PyTypeInfo<BaseType = T>,
            S::BaseLayout: PySizedLayout<T>,
            S::BaseType: PyTypeInfo<Initializer = Self>,
        {
            PyClassInitializer::new(subclass_value, self)
        }

        /// Create a new PyCell and initialize it.
        #[doc(hidden)]
        pub fn create_cell(self, py: Python) -> PyResult<*mut PyCell<T>>
        where
            T: PyClass,
            T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
        {
            unsafe { self.create_cell_from_subtype(py, T::type_object_raw(py)) }
        }

        /// Create a new PyCell and initialize it given a typeobject `subtype`.
        /// Called by our `tp_new` generated by the `#[new]` attribute.
        ///
        /// # Safety
        /// `subtype` must be a subclass of T.
        #[doc(hidden)]
        pub unsafe fn create_cell_from_subtype(
            self,
            py: Python,
            subtype: *mut crate::ffi::PyTypeObject,
        ) -> PyResult<*mut PyCell<T>>
        where
            T: PyClass,
            T::BaseLayout: PyBorrowFlagLayout<T::BaseType>,
        {
            let cell = PyCell::internal_new(py, subtype)?;
            self.init_class(&mut *cell);
            Ok(cell)
        }
    }

    impl<T: PyClass> PyObjectInit<T> for PyClassInitializer<T> {
        fn init_class<L: PyLayout<T>>(self, layout: &mut L) {
            let Self { init, super_init } = self;
            layout.py_init(init);
            if let Some(super_obj) = layout.get_super() {
                super_init.init_class(super_obj);
            }
        }
        private_impl! {}
    }

    impl<T> From<T> for PyClassInitializer<T>
    where
        T: PyClass,
        T::BaseType: PyTypeInfo<Initializer = PyNativeTypeInitializer<T::BaseType>>,
    {
        fn from(value: T) -> PyClassInitializer<T> {
            Self::new(value, PyNativeTypeInitializer(PhantomData))
        }
    }

    impl<S, B> From<(S, B)> for PyClassInitializer<S>
    where
        S: PyClass + PyTypeInfo<BaseType = B>,
        S::BaseLayout: PySizedLayout<B>,
        B: PyClass + PyTypeInfo<Initializer = PyClassInitializer<B>>,
        B::BaseType: PyTypeInfo<Initializer = PyNativeTypeInitializer<B::BaseType>>,
    {
        fn from(sub_and_base: (S, B)) -> PyClassInitializer<S> {
            let (sub, base) = sub_and_base;
            PyClassInitializer::from(base).add_subclass(sub)
        }
    }

    // Implementation used by proc macros to allow anything convertible to PyClassInitializer<T> to be
    // the return value of pyclass #[new] method (optionally wrapped in `Result<U, E>`).
    impl<T, U> IntoPyCallbackOutput<PyClassInitializer<T>> for U
    where
        T: PyClass,
        U: Into<PyClassInitializer<T>>,
    {
        fn convert(self, _py: Python) -> PyResult<PyClassInitializer<T>> {
            Ok(self.into())
        }
    }