use std::{convert::TryFrom, fmt};
use serde::{Deserialize, Serialize, de};
use super::{
SATS_PER_BTC, error::CrossLeverageValidationError, leverage::Leverage, margin::Margin,
price::Price, quantity::cross::CrossQuantity,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct CrossLeverage(u8);
impl CrossLeverage {
pub const MIN: Self = Self(1);
pub const MAX: Self = Self(100);
pub fn bounded<T>(value: T) -> Self
where
T: Into<f64>,
{
let as_f64: f64 = value.into();
let rounded = as_f64.round().max(0.0) as u8;
let clamped = rounded.clamp(Self::MIN.0, Self::MAX.0);
Self(clamped)
}
pub fn as_u8(&self) -> u8 {
self.0
}
pub fn as_u64(&self) -> u64 {
self.0 as u64
}
pub fn as_i64(&self) -> i64 {
self.0 as i64
}
pub fn as_f64(&self) -> f64 {
self.0 as f64
}
pub fn try_calculate_rounded(
quantity: CrossQuantity,
running_margin: Margin,
price: Price,
) -> Result<Self, CrossLeverageValidationError> {
let leverage_value =
quantity.as_f64() * SATS_PER_BTC / (running_margin.as_f64() * price.as_f64());
Self::try_from(leverage_value.round())
}
}
impl From<CrossLeverage> for u8 {
fn from(value: CrossLeverage) -> u8 {
value.0
}
}
impl From<CrossLeverage> for u16 {
fn from(value: CrossLeverage) -> u16 {
value.0 as u16
}
}
impl From<CrossLeverage> for u32 {
fn from(value: CrossLeverage) -> u32 {
value.0 as u32
}
}
impl From<CrossLeverage> for u64 {
fn from(value: CrossLeverage) -> u64 {
value.0 as u64
}
}
impl From<CrossLeverage> for i16 {
fn from(value: CrossLeverage) -> i16 {
value.0 as i16
}
}
impl From<CrossLeverage> for i32 {
fn from(value: CrossLeverage) -> i32 {
value.0 as i32
}
}
impl From<CrossLeverage> for i64 {
fn from(value: CrossLeverage) -> i64 {
value.0 as i64
}
}
impl From<CrossLeverage> for i128 {
fn from(value: CrossLeverage) -> i128 {
value.0 as i128
}
}
impl From<CrossLeverage> for f64 {
fn from(value: CrossLeverage) -> f64 {
value.as_f64()
}
}
impl From<CrossLeverage> for Leverage {
fn from(value: CrossLeverage) -> Leverage {
Leverage::try_from(value.as_f64()).expect("Must be a valid `Leverage`")
}
}
impl TryFrom<u8> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Self::try_from(value as u128)
}
}
impl TryFrom<u16> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: u16) -> Result<Self, Self::Error> {
Self::try_from(value as u128)
}
}
impl TryFrom<u32> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
Self::try_from(value as u128)
}
}
impl TryFrom<u64> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
Self::try_from(value as u128)
}
}
impl TryFrom<u128> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: u128) -> Result<Self, Self::Error> {
if value < Self::MIN.0 as u128 {
return Err(CrossLeverageValidationError::TooLow {
value: value as i128,
});
}
if value > Self::MAX.0 as u128 {
return Err(CrossLeverageValidationError::TooHigh { value });
}
Ok(CrossLeverage(value as u8))
}
}
impl TryFrom<usize> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: usize) -> Result<Self, Self::Error> {
Self::try_from(value as u128)
}
}
impl TryFrom<i8> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: i8) -> Result<Self, Self::Error> {
Self::try_from(value as i128)
}
}
impl TryFrom<i16> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: i16) -> Result<Self, Self::Error> {
Self::try_from(value as i128)
}
}
impl TryFrom<i32> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
Self::try_from(value as i128)
}
}
impl TryFrom<i64> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: i64) -> Result<Self, Self::Error> {
Self::try_from(value as i128)
}
}
impl TryFrom<i128> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: i128) -> Result<Self, Self::Error> {
if value < Self::MIN.0 as i128 {
return Err(CrossLeverageValidationError::TooLow { value });
}
if value > Self::MAX.0 as i128 {
return Err(CrossLeverageValidationError::TooHigh {
value: value as u128,
});
}
Ok(CrossLeverage(value as u8))
}
}
impl TryFrom<isize> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: isize) -> Result<Self, Self::Error> {
Self::try_from(value as i128)
}
}
impl TryFrom<f32> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: f32) -> Result<Self, Self::Error> {
Self::try_from(value as f64)
}
}
impl TryFrom<f64> for CrossLeverage {
type Error = CrossLeverageValidationError;
fn try_from(value: f64) -> Result<Self, Self::Error> {
if value.fract() != 0.0 {
return Err(CrossLeverageValidationError::NotAnInteger { value });
}
Self::try_from(value as i128)
}
}
impl fmt::Display for CrossLeverage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Serialize for CrossLeverage {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_u8(self.0)
}
}
impl<'de> Deserialize<'de> for CrossLeverage {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let leverage_u8 = u8::deserialize(deserializer)?;
CrossLeverage::try_from(leverage_u8).map_err(|e| de::Error::custom(e.to_string()))
}
}