apple-quant-algorithmic 0.3.0

Apple Quant's algorithmic library.
use std::{
	ops::{Add, Sub},
	time::{SystemTime, UNIX_EPOCH},
};

use apple_quant_core::{TimeDeltaExt, UnwrapOptionExt, UnwrapResultExt};

use chrono::{Duration, NaiveTime};

use chrono_tz::Tz;
use time::UtcDateTime;

use super::{Timestamp, TimestampType};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UtcNs(TimestampType);

impl UtcNs {
	#[inline]
	pub(crate) unsafe fn from_utc_date_time(
		utc_date_time: &UtcDateTime,
	) -> Self {
		unsafe {
			Self::new_unchecked(utc_date_time.unix_timestamp_nanos())
		}
	}

	#[inline]
	pub(crate) fn new_unchecked(
		utc_ns: TimestampType,
	) -> Self {
		Self(utc_ns)
	}

	#[cfg(feature = "timestamp-u64")]
	#[inline]
	pub(super) fn now() -> Self {
		let now = SystemTime::now()
			.duration_since(UNIX_EPOCH).unwrap_release_unsafe();

		let now = (now.as_secs() * 1_000_000_000) + (now.subsec_nanos() as u64);
		Self(now)
	}

	#[cfg(not(feature = "timestamp-u64"))]
	#[inline]
	pub(super) fn now() -> Self {
		let now = unsafe {
			SystemTime::now()
				.duration_since(UNIX_EPOCH).unwrap_unchecked_release()
		};

		let now = now.as_nanos() as i128;
		Self(now)
	}

	#[inline]
	pub fn as_timestamp_type(
		&self,
	) -> &TimestampType {
		&self.0
	}

	#[inline]
	pub fn into_timestamp_type(
		self,
	) -> TimestampType {
		self.0
	}

	#[inline]
	pub fn previous_time(
		&self,
		tz: Tz,
		naive_time: &NaiveTime,
	) -> Self {
		unimplemented!()
	}

	#[inline]
	pub fn as_timestamp(
		&self,
	) -> Timestamp {
		(*self).into()
	}

	#[inline]
	pub fn into_timestamp(
		self,
	) -> Timestamp {
		self.into()
	}
}

impl From<Timestamp> for UtcNs {
	fn from(
		value: Timestamp,
	) -> Self {
		value.into_utc_ns()
	}
}

impl Add<Duration> for UtcNs {
	type Output = Self;

	#[cfg(feature = "timestamp-u64")]
	#[inline]
	fn add(
		mut self,
		rhs: Duration,
	) -> Self::Output {
		let duration_ns = (rhs.num_seconds() * 1_000_000_000) as u64 +
			(rhs.subsec_nanos() as u64);

		self.0 += duration_ns;
		self
	}

	#[cfg(not(feature = "timestamp-u64"))]
	#[inline]
	fn add(
		mut self,
		rhs: Duration,
	) -> Self::Output {
		let duration_ns = (rhs.num_seconds() * 1_000_000_000) as i128 +
			(rhs.subsec_nanos() as i128);

		self.0 += duration_ns;
		self
	}
}

impl Add<&Duration> for UtcNs {
	type Output = Self;

	#[inline]
	fn add(
		self,
		rhs: &Duration,
	) -> Self::Output {
		self + *rhs
	}
}

impl Sub<Duration> for UtcNs {
	type Output = Self;

	#[cfg(feature = "timestamp-u64")]
	#[inline]
	fn sub(
		mut self,
		rhs: Duration,
	) -> Self::Output {
		let duration_ns = (rhs.num_seconds() * 1_000_000_000) as u64 +
			(rhs.subsec_nanos() as u64);

		self.0 -= duration_ns;
		self
	}

	#[cfg(not(feature = "timestamp-u64"))]
	#[inline]
	fn sub(
		mut self,
		rhs: Duration,
	) -> Self::Output {
		let duration_ns = (rhs.num_seconds() * 1_000_000_000) as i128 +
			(rhs.subsec_nanos() as i128);

		self.0 -= duration_ns;
		self
	}
}

impl Sub<&Duration> for UtcNs {
	type Output = Self;

	#[inline]
	fn sub(
		self,
		rhs: &Duration,
	) -> Self::Output {
		self - *rhs
	}
}

impl Sub for UtcNs {
	type Output = Duration;

	fn sub(
		self,
		rhs: Self,
	) -> Self::Output {
		let nanoseconds = self.0 - rhs.0;

		unsafe {
			Duration::nanoseconds_i128(nanoseconds).unwrap_unchecked_release()
		}
	}
}

impl Sub for &UtcNs {
	type Output = Duration;

	fn sub(
		self,
		rhs: Self,
	) -> Self::Output {
		*self - *rhs
	}
}