ps_ecc/long/header/methods/
new.rs1use crate::{
2 long::{
3 header::{
4 magic::LONG_ECC_HEADER_VERSION, utils::calculate_header_checksum, LONG_ECC_HEADER_MAGIC,
5 },
6 LongEccHeader, OverlapFactor, HEADER_SIZE,
7 },
8 LongEccHeaderConstructorError, MAX_PARITY,
9};
10
11use super::super::RS;
12
13impl LongEccHeader {
14 pub fn new(
25 parity: u8,
26 overlap_factor: OverlapFactor,
27 full_length: u32,
28 message_length: u32,
29 checksum: u64,
30 ) -> Result<Self, LongEccHeaderConstructorError> {
31 let magic = LONG_ECC_HEADER_MAGIC;
32 let version = LONG_ECC_HEADER_VERSION;
33
34 if parity > MAX_PARITY {
35 return Err(LongEccHeaderConstructorError::InvalidParityCount(parity));
36 }
37
38 if u64::from(full_length) < u64::from(message_length) + HEADER_SIZE as u64 {
43 return Err(LongEccHeaderConstructorError::InvalidMessageLength(
44 message_length,
45 full_length,
46 ));
47 }
48
49 let parity = parity | overlap_factor.to_u8();
51
52 let mut header = Self {
53 magic,
54 version,
55 parity,
56 full_length,
57 message_length,
58 header_checksum: calculate_header_checksum(
59 version,
60 parity,
61 full_length,
62 message_length,
63 ),
64 checksum,
65 header_parity: [0; 8],
66 };
67
68 if header.parity_bytes() >= header.segment_distance() {
71 return Err(LongEccHeaderConstructorError::InvalidSegmentParityRatio(
72 header.segment_distance(),
73 header.parity(),
74 ));
75 }
76
77 let expected_length = HEADER_SIZE as u64
80 + u64::from(message_length)
81 + u64::from(header.parity_bytes()) * u64::from(header.segment_count());
82
83 if u64::from(full_length) != expected_length {
84 return Err(LongEccHeaderConstructorError::InvalidFullLength(
85 full_length,
86 expected_length,
87 ));
88 }
89
90 let parity = RS.generate_parity(&header.to_bytes()[..24])?;
91
92 header.header_parity.copy_from_slice(&parity);
93
94 Ok(header)
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use crate::{
101 long::{LongEccHeader, OverlapFactor},
102 MAX_PARITY,
103 };
104
105 use super::LongEccHeaderConstructorError;
106
107 #[test]
108 fn test_new_rejects_invalid_segment_parity_ratio() {
109 let result = LongEccHeader::new(63, OverlapFactor::Quadruple, 100, 50, 0);
112
113 assert_eq!(
114 result,
115 Err(LongEccHeaderConstructorError::InvalidSegmentParityRatio(
116 32, 63
117 ))
118 );
119 }
120
121 #[test]
122 fn test_new_quadruple_overlap_boundary() {
123 assert!(LongEccHeader::new(25, OverlapFactor::Quadruple, 132, 50, 0).is_ok());
127 assert_eq!(
128 LongEccHeader::new(26, OverlapFactor::Quadruple, 132, 50, 0),
129 Err(LongEccHeaderConstructorError::InvalidSegmentParityRatio(
130 50, 26
131 ))
132 );
133 }
134
135 #[test]
136 fn test_new_double_overlap_boundary() {
137 assert!(LongEccHeader::new(42, OverlapFactor::Double, 166, 50, 0).is_ok());
141 assert_eq!(
142 LongEccHeader::new(43, OverlapFactor::Double, 166, 50, 0),
143 Err(LongEccHeaderConstructorError::InvalidSegmentParityRatio(
144 84, 43
145 ))
146 );
147 }
148
149 #[test]
150 fn test_new_triple_overlap_boundary() {
151 assert!(LongEccHeader::new(31, OverlapFactor::Triple, 144, 50, 0).is_ok());
155 assert_eq!(
156 LongEccHeader::new(32, OverlapFactor::Triple, 144, 50, 0),
157 Err(LongEccHeaderConstructorError::InvalidSegmentParityRatio(
158 63, 32
159 ))
160 );
161 }
162
163 #[test]
164 fn test_new_rejects_message_length_exceeding_full_length() {
165 let result = LongEccHeader::new(1, OverlapFactor::Simple, 41, 10, 0);
167
168 assert_eq!(
169 result,
170 Err(LongEccHeaderConstructorError::InvalidMessageLength(10, 41))
171 );
172 }
173
174 #[test]
175 fn test_new_rejects_incorrect_full_length() {
176 assert!(LongEccHeader::new(1, OverlapFactor::Simple, 44, 10, 0).is_ok());
179 assert_eq!(
180 LongEccHeader::new(1, OverlapFactor::Simple, 45, 10, 0),
181 Err(LongEccHeaderConstructorError::InvalidFullLength(45, 44))
182 );
183 }
184
185 #[test]
186 fn test_new_accepts_max_parity_without_overlap() {
187 assert!(LongEccHeader::new(MAX_PARITY, OverlapFactor::Simple, 208, 50, 0).is_ok());
190 }
191}