levana_perpswap_cosmos/number/
ratio.rs1use crate::prelude::cw_serde;
6use anyhow::{ensure, Result};
7use cosmwasm_std::Decimal256;
8use std::ops::Bound;
9
10fn validate_ratio(
11 value: &Decimal256,
12 lower: Bound<Decimal256>,
13 upper: Bound<Decimal256>,
14) -> Result<()> {
15 let is_valid = (match lower {
16 Bound::Included(lower) => lower <= *value,
17 Bound::Excluded(lower) => lower < *value,
18 Bound::Unbounded => true,
19 }) && (match upper {
20 Bound::Included(upper) => *value <= upper,
21 Bound::Excluded(upper) => *value < upper,
22 Bound::Unbounded => true,
23 });
24
25 ensure!(
26 is_valid,
27 "Invalid ratio, {} is out of range ({:?}, {:?})",
28 value,
29 lower,
30 upper
31 );
32
33 Ok(())
34}
35
36#[cw_serde]
37pub struct InclusiveRatio(Decimal256);
39
40impl InclusiveRatio {
41 pub fn new(value: Decimal256) -> Result<Self> {
43 validate_ratio(
44 &value,
45 Bound::Included(Decimal256::zero()),
46 Bound::Included(Decimal256::one()),
47 )?;
48
49 Ok(InclusiveRatio(value))
50 }
51
52 pub fn raw(&self) -> Decimal256 {
54 self.0
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn test_bounded_ratio() {
64 let raw_ratio = Decimal256::zero();
67 InclusiveRatio::new(raw_ratio).unwrap();
68
69 let raw_ratio = Decimal256::one();
70 InclusiveRatio::new(raw_ratio).unwrap();
71
72 let raw_ratio = Decimal256::from_ratio(1u64, 2u64);
73 InclusiveRatio::new(raw_ratio).unwrap();
74
75 let raw_ratio = Decimal256::from_ratio(2u64, 1u64);
76 InclusiveRatio::new(raw_ratio).unwrap_err();
77 }
78}