use std::{
cmp,
ops::{Add, AddAssign, Sub, SubAssign},
};
use crate::{UnwrapOptionExt, UnwrapResultExt, instrument::InstrumentSpec};
use super::{AggressiveVolume, DirectionalIntent, DirectionlessVolume, RestingVolume, VolumeDelta};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DirectionalIntentVolume<IS: InstrumentSpec> {
pub directional_intent: DirectionalIntent,
pub directionless_volume: DirectionlessVolume<IS>,
}
impl<IS: InstrumentSpec> DirectionalIntentVolume<IS> {
pub fn as_flipped(&self) -> Self {
Self {
directional_intent: self
.directional_intent
.as_flipped(),
directionless_volume: self.directionless_volume,
}
}
pub fn as_zeroable(&self) -> ZeroableDirectionalIntentVolume<IS> {
self.into()
}
}
impl<IS: InstrumentSpec> Add for DirectionalIntentVolume<IS> {
type Output = Option<Self>;
fn add(
mut self,
mut rhs: Self,
) -> Self::Output {
if self.directional_intent == rhs.directional_intent {
self.directionless_volume += rhs.directionless_volume;
return Some(self);
}
if self.directionless_volume == rhs.directionless_volume {
return None;
}
if self.directionless_volume > rhs.directionless_volume {
let directionless_volume = (self.directionless_volume - rhs.directionless_volume)
.unwrap_release_unsafe()
.unwrap_release_unsafe();
self.directionless_volume = directionless_volume;
return Some(self);
} else {
let directionless_volume = (rhs.directionless_volume - self.directionless_volume)
.unwrap_release_unsafe()
.unwrap_release_unsafe();
rhs.directionless_volume = directionless_volume;
return Some(rhs);
}
}
}
impl<IS: InstrumentSpec> Sub for DirectionalIntentVolume<IS> {
type Output = Option<Self>;
fn sub(
self,
mut rhs: Self,
) -> Self::Output {
rhs.directional_intent.flip();
self + rhs
}
}
impl<IS: InstrumentSpec> From<AggressiveVolume<IS>> for DirectionalIntentVolume<IS> {
fn from(value: AggressiveVolume<IS>) -> Self {
(&value).into()
}
}
impl<IS: InstrumentSpec> From<&AggressiveVolume<IS>> for DirectionalIntentVolume<IS> {
fn from(value: &AggressiveVolume<IS>) -> Self {
Self {
directional_intent: value.aggressor_side().into(),
directionless_volume: *value.as_directionless_volume(),
}
}
}
impl<IS: InstrumentSpec> From<RestingVolume<IS>> for DirectionalIntentVolume<IS> {
fn from(value: RestingVolume<IS>) -> Self {
Self {
directional_intent: value.resting_side().into(),
directionless_volume: *value.as_directionless_volume(),
}
}
}
impl<IS: InstrumentSpec> From<VolumeDelta<IS>> for Option<DirectionalIntentVolume<IS>> {
fn from(value: VolumeDelta<IS>) -> Self {
match value {
VolumeDelta::Zero => None,
VolumeDelta::AggressiveDelta {
directionless_volume,
aggressor_side,
} => Some(DirectionalIntentVolume {
directional_intent: aggressor_side.as_directional_intent(),
directionless_volume,
}),
VolumeDelta::RestingDelta {
directionless_volume,
resting_side,
} => Some(DirectionalIntentVolume {
directional_intent: resting_side.as_directional_intent(),
directionless_volume,
}),
}
}
}
impl<IS: InstrumentSpec> PartialOrd for DirectionalIntentVolume<IS> {
fn partial_cmp(
&self,
other: &Self,
) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<IS: InstrumentSpec> Ord for DirectionalIntentVolume<IS> {
fn cmp(
&self,
other: &Self,
) -> cmp::Ordering {
match (
self.directional_intent,
other.directional_intent,
) {
(DirectionalIntent::Positive, DirectionalIntent::Negative) => cmp::Ordering::Greater,
(DirectionalIntent::Negative, DirectionalIntent::Positive) => cmp::Ordering::Less,
_ => {
if self.directionless_volume == other.directionless_volume {
cmp::Ordering::Equal
} else if self.directionless_volume > other.directionless_volume {
cmp::Ordering::Greater
} else {
cmp::Ordering::Less
}
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ZeroableDirectionalIntentVolume<IS: InstrumentSpec>(Option<DirectionalIntentVolume<IS>>);
impl<IS: InstrumentSpec> ZeroableDirectionalIntentVolume<IS> {
pub const ZERO: Self = Self(None);
pub fn new(directional_intent_volume: Option<DirectionalIntentVolume<IS>>) -> Self {
Self(directional_intent_volume)
}
pub fn as_flipped(&self) -> Self {
let Some(directional_intent_volume) = &self.0 else {
return Self(None);
};
Self(Some(
directional_intent_volume.as_flipped(),
))
}
pub fn directional_intent_volume(&self) -> &Option<DirectionalIntentVolume<IS>> {
&self.0
}
}
impl<IS: InstrumentSpec> From<DirectionalIntentVolume<IS>> for ZeroableDirectionalIntentVolume<IS> {
fn from(value: DirectionalIntentVolume<IS>) -> Self {
Self(Some(value))
}
}
impl<IS: InstrumentSpec> From<&DirectionalIntentVolume<IS>>
for ZeroableDirectionalIntentVolume<IS>
{
fn from(value: &DirectionalIntentVolume<IS>) -> Self {
Self(Some(*value))
}
}
impl<IS: InstrumentSpec> From<Option<DirectionalIntentVolume<IS>>>
for ZeroableDirectionalIntentVolume<IS>
{
fn from(value: Option<DirectionalIntentVolume<IS>>) -> Self {
Self(value)
}
}
impl<IS: InstrumentSpec> From<&Option<DirectionalIntentVolume<IS>>>
for ZeroableDirectionalIntentVolume<IS>
{
fn from(value: &Option<DirectionalIntentVolume<IS>>) -> Self {
Self(*value)
}
}
impl<IS: InstrumentSpec> Add for ZeroableDirectionalIntentVolume<IS> {
type Output = Self;
fn add(
self,
rhs: Self,
) -> Self::Output {
match (self.0, rhs.0) {
(Some(self_directional_intent_volume), Some(rhs_directional_intent_volume)) => {
(self_directional_intent_volume + rhs_directional_intent_volume).into()
}
(Some(self_directional_intent_volume), None) => {
Some(self_directional_intent_volume).into()
}
(None, Some(rhs_directional_intent_volume)) => {
Some(rhs_directional_intent_volume).into()
}
(None, None) => None.into(),
}
}
}
impl<IS: InstrumentSpec> Sub for ZeroableDirectionalIntentVolume<IS> {
type Output = Self;
fn sub(
self,
mut rhs: Self,
) -> Self::Output {
rhs = rhs.as_flipped();
self + rhs
}
}
impl<IS: InstrumentSpec> AddAssign for ZeroableDirectionalIntentVolume<IS> {
fn add_assign(
&mut self,
rhs: Self,
) {
*self = *self + rhs
}
}
impl<IS: InstrumentSpec> SubAssign for ZeroableDirectionalIntentVolume<IS> {
fn sub_assign(
&mut self,
rhs: Self,
) {
*self = *self - rhs;
}
}
impl<IS: InstrumentSpec> Default for ZeroableDirectionalIntentVolume<IS> {
fn default() -> Self {
Self(None)
}
}
impl<IS: InstrumentSpec> PartialOrd for ZeroableDirectionalIntentVolume<IS> {
fn partial_cmp(
&self,
other: &Self,
) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<IS: InstrumentSpec> Ord for ZeroableDirectionalIntentVolume<IS> {
fn cmp(
&self,
other: &Self,
) -> cmp::Ordering {
match (self, other) {
(Self(None), Self(None)) => cmp::Ordering::Equal,
(Self(None), Self(Some(other_directional_intent_volume))) => {
if other_directional_intent_volume.directional_intent == DirectionalIntent::Positive
{
cmp::Ordering::Less
} else {
cmp::Ordering::Greater
}
}
(Self(Some(self_directional_intent_volume)), Self(None)) => {
if self_directional_intent_volume.directional_intent == DirectionalIntent::Positive
{
cmp::Ordering::Greater
} else {
cmp::Ordering::Less
}
}
(
Self(Some(self_directional_intent_volume)),
Self(Some(other_directional_intent_volume)),
) => self_directional_intent_volume.cmp(other_directional_intent_volume),
}
}
}