use pyo3::exceptions::PyException;
use pyo3::types::PyType;
use pyo3::{Bound, PyResult, create_exception, pyclass, pymethods};
use crate::time::deltas::TimeDelta;
use crate::time::intervals::TimeDeltaInterval;
create_exception!(
lox_space,
NonFiniteTimeDeltaError,
PyException,
"Python exception raised when a non-finite `TimeDelta` is accessed."
);
#[pyclass(name = "TimeDelta", module = "lox_space", frozen, from_py_object)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PyTimeDelta(pub TimeDelta);
#[pymethods]
impl PyTimeDelta {
#[new]
pub fn new(seconds: f64) -> Self {
Self(TimeDelta::from_seconds_f64(seconds))
}
pub fn __repr__(&self) -> String {
format!("TimeDelta({})", self.to_decimal_seconds())
}
pub fn __str__(&self) -> String {
format!("{} seconds", self.to_decimal_seconds())
}
pub fn __float__(&self) -> f64 {
self.to_decimal_seconds()
}
pub fn __neg__(&self) -> Self {
Self(-self.0)
}
pub fn __add__(&self, other: PyTimeDelta) -> Self {
Self(self.0 + other.0)
}
pub fn __sub__(&self, other: PyTimeDelta) -> Self {
Self(self.0 - other.0)
}
pub fn __mul__(&self, other: f64) -> Self {
Self(other * self.0)
}
pub fn __rmul__(&self, other: f64) -> Self {
Self(other * self.0)
}
pub fn __eq__(&self, other: PyTimeDelta) -> bool {
self.0 == other.0
}
pub fn seconds(&self) -> PyResult<i64> {
self.0.seconds().ok_or(NonFiniteTimeDeltaError::new_err(
"cannot access seconds for non-finite time delta",
))
}
pub fn subsecond(&self) -> PyResult<f64> {
self.0.subsecond().ok_or(NonFiniteTimeDeltaError::new_err(
"cannot access subsecond for non-finite time delta",
))
}
#[classmethod]
pub fn from_seconds(_cls: &Bound<'_, PyType>, seconds: i64) -> Self {
Self(TimeDelta::from_seconds(seconds))
}
#[classmethod]
pub fn from_minutes(_cls: &Bound<'_, PyType>, minutes: f64) -> PyResult<Self> {
Ok(Self(TimeDelta::from_minutes_f64(minutes)))
}
#[classmethod]
pub fn from_hours(_cls: &Bound<'_, PyType>, hours: f64) -> PyResult<Self> {
Ok(Self(TimeDelta::from_hours_f64(hours)))
}
#[classmethod]
pub fn from_days(_cls: &Bound<'_, PyType>, days: f64) -> PyResult<Self> {
Ok(Self(TimeDelta::from_days_f64(days)))
}
#[classmethod]
pub fn from_julian_years(_cls: &Bound<'_, PyType>, years: f64) -> PyResult<Self> {
Ok(Self(TimeDelta::from_julian_years(years)))
}
#[classmethod]
pub fn from_julian_centuries(_cls: &Bound<'_, PyType>, centuries: f64) -> PyResult<Self> {
Ok(Self(TimeDelta::from_julian_centuries(centuries)))
}
#[classmethod]
pub fn from_milliseconds(_cls: &Bound<'_, PyType>, ms: i64) -> Self {
Self(TimeDelta::from_milliseconds(ms))
}
#[classmethod]
pub fn from_microseconds(_cls: &Bound<'_, PyType>, us: i64) -> Self {
Self(TimeDelta::from_microseconds(us))
}
#[classmethod]
pub fn from_nanoseconds(_cls: &Bound<'_, PyType>, ns: i64) -> Self {
Self(TimeDelta::from_nanoseconds(ns))
}
#[classmethod]
pub fn from_picoseconds(_cls: &Bound<'_, PyType>, ps: i64) -> Self {
Self(TimeDelta::from_picoseconds(ps))
}
#[classmethod]
pub fn from_femtoseconds(_cls: &Bound<'_, PyType>, fs: i64) -> Self {
Self(TimeDelta::from_femtoseconds(fs))
}
#[classmethod]
pub fn from_attoseconds(_cls: &Bound<'_, PyType>, atto: i64) -> Self {
Self(TimeDelta::from_attoseconds(atto))
}
#[classmethod]
#[pyo3(signature = (start, end, step=None))]
pub fn range(
_cls: &Bound<'_, PyType>,
start: i64,
end: i64,
step: Option<i64>,
) -> PyResult<Vec<Self>> {
let step = TimeDelta::from_seconds(step.unwrap_or(1));
let interval =
TimeDeltaInterval::new(TimeDelta::from_seconds(start), TimeDelta::from_seconds(end));
Ok(interval.step_by(step).map(Self).collect())
}
pub fn to_decimal_seconds(&self) -> f64 {
self.0.to_seconds().to_f64()
}
}