fix/
fix_value.rs

1use crate::typenum::{Integer, U10};
2use crate::Fix;
3use anchor_lang::prelude::{borsh, AnchorDeserialize, AnchorSerialize, InitSpace};
4use paste::paste;
5
6macro_rules! impl_fix_value {
7    ($sign:ident, $bits:expr) => {
8        paste! {
9           /// A value-space `Fix` where base is always 10 and bits are a concrete type.
10           /// Intended for serialized storage in Solana accounts where generics won't work.
11            #[derive(PartialEq, Eq, Copy, Clone, Debug, AnchorSerialize, AnchorDeserialize, InitSpace)]
12            pub struct [<$sign FixValue $bits>] {
13                pub bits: [<$sign:lower $bits>],
14                pub exp: i8,
15            }
16
17            impl [<$sign FixValue $bits>] {
18                pub fn new(bits: [<$sign:lower $bits>], exp: i8) -> Self {
19                    Self { bits, exp }
20                }
21            }
22
23            impl<Bits, Exp> From<Fix<Bits, U10, Exp>> for [<$sign FixValue $bits>]
24            where
25                Bits: Into<[<$sign:lower $bits>]>,
26                Exp: Integer,
27            {
28                fn from(fix: Fix<Bits, U10, Exp>) -> Self {
29                    Self {
30                        bits: fix.bits.into(),
31                        exp: Exp::to_i8(),
32                    }
33                }
34            }
35
36            impl<Bits, Exp> From<[<$sign FixValue $bits>]> for Fix<Bits, U10, Exp>
37            where
38                Bits: From<[<$sign:lower $bits>]>,
39                Exp: Integer,
40            {
41              fn from(value: [<$sign FixValue $bits>]) -> Fix<Bits, U10, Exp> {
42                Fix::new(value.bits.into())
43              }
44            }
45        }
46    };
47}
48
49impl_fix_value!(U, 8);
50impl_fix_value!(U, 16);
51impl_fix_value!(U, 32);
52impl_fix_value!(U, 64);
53impl_fix_value!(U, 128);
54impl_fix_value!(I, 8);
55impl_fix_value!(I, 16);
56impl_fix_value!(I, 32);
57impl_fix_value!(I, 64);
58impl_fix_value!(I, 128);
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63    use crate::aliases::si::Kilo;
64    use anyhow::Result;
65    use borsh::to_vec;
66
67    macro_rules! fix_value_tests {
68        ($sign:ident, $bits:expr) => {
69            paste! {
70                #[test]
71                fn [<roundtrip_into_ $sign:lower $bits>]() -> Result<()> {
72                    let start = Kilo::new([<69 $sign:lower $bits>]);
73                    let there: [<$sign FixValue $bits>] = start.into();
74                    let back: Kilo<[<$sign:lower $bits>]> = there.into();
75                    assert_eq!(there, [<$sign FixValue $bits>]::new(69, 3));
76                    Ok(assert_eq!(start, back))
77                }
78
79                #[test]
80                fn [<roundtrip_serialize_ $sign:lower $bits>]() -> Result<()> {
81                    let start = [<$sign FixValue $bits>]::new(20, -2);
82                    let bytes = to_vec(&start)?;
83                    let back = AnchorDeserialize::deserialize(&mut bytes.as_slice())?;
84                    Ok(assert_eq!(start, back))
85                }
86            }
87        };
88    }
89
90    fix_value_tests!(U, 8);
91    fix_value_tests!(U, 16);
92    fix_value_tests!(U, 32);
93    fix_value_tests!(U, 64);
94    fix_value_tests!(U, 128);
95    fix_value_tests!(I, 8);
96    fix_value_tests!(I, 16);
97    fix_value_tests!(I, 32);
98    fix_value_tests!(I, 64);
99    fix_value_tests!(I, 128);
100}