Skip to content

Commit

Permalink
rpc - add serialize for hp-fixed for rpc
Browse files Browse the repository at this point in the history
  • Loading branch information
theBeardA committed Jul 28, 2023
1 parent 0d5ea9f commit 35a055f
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 38 deletions.
10 changes: 6 additions & 4 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3479,9 +3479,11 @@ name = "hp-fixed"
version = "0.1.0"
dependencies = [
"anyhow",
"bincode",
"num-bigint",
"num-traits",
"serde",
"serde_json",
]

[[package]]
Expand Down Expand Up @@ -6745,9 +6747,9 @@ dependencies = [

[[package]]
name = "serde"
version = "1.0.173"
version = "1.0.177"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91f70896d6720bc714a4a57d22fc91f1db634680e65c8efe13323f1fa38d53f"
checksum = "63ba2516aa6bf82e0b19ca8b50019d52df58455d3cf9bdaf6315225fdd0c560a"
dependencies = [
"serde_derive",
]
Expand Down Expand Up @@ -6793,9 +6795,9 @@ dependencies = [

[[package]]
name = "serde_derive"
version = "1.0.173"
version = "1.0.177"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6250dde8342e0232232be9ca3db7aa40aceb5a3e5dd9bddbc00d99a007cde49"
checksum = "401797fe7833d72109fedec6bfcbe67c0eed9b99772f26eb8afd261f0abc6fd3"
dependencies = [
"proc-macro2 1.0.66",
"quote 1.0.31",
Expand Down
18 changes: 5 additions & 13 deletions core/rpc/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,7 @@ async fn test_rpc_get_flk_balance() -> Result<()> {
if value.get("result").is_some() {
// Parse the response as a successful response
let success_response: RpcSuccessResponse<HpUfixed<18>> = serde_json::from_value(value)?;
assert_eq!(
HpUfixed::<18>::new(1_000_u32.into()),
success_response.result
);
assert_eq!(HpUfixed::<18>::from(1_000_u32), success_response.result);
} else {
panic!("Rpc Error: {value}")
}
Expand Down Expand Up @@ -315,12 +312,10 @@ async fn test_rpc_get_staked() -> Result<()> {
)
.await?;
rpc.config.port = port;

task::spawn(async move {
rpc.start().await;
});
wait_for_server_start(port).await?;

let req = json!({
"jsonrpc": "2.0",
"method":"flk_get_staked",
Expand All @@ -333,12 +328,9 @@ async fn test_rpc_get_staked() -> Result<()> {
if response.status().is_success() {
let value: Value = response.json().await?;
if value.get("result").is_some() {
// Parse the response as a successful response
//Parse the response as a successful response
let success_response: RpcSuccessResponse<HpUfixed<18>> = serde_json::from_value(value)?;
assert_eq!(
HpUfixed::<18>::new(1_000_u32.into()),
success_response.result
);
assert_eq!(HpUfixed::<18>::from(1_000_u32), success_response.result);
} else {
panic!("Rpc Error: {value}")
}
Expand Down Expand Up @@ -402,7 +394,7 @@ async fn test_rpc_get_stables_balance() -> Result<()> {
if value.get("result").is_some() {
// Parse the response as a successful response
let success_response: RpcSuccessResponse<HpUfixed<6>> = serde_json::from_value(value)?;
assert_eq!(HpUfixed::<6>::new(2_00_u32.into()), success_response.result);
assert_eq!(HpUfixed::<6>::from(2_00_u32), success_response.result);
} else {
panic!("Rpc Error: {value}")
}
Expand Down Expand Up @@ -660,7 +652,7 @@ async fn test_rpc_get_locked() -> Result<()> {
if value.get("result").is_some() {
// Parse the response as a successful response
let success_response: RpcSuccessResponse<HpUfixed<18>> = serde_json::from_value(value)?;
assert_eq!(HpUfixed::<18>::new(500_u32.into()), success_response.result);
assert_eq!(HpUfixed::<18>::from(500_u32), success_response.result);
} else {
panic!("Rpc Error: {value}")
}
Expand Down
3 changes: 3 additions & 0 deletions lib/hp-fixed/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ num-bigint = {version = "0.4.3", features=["serde"]}
num-traits ="0.2.15"
serde = { version = "1.0", features = ["derive"] }

[dev-dependencies]
serde_json.workspace = true
bincode.workspace = true
10 changes: 5 additions & 5 deletions lib/hp-fixed/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ async fn main() {

assert_eq!(z, HpFixed::<5>::from(30.24690));

let value = HpFixed::<19>::new(BigInt::from(std::i32::MAX as i64 + 1));
let value = HpFixed::<19>::from(std::i32::MAX as i64 + 1);
assert_eq!(
TryInto::<isize>::try_into(value.clone()).unwrap(),
std::i32::MAX as isize + 1
Expand All @@ -44,13 +44,13 @@ async fn main() {
use hp_fixed::unsigned::HpUfixed;
use num_bigint::BigUint;

let a = HpUfixed::<5>::new(BigUint::from(10u32));
let b = HpUfixed::<5>::new(BigUint::from(20u32));
let a = HpUfixed::<5>::from(10u32);
let b = HpUfixed::<5>::from(20u32);
let c = a + b;

assert_eq!(c, HpUfixed::<5>::new(BigUint::from(30u32)));
assert_eq!(c, HpUfixed::<5>::from(30u32));

let value = HpUfixed::<20>::new(BigUint::from(std::u64::MAX as u128 + 1_u128));
let value = HpUfixed::<20>::from(std::u64::MAX as u128 + 1_u128);
assert_eq!(
std::u64::MAX as u128 + 1_u128,
value.clone().try_into().unwrap()
Expand Down
28 changes: 27 additions & 1 deletion lib/hp-fixed/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,32 @@ pub enum HpFixedConversionError {
Underflow,
DivisionError,
FloatParseError,
ParseError,
}

impl fmt::Display for HpFixedConversionError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
HpFixedConversionError::PrecisionLevelNotSupported => {
write!(f, "Precision level not supported")
},
HpFixedConversionError::Overflow => {
write!(f, "Overflow")
},
HpFixedConversionError::Underflow => {
write!(f, "Underflow")
},
HpFixedConversionError::DivisionError => {
write!(f, "Division error")
},
HpFixedConversionError::FloatParseError => {
write!(f, "Float parse error")
},
HpFixedConversionError::ParseError => {
write!(f, "Parse error")
},
}
}
}

fn format_hp_fixed<T, const P: usize>(value: &T, f: &mut fmt::Formatter<'_>) -> fmt::Result
Expand All @@ -37,7 +63,7 @@ where
}
}
formatted = formatted.chars().rev().collect();
write!(f, "HpUfixed<{P}>({formatted})")
write!(f, "{formatted}<{P}>")
}
}

Expand Down
48 changes: 41 additions & 7 deletions lib/hp-fixed/src/signed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ use std::{
convert::TryInto,
fmt,
ops::{Add, AddAssign, Div, Mul, Sub, SubAssign},
str::FromStr,
};

use num_bigint::{
BigInt, BigUint,
Sign::{Minus, Plus},
};
use num_traits::{FromPrimitive, Signed, ToPrimitive, Zero};
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize};

use crate::{format_hp_fixed, get_float_parts, HpFixedConversionError};

#[derive(Clone, Debug, Hash, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, Default)]
#[derive(Clone, Debug, Hash, PartialEq, PartialOrd, Ord, Eq, Default)]

/// A high-precision fixed-point number backed by a `BigInt`.
///
Expand Down Expand Up @@ -50,8 +51,7 @@ pub struct HpFixed<const P: usize>(BigInt);

impl<const P: usize> HpFixed<P> {
pub fn new(value: BigInt) -> Self {
let ten: BigInt = BigUint::from(10u32).into();
HpFixed::<P>(value * ten.pow(P.try_into().unwrap()))
HpFixed::<P>(value)
}

pub fn zero() -> HpFixed<P> {
Expand Down Expand Up @@ -92,6 +92,40 @@ impl<const P: usize> fmt::Display for HpFixed<P> {
}
}

impl<const P: usize> FromStr for HpFixed<P> {
type Err = HpFixedConversionError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let value = BigInt::from_str(s).map_err(|_| HpFixedConversionError::ParseError)?;

Ok(HpFixed::new(value))
}
}

impl<const P: usize> Serialize for HpFixed<P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
let s = &self.to_string();
let cleaned_s = s.replace('_', "");
let parts: Vec<&str> = cleaned_s.split('<').collect();
let final_string = parts[0].to_string();

serializer.serialize_str(&final_string)
}
}

impl<'de, const P: usize> Deserialize<'de> for HpFixed<P> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
s.parse::<HpFixed<P>>()
.map_err(|_| serde::de::Error::custom("Failed to deserialize HpFixed"))
}
}

impl<const P: usize> Add<HpFixed<P>> for HpFixed<P> {
type Output = HpFixed<P>;

Expand Down Expand Up @@ -438,9 +472,9 @@ mod tests {

#[test]
fn test_try_into() {
let large = HpFixed::<20>::new(BigInt::from(std::i64::MIN as i128 - 1));
let medium = HpFixed::<19>::new(BigInt::from(std::i32::MAX as i64 + 1));
let small = HpFixed::<18>::new(BigInt::from(std::i16::MAX as i32 + 1));
let large = HpFixed::<20>::from(BigInt::from(std::i64::MIN as i128 - 1));
let medium = HpFixed::<19>::from(BigInt::from(std::i32::MAX as i64 + 1));
let small = HpFixed::<18>::from(BigInt::from(std::i16::MAX as i32 + 1));

assert_eq!(std::i64::MIN as i128 - 1, large.clone().try_into().unwrap());
assert!(matches!(
Expand Down
67 changes: 59 additions & 8 deletions lib/hp-fixed/src/unsigned.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::{
fmt,
ops::{Add, AddAssign, Div, Mul, Sub, SubAssign},
str::FromStr,
};

use num_bigint::BigUint;
use num_traits::{zero, CheckedDiv, FromPrimitive, ToPrimitive};
use serde::{Deserialize, Serialize};
use num_traits::{CheckedDiv, FromPrimitive, ToPrimitive, Zero};
use serde::{Deserialize, Deserializer, Serialize};

use crate::{format_hp_fixed, get_float_parts, HpFixedConversionError};

Expand Down Expand Up @@ -42,16 +43,16 @@ use crate::{format_hp_fixed, get_float_parts, HpFixedConversionError};
///
/// * `BigUint`: The underlying large unsigned integer value that the `HpUfixed` wraps around.

#[derive(Clone, Debug, Hash, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, Default)]
#[derive(Clone, Debug, Hash, PartialEq, PartialOrd, Ord, Eq, Default)]
pub struct HpUfixed<const P: usize>(BigUint);

impl<const P: usize> HpUfixed<P> {
pub fn new(value: BigUint) -> Self {
HpUfixed::<P>(value * BigUint::from(10u32).pow(P.try_into().unwrap()))
HpUfixed::<P>(value)
}

pub fn zero() -> HpUfixed<P> {
HpUfixed::new(zero())
HpUfixed::new(BigUint::zero())
}
pub fn convert_precision<const Q: usize>(&self) -> HpUfixed<Q> {
let current_value: &BigUint = &self.0;
Expand Down Expand Up @@ -86,6 +87,39 @@ impl<const P: usize> fmt::Display for HpUfixed<P> {
}
}

impl<const P: usize> FromStr for HpUfixed<P> {
type Err = HpFixedConversionError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let value = BigUint::from_str(s).map_err(|_| HpFixedConversionError::ParseError)?;

Ok(HpUfixed::new(value))
}
}

impl<const P: usize> Serialize for HpUfixed<P> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
let s = &self.to_string();
let cleaned_s = s.replace('_', "");
let parts: Vec<&str> = cleaned_s.split('<').collect();
let final_string = parts[0].to_string();
serializer.serialize_str(&final_string)
}
}

impl<'de, const P: usize> Deserialize<'de> for HpUfixed<P> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
s.parse::<HpUfixed<P>>()
.map_err(|_| serde::de::Error::custom("Failed to deserialize HpUfixed"))
}
}

impl<const P: usize> Add<HpUfixed<P>> for HpUfixed<P> {
type Output = HpUfixed<P>;

Expand Down Expand Up @@ -379,9 +413,9 @@ mod tests {

#[test]
fn test_try_into() {
let large = HpUfixed::<20>::new(BigUint::from(std::u64::MAX as u128 + 1_u128));
let medium = HpUfixed::<19>::new(BigUint::from(std::u32::MAX as u64 + 1_u64));
let small = HpUfixed::<18>::new(BigUint::from(std::u16::MAX as u32 + 1_u32));
let large = HpUfixed::<20>::from(BigUint::from(std::u64::MAX as u128 + 1_u128));
let medium = HpUfixed::<19>::from(BigUint::from(std::u32::MAX as u64 + 1_u64));
let small = HpUfixed::<18>::from(BigUint::from(std::u16::MAX as u32 + 1_u32));

assert_eq!(
std::u64::MAX as u128 + 1_u128,
Expand Down Expand Up @@ -534,4 +568,21 @@ mod tests {
let result = decimal1.convert_precision::<2>();
assert_eq!(result.0, BigUint::from(123_412_u128));
}

#[test]
fn test_serde() {
let decimal: HpUfixed<18> = HpUfixed::from(10_f64);
let ser = serde_json::to_string(&decimal).unwrap();
let decimal2: HpUfixed<18> = serde_json::from_str(&ser).unwrap();
assert_eq!(decimal, decimal2);
}

#[test]
fn bincode_serde_test() {
let decimal: HpUfixed<18> = HpUfixed::from(10_f64);
let serialized = bincode::serialize(&decimal).expect("Failed to serialize using bincode");
let deserialized: HpUfixed<18> =
bincode::deserialize(&serialized).expect("Failed to deserialize using bincode");
assert_eq!(decimal, deserialized);
}
}

0 comments on commit 35a055f

Please sign in to comment.