apple-quant-algorithmic 0.4.0

Apple Quant's algorithmic library.
Documentation
mod checked;
mod ext;
mod unchecked;
mod volume;

use std::borrow::Borrow;

use std::{
	ops::{Deref, DerefMut},
	fmt::Debug, hash::Hash,
};

use apple_quant_core::{AddUnchecked, SubUnchecked};

pub use checked::*;
pub use ext::*;
pub use unchecked::*;
pub use volume::*;

#[cfg(debug_assertions)]
pub type ZeroableType<T> = ZeroableChecked<T>;

#[cfg(not(debug_assertions))]
pub type ZeroableType<T> = ZeroableUnchecked<T>;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Zeroable<T: ZeroableVolume>(ZeroableType<T>);

impl<T: ZeroableVolume> Zeroable<T> {
	pub const ZERO: Self = Self(ZeroableType::ZERO);

	/// Always safe regardless of `debug_assertions` and `T` zeroed state.
	pub fn from_optional(
		t: Option<T>,
	) -> Self {
		#[cfg(not(debug_assertions))]
		let t = t.unwrap_or(T::ZERO);

		#[cfg(debug_assertions)]
		let t = if let Some(
			t,
		) = t && t.is_zero() {
			// Sanitize `T` to `None`.
			None
		} else {
			t
		};

		Self(ZeroableType::new(t))
	}

	/// Always safe regardless of `debug_assertions` and `T` zeroed state.
	pub fn from_zeroable(
		t: T,
	) -> Self {
		#[cfg(debug_assertions)]
		let t = if t.is_zero() {
			None
		} else {
			Some(t)
		};

		Self(ZeroableType::new(t))
	}

	pub fn is_zero(
		&self,
	) -> bool {
		self.0.as_optional_nonzero_ref().is_none()
	}
}

impl<T: ZeroableVolume> ZeroableExt<T> for Zeroable<T> {
	fn as_optional_nonzero_ref(
		&self,
	) -> Option<&T> {
		self.0.as_optional_nonzero_ref()
	}

	fn as_optional_nonzero_mut(
		&mut self,
	) -> Option<&mut T> {
		self.0.as_optional_nonzero_mut()
	}

	fn into_optional_nonzero(
		self,
	) -> Option<T> {
		self.0.into_optional_nonzero()
	}

	fn as_zeroable(
		&self,
	) -> T {
		self.0.as_zeroable()
	}

	fn into_zeroable(
		self,
	) -> T {
		self.0.into_zeroable()
	}

	fn as_nonzero_unchecked_ref(
		&self,
	) -> &T {
		self.0.as_nonzero_unchecked_ref()
	}

	fn as_nonzero_unchecked_mut(
		&mut self,
	) -> &mut T {
		self.0.as_nonzero_unchecked_mut()
	}

	fn into_nonzero_unchecked(
		self,
	) -> T {
		self.0.into_nonzero_unchecked()
	}
}

impl<T: ZeroableVolume> Deref for Zeroable<T> {
	type Target = ZeroableType<T>;

	fn deref(
		&self,
	) -> &Self::Target {
		&self.0
	}
}

impl<T: ZeroableVolume> DerefMut for Zeroable<T> {
	fn deref_mut(
		&mut self,
	) -> &mut Self::Target {
		&mut self.0
	}
}

impl<T: ZeroableVolume> From<Zeroable<T>> for Result<Zeroable<T>, ()> {
	fn from(
		value: Zeroable<T>,
	) -> Self {
		Ok(value)
	}
}

// Manual implementation because we only want unchecked impls.
impl<T: ZeroableVolume> AddUnchecked<Zeroable<T>, Zeroable<T>> for Zeroable<T> {
	fn add_unchecked(
		self,
		rhs: impl Borrow<Zeroable<T>>,
	) -> Zeroable<T> {
		let lhs = self.as_zeroable();
		let rhs = rhs.borrow().as_zeroable();

		Zeroable::from_zeroable(lhs.add_unchecked(rhs))
	}
}

// Manual implementation because we only want unchecked impls.
impl<T: ZeroableVolume> AddUnchecked<Zeroable<T>, Zeroable<T>> for &Zeroable<T> {
	fn add_unchecked(
		self,
		rhs: impl Borrow<Zeroable<T>>,
	) -> Zeroable<T> {
		(*self).add_unchecked(rhs)
	}
}

// Manual implementation because we only want unchecked impls.
impl<T: ZeroableVolume> SubUnchecked<Zeroable<T>, Zeroable<T>> for Zeroable<T> {
	fn sub_unchecked(
		self,
		rhs: impl Borrow<Zeroable<T>>,
	) -> Zeroable<T> {
		let lhs = self.as_zeroable();
		let rhs = rhs.borrow().as_zeroable();

		Zeroable::from_zeroable(lhs.sub_unchecked(rhs))
	}
}

// Manual implementation because we only want unchecked impls.
impl<T: ZeroableVolume> SubUnchecked<Zeroable<T>, Zeroable<T>> for &Zeroable<T> {
	fn sub_unchecked(
		self,
		rhs: impl Borrow<Zeroable<T>>,
	) -> Zeroable<T> {
		(*self).sub_unchecked(rhs)
	}
}