rithm 14.8.0

Arbitrary precision arithmetic.
Documentation
use pyo3::exceptions::PyValueError;
use pyo3::prelude::PyAnyMethods;
use pyo3::sync::PyOnceLock;
use pyo3::types::{PyTuple, PyTypeMethods};
use pyo3::{
    pyclass, pymethods, Bound, Py, PyAny, PyResult, PyTypeInfo, Python,
};
use traiter::numbers::Endianness;

#[pyclass(
    name = "Endianness",
    module = "rithm.enums",
    frozen,
    skip_from_py_object
)]
#[derive(Clone)]
pub(super) struct PyEndianness(Endianness);

#[allow(non_snake_case)]
#[pymethods]
impl PyEndianness {
    #[classattr]
    fn BIG(py: Python<'_>) -> Py<PyEndianness> {
        to_py_endianness_values(py)[0].clone_ref(py)
    }

    #[classattr]
    fn LITTLE(py: Python<'_>) -> Py<PyEndianness> {
        to_py_endianness_values(py)[1].clone_ref(py)
    }

    #[new]
    #[pyo3(signature = (value, /))]
    fn new(value: &Bound<'_, PyAny>, py: Python<'_>) -> PyResult<Py<Self>> {
        let values = to_py_endianness_values(py);
        match value.extract::<usize>() {
            Ok(value) if value < values.len() => {
                Ok(values[value].clone_ref(py))
            }
            _ => Err(PyValueError::new_err(format!(
                "{} is not a valid {}",
                value.repr()?,
                Self::type_object(py).name()?
            ))),
        }
    }

    #[getter]
    fn value(&self) -> u8 {
        match self.0 {
            Endianness::Big => 0,
            Endianness::Little => 1,
        }
    }

    fn __getnewargs__<'py>(
        &self,
        py: Python<'py>,
    ) -> PyResult<Bound<'py, PyTuple>> {
        PyTuple::new(py, [self.value()])
    }

    fn __repr__<'py>(&self, py: Python<'py>) -> PyResult<String> {
        Ok(format!(
            "{}.{}",
            Self::type_object(py).name()?,
            match self.0 {
                Endianness::Big => "BIG",
                Endianness::Little => "LITTLE",
            }
        ))
    }
}

impl From<PyEndianness> for Endianness {
    fn from(value: PyEndianness) -> Self {
        value.0
    }
}

fn to_py_endianness_values(py: Python<'_>) -> &[Py<PyEndianness>; 2usize] {
    static VALUES: PyOnceLock<[Py<PyEndianness>; 2usize]> = PyOnceLock::new();
    VALUES.get_or_init(py, || {
        [
            Bound::new(py, PyEndianness(Endianness::Big))
                .unwrap()
                .into(),
            Bound::new(py, PyEndianness(Endianness::Little))
                .unwrap()
                .into(),
        ]
    })
}