jam_std_common/util/
injective_decode.rs1use crate::{CountedOutput, RecordedInput};
2use arrayvec::ArrayVec;
3use codec::{ConstEncodedLen, Decode, Encode, Error, Input, MaxEncodedLen, Output};
4
5#[derive(Copy, Clone, Debug, Eq, PartialEq)]
10pub enum InjectiveDecode<T, const N: usize> {
11 Valid(T),
12 Invalid([u8; N]),
13}
14
15impl<T, const N: usize> InjectiveDecode<T, N> {
16 pub fn valid(&self) -> Option<&T> {
17 match self {
18 Self::Valid(value) => Some(value),
19 Self::Invalid(_) => None,
20 }
21 }
22}
23
24impl<T: MaxEncodedLen, const N: usize> Encode for InjectiveDecode<T, N> {
25 fn size_hint(&self) -> usize {
26 N
27 }
28
29 fn encode_to<O: Output + ?Sized>(&self, output: &mut O) {
30 match self {
31 Self::Valid(value) => {
32 let mut counted_output = CountedOutput::new(output);
33 debug_assert!(T::max_encoded_len() <= N);
34 value.encode_to(&mut counted_output);
35 while counted_output.num_bytes_written() < N {
37 counted_output.push_byte(0);
38 }
39 debug_assert_eq!(counted_output.num_bytes_written(), N);
40 },
41 Self::Invalid(encoded) => output.write(encoded),
42 }
43 }
44
45 fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
46 match self {
47 Self::Valid(_) => f(&self.encode()),
48 Self::Invalid(encoded) => f(encoded),
49 }
50 }
51
52 fn encoded_size(&self) -> usize {
53 N
54 }
55}
56
57impl<T: MaxEncodedLen, const N: usize> MaxEncodedLen for InjectiveDecode<T, N> {
58 fn max_encoded_len() -> usize {
59 N
60 }
61}
62
63impl<T: MaxEncodedLen, const N: usize> ConstEncodedLen for InjectiveDecode<T, N> {}
64
65impl<T: MaxEncodedLen + Decode, const N: usize> Decode for InjectiveDecode<T, N> {
66 fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
67 let mut recorded_input = RecordedInput::with_record(input, ArrayVec::<u8, N>::new());
68
69 debug_assert!(T::max_encoded_len() <= N);
70 let mut value = T::decode(&mut recorded_input);
71 if recorded_input.failed() {
72 value?;
73 debug_assert!(false);
75 return Err("Unforwarded input failure".into())
76 }
77
78 while !recorded_input.record().is_full() {
80 if (recorded_input.read_byte()? != 0) && value.is_ok() {
81 value = Err("Non-zero padding".into());
82 }
83 }
84
85 match value {
86 Ok(value) => Ok(Self::Valid(value)),
87 Err(_) =>
88 Ok(Self::Invalid(recorded_input.into_record().into_inner().expect("Filled above"))),
89 }
90 }
91
92 fn skip<I: Input>(input: &mut I) -> Result<(), Error> {
93 for _ in 0..N {
94 input.read_byte()?;
95 }
96 Ok(())
97 }
98
99 fn encoded_fixed_size() -> Option<usize> {
100 Some(N)
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn encode_valid_pads_with_zeroes() {
110 let x = InjectiveDecode::<u16, 4>::Valid(0x0201);
111 assert_eq!(&x.encode(), &[0x01, 0x02, 0x00, 0x00]);
112 assert_eq!(x.encoded_size(), 4);
113 assert_eq!(x.size_hint(), 4);
114 }
115
116 #[test]
117 fn encode_invalid_writes_raw_bytes() {
118 let x = InjectiveDecode::<u16, 4>::Invalid([1, 2, 3, 4]);
119 assert_eq!(&x.encode(), &[1, 2, 3, 4]);
120 }
121
122 #[test]
123 fn decode_valid_with_zero_padding() {
124 let encoded = [0x01, 0x02, 0x00, 0x00];
125 let decoded = InjectiveDecode::<u16, 4>::decode(&mut &encoded[..]).unwrap();
126 assert_eq!(decoded, InjectiveDecode::Valid(0x0201));
127 }
128
129 #[test]
130 fn decode_nonzero_padding_is_invalid() {
131 let encoded = [0x01, 0x02, 0x00, 0x05];
134 let decoded = InjectiveDecode::<u16, 4>::decode(&mut &encoded[..]).unwrap();
135 assert_eq!(decoded, InjectiveDecode::Invalid(encoded));
136 }
137
138 #[test]
139 fn decode_invalid_value_is_captured() {
140 let encoded = [0x02, 0x00];
143 let decoded = InjectiveDecode::<bool, 2>::decode(&mut &encoded[..]).unwrap();
144 assert_eq!(decoded, InjectiveDecode::Invalid(encoded));
145 }
146
147 #[test]
148 fn decode_is_injective() {
149 for a in 0..=4u8 {
151 for b in 0..=4u8 {
152 for c in 0..=1u8 {
153 for d in 0..=1u8 {
154 let encoded = [a, b, c, d];
155 let decoded = InjectiveDecode::<u16, 4>::decode(&mut &encoded[..]).unwrap();
156 assert_eq!(&decoded.encode(), &encoded);
157 }
158 }
159 }
160 }
161 }
162
163 #[test]
164 fn decode_fails_on_truncated_input() {
165 let encoded = [0x01];
166 assert!(InjectiveDecode::<u16, 4>::decode(&mut &encoded[..]).is_err());
167 }
168
169 #[test]
170 fn skip() {
171 let mut input = [1, 2, 3, 4, 5, 6].as_slice();
172 InjectiveDecode::<u16, 4>::skip(&mut input).unwrap();
173 assert_eq!(input, &[5, 6]);
174 assert!(InjectiveDecode::<u16, 4>::skip(&mut input).is_err());
175 }
176}