dfx_base/
checksum.rs

1use std::num::Wrapping;
2
3pub trait FixChecksum {
4    fn checksum(self) -> Wrapping<u8>;
5}
6
7pub trait FixLength {
8    fn bytes_len(self) -> u32;
9}
10
11macro_rules! impl_checksum_unsigned {
12    ($type_name:ident) => {
13        impl FixChecksum for $type_name {
14            fn checksum(self) -> Wrapping<u8> {
15                if self == 0 {
16                    Wrapping('0' as u8)
17                } else {
18                    let mut total = Wrapping(0);
19                    let mut tag = self;
20                    while tag > 0 {
21                        total += Wrapping((tag % 10) as u8) + Wrapping('0' as u8);
22                        tag = tag / 10;
23                    }
24                    total
25                }
26            }
27        }
28    };}
29
30macro_rules! impl_bytes_len_unsigned {
31    ($type_name:ident) => {
32        impl FixLength for $type_name {
33            fn bytes_len(self) -> u32 {
34                if self == 0 {
35                    1
36                } else {
37                    let mut total = 0;
38                    let mut tag = self;
39                    while tag > 0 {
40                        total += 1;
41                        tag = tag / 10;
42                    }
43                    total
44                }
45            }
46        }
47    };}
48
49impl_checksum_unsigned!(u8);
50impl_checksum_unsigned!(u16);
51impl_checksum_unsigned!(u32);
52impl_checksum_unsigned!(u64);
53impl_checksum_unsigned!(u128);
54impl_bytes_len_unsigned!(u8);
55impl_bytes_len_unsigned!(u16);
56impl_bytes_len_unsigned!(u32);
57impl_bytes_len_unsigned!(u64);
58impl_bytes_len_unsigned!(u128);
59
60macro_rules! impl_checksum_signed {
61    ($type_name:ident) => {
62        impl FixChecksum for $type_name {
63            fn checksum(self) -> Wrapping<u8> {
64                if self == 0 {
65                    Wrapping('0' as u8)
66                } else {
67                    let checksum_neg = if self < 0 {
68                        Wrapping('-' as u8)
69                    } else {
70                        Wrapping(0)
71                    };
72                    let mut total = Wrapping(0);
73                    let mut tag = self.abs();
74                    while tag > 0 {
75                        total += Wrapping((tag % 10) as u8) + Wrapping('0' as u8);
76                        tag = tag / 10;
77                    }
78                    total + checksum_neg
79                }
80            }
81        }
82    };}
83
84macro_rules! impl_bytes_len_signed {
85    ($type_name:ident) => {
86        impl FixLength for $type_name {
87            fn bytes_len(self) -> u32 {
88                if self == 0 {
89                    1
90                } else {
91                    let checksum_neg = if self < 0 {
92                        1
93                    } else {
94                        0
95                    };
96                    let mut total = 0;
97                    let mut tag = self.abs();
98                    while tag > 0 {
99                        total += 1;
100                        tag = tag / 10;
101                    }
102                    total + checksum_neg
103                }
104            }
105        }
106    };}
107
108impl_checksum_signed!(i8);
109impl_checksum_signed!(i16);
110impl_checksum_signed!(i32);
111impl_checksum_signed!(i64);
112impl_checksum_signed!(i128);
113impl_bytes_len_signed!(i8);
114impl_bytes_len_signed!(i16);
115impl_bytes_len_signed!(i32);
116impl_bytes_len_signed!(i64);
117impl_bytes_len_signed!(i128);
118
119impl FixChecksum for &[u8] {
120    fn checksum(self) -> Wrapping<u8> {
121        self.iter().map(|b| Wrapping(*b)).sum()
122    }
123}
124
125impl FixLength for &[u8] {
126    fn bytes_len(self) -> u32 {
127        self.len() as u32
128    }
129}