stock-trek 0.1.2

Stock Trek time-series analysis
Documentation
#[cfg(feature = "python")]
use pyo3::prelude::*;
#[cfg(feature = "python")]
use rust_decimal::Decimal;
#[cfg(feature = "python")]
use std::str::FromStr;

#[cfg(feature = "python")]
impl<'a, 'py> FromPyObject<'a, 'py> for crate::data::Real {
    type Error = PyErr;

    fn extract(ob: pyo3::Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
        if let Ok(i) = ob.extract::<i32>() {
            return Ok(crate::data::Real::Int(i));
        }
        if let Ok(i) = ob.extract::<i64>() {
            return Ok(crate::data::Real::Long(i));
        }
        if let Ok(f) = ob.extract::<f32>() {
            return Ok(crate::data::Real::Float(f));
        }
        if let Ok(f) = ob.extract::<f64>() {
            return Ok(crate::data::Real::Double(f));
        }
        if let Ok(s) = ob.extract::<String>() {
            if let Ok(d) = Decimal::from_str(&s) {
                return Ok(crate::data::Real::Decimal(d));
            }
        }

        Err(pyo3::exceptions::PyTypeError::new_err(
            "Expected int, long, float, double, or decimal string",
        ))
    }
}

#[cfg(feature = "python")]
#[pyclass]
pub struct Datum {
    inner: crate::data::Datum,
}

#[cfg(feature = "python")]
#[pyclass]
pub struct TimeSeries {
    inner: crate::data::TimeSeries,
}

#[cfg(feature = "python")]
#[pymethods]
impl TimeSeries {
    #[new]
    pub fn new() -> Self {
        Self {
            inner: crate::data::TimeSeries::new(),
        }
    }

    #[staticmethod]
    pub fn with_capacity(capacity: usize) -> Self {
        Self {
            inner: crate::data::TimeSeries::with_capacity(capacity),
        }
    }

    pub fn add_datum(&mut self, datum: &Datum) {
        self.inner.add_datum(datum.inner.clone());
    }

    pub fn get_datum(&self, index: usize) -> Option<Datum> {
        self.inner
            .get_datum(index)
            .map(|d| Datum { inner: d.clone() })
    }

    pub fn data(&self) -> Vec<Datum> {
        self.inner
            .data()
            .iter()
            .map(|d| Datum { inner: d.clone() })
            .collect()
    }

    pub fn len(&self) -> usize {
        self.inner.len()
    }

    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }
}

#[cfg(feature = "python")]
pub fn add_submodule(py: Python, parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
    let data = PyModule::new(py, "data")?;
    data.add_class::<Datum>()?;
    data.add_class::<TimeSeries>()?;
    parent_module.add_submodule(&data)?;
    Ok(())
}