1use crate::error::{Error, Result};
18use crate::lct::LctHeader;
19
20pub const HET_EXT_FTI: u8 = 64;
23
24pub const PSI_SPI: u8 = 0b10;
27
28#[derive(Debug, Clone, PartialEq, Eq)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize))]
38pub struct AlcPacket<'a> {
39 pub lct: LctHeader<'a>,
41 pub fec_payload_id: &'a [u8],
44 pub payload: &'a [u8],
46}
47
48impl<'a> AlcPacket<'a> {
49 pub fn new(lct: LctHeader<'a>, fec_payload_id: &'a [u8], payload: &'a [u8]) -> Self {
51 AlcPacket {
52 lct,
53 fec_payload_id,
54 payload,
55 }
56 }
57
58 pub fn spi(&self) -> bool {
60 self.lct.psi & PSI_SPI != 0
61 }
62
63 pub fn serialized_len(&self) -> usize {
65 self.lct.serialized_len() + self.fec_payload_id.len() + self.payload.len()
66 }
67
68 pub fn parse(data: &'a [u8], fec_payload_id_len: usize) -> Result<Self> {
72 let (lct, used) = LctHeader::parse(data)?;
73 let rest = &data[used..];
74 if rest.len() < fec_payload_id_len {
75 return Err(Error::BufferTooShort {
76 need: fec_payload_id_len,
77 have: rest.len(),
78 what: "ALC FEC Payload ID",
79 });
80 }
81 let fec_payload_id = &rest[..fec_payload_id_len];
82 let payload = &rest[fec_payload_id_len..];
83 Ok(AlcPacket {
84 lct,
85 fec_payload_id,
86 payload,
87 })
88 }
89
90 pub fn serialize_into(&self, out: &mut [u8]) -> Result<usize> {
92 let total = self.serialized_len();
93 if out.len() < total {
94 return Err(Error::OutputBufferTooSmall {
95 need: total,
96 have: out.len(),
97 });
98 }
99 let mut off = self.lct.serialize_into(out)?;
100 out[off..off + self.fec_payload_id.len()].copy_from_slice(self.fec_payload_id);
101 off += self.fec_payload_id.len();
102 out[off..off + self.payload.len()].copy_from_slice(self.payload);
103 off += self.payload.len();
104 Ok(off)
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
113#[cfg_attr(feature = "serde", derive(serde::Serialize))]
114pub struct FecPayloadId128 {
115 pub source_block_number: u32,
117 pub source_block_length: u16,
119 pub encoding_symbol_id: u16,
121}
122
123pub const FEC_PAYLOAD_ID_128_LEN: usize = 8;
125
126impl FecPayloadId128 {
127 pub fn serialized_len(&self) -> usize {
129 FEC_PAYLOAD_ID_128_LEN
130 }
131
132 pub fn parse(data: &[u8]) -> Result<Self> {
134 if data.len() < FEC_PAYLOAD_ID_128_LEN {
135 return Err(Error::BufferTooShort {
136 need: FEC_PAYLOAD_ID_128_LEN,
137 have: data.len(),
138 what: "FEC Payload ID (fec_id 128/129)",
139 });
140 }
141 Ok(FecPayloadId128 {
142 source_block_number: u32::from_be_bytes([data[0], data[1], data[2], data[3]]),
143 source_block_length: u16::from_be_bytes([data[4], data[5]]),
144 encoding_symbol_id: u16::from_be_bytes([data[6], data[7]]),
145 })
146 }
147
148 pub fn serialize_into(&self, out: &mut [u8]) -> Result<usize> {
150 if out.len() < FEC_PAYLOAD_ID_128_LEN {
151 return Err(Error::OutputBufferTooSmall {
152 need: FEC_PAYLOAD_ID_128_LEN,
153 have: out.len(),
154 });
155 }
156 out[0..4].copy_from_slice(&self.source_block_number.to_be_bytes());
157 out[4..6].copy_from_slice(&self.source_block_length.to_be_bytes());
158 out[6..8].copy_from_slice(&self.encoding_symbol_id.to_be_bytes());
159 Ok(FEC_PAYLOAD_ID_128_LEN)
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166 use crate::lct::{LCT_VERSION, LctHeader};
167 use alloc::vec;
168
169 fn lct_with_tsi() -> ([u8; 4], [u8; 4]) {
170 ([0u8; 4], [0x00, 0x00, 0x00, 0x07])
172 }
173
174 #[test]
175 fn alc_packet_round_trip() {
176 let (cci, tsi) = lct_with_tsi();
177 let lct = LctHeader {
178 version: LCT_VERSION,
179 psi: PSI_SPI,
180 close_session: false,
181 close_object: false,
182 codepoint: 0x80,
183 cci: &cci,
184 tsi: &tsi,
185 toi: &[],
186 extensions: vec![],
187 };
188 let fpid = [0x00u8, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02];
189 let payload = [0xDEu8, 0xAD, 0xBE, 0xEF];
190 let pkt = AlcPacket::new(lct, &fpid, &payload);
191 assert!(pkt.spi());
192
193 let mut out = vec![0u8; pkt.serialized_len()];
194 let n = pkt.serialize_into(&mut out).unwrap();
195 assert_eq!(n, pkt.serialized_len());
196
197 let re = AlcPacket::parse(&out, FEC_PAYLOAD_ID_128_LEN).unwrap();
198 assert_eq!(re, pkt);
199 assert_eq!(re.fec_payload_id, &fpid);
200 assert_eq!(re.payload, &payload);
201 }
202
203 #[test]
204 fn data_less_packet_has_no_fpid_or_payload() {
205 let (cci, tsi) = lct_with_tsi();
206 let lct = LctHeader {
207 version: LCT_VERSION,
208 psi: 0,
209 close_session: true,
210 close_object: false,
211 codepoint: 0,
212 cci: &cci,
213 tsi: &tsi,
214 toi: &[],
215 extensions: vec![],
216 };
217 let pkt = AlcPacket::new(lct, &[], &[]);
218 let mut out = vec![0u8; pkt.serialized_len()];
219 pkt.serialize_into(&mut out).unwrap();
220 let re = AlcPacket::parse(&out, 0).unwrap();
221 assert_eq!(re, pkt);
222 assert!(re.fec_payload_id.is_empty());
223 assert!(re.payload.is_empty());
224 }
225
226 #[test]
227 fn fec_payload_id_128_exact_bytes() {
228 let f = FecPayloadId128 {
229 source_block_number: 0x0102_0304,
230 source_block_length: 0x0506,
231 encoding_symbol_id: 0x0708,
232 };
233 let mut out = [0u8; FEC_PAYLOAD_ID_128_LEN];
234 f.serialize_into(&mut out).unwrap();
235 assert_eq!(out, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
236 assert_eq!(FecPayloadId128::parse(&out).unwrap(), f);
237 }
238
239 #[test]
240 fn mutating_payload_changes_wire() {
241 let (cci, tsi) = lct_with_tsi();
242 let mk = |p: &[u8]| {
243 let lct = LctHeader {
244 version: LCT_VERSION,
245 psi: 0,
246 close_session: false,
247 close_object: false,
248 codepoint: 0,
249 cci: &cci,
250 tsi: &tsi,
251 toi: &[],
252 extensions: vec![],
253 };
254 let pkt = AlcPacket::new(lct, &[], p);
255 let mut out = vec![0u8; pkt.serialized_len()];
256 pkt.serialize_into(&mut out).unwrap();
257 out
258 };
259 assert_ne!(mk(&[1, 2, 3, 4]), mk(&[1, 2, 3, 5]));
260 }
261}