leodos_protocols/transport/cfdp/pdu/file_data/
without_meta.rs1use crate::transport::cfdp::pdu::CfdpError;
2use crate::transport::cfdp::pdu::EntityId;
3use crate::transport::cfdp::pdu::Pdu;
4use crate::transport::cfdp::pdu::PduHeaderFixedPart;
5use crate::transport::cfdp::pdu::TransactionSeqNum;
6use crate::transport::cfdp::pdu::header::Direction;
7use crate::transport::cfdp::pdu::header::PduType;
8use crate::transport::cfdp::pdu::header::TransmissionMode;
9
10use bon::bon;
11use zerocopy::FromBytes;
12use zerocopy::Immutable;
13use zerocopy::IntoBytes;
14use zerocopy::KnownLayout;
15use zerocopy::Unaligned;
16use zerocopy::network_endian::U32;
17use zerocopy::network_endian::U64;
18
19#[repr(C)]
35#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
36pub struct FileDataPduWithoutMeta {
37 rest: [u8],
39}
40
41impl FileDataPduWithoutMeta {
42 pub fn offset(&self, large_file_flag: bool) -> Result<u64, CfdpError> {
44 if large_file_flag {
45 U64::ref_from_prefix(&self.rest)
46 .map(|(r, _)| r.get())
47 .map_err(|_| CfdpError::Custom("Invalid FSS Offset"))
48 } else {
49 U32::ref_from_prefix(&self.rest)
50 .map(|(r, _)| r.get() as u64)
51 .map_err(|_| CfdpError::Custom("Invalid FSS Offset"))
52 }
53 }
54 pub fn set_offset(&mut self, offset: u64, large_file_flag: bool) -> Result<(), CfdpError> {
56 if large_file_flag {
57 U64::mut_from_prefix(&mut self.rest)
58 .map(|(r, _)| r.set(offset))
59 .map_err(|_| CfdpError::Custom("Invalid FSS Offset"))
60 } else {
61 if offset > u32::MAX as u64 {
62 return Err(CfdpError::DataTooLarge {
63 field: "offset",
64 max: u32::MAX as usize,
65 });
66 }
67 U32::mut_from_prefix(&mut self.rest)
68 .map(|(r, _)| r.set(offset as u32))
69 .map_err(|_| CfdpError::Custom("Invalid FSS Offset"))
70 }
71 }
72
73 pub fn file_data(&self, large_file_flag: bool) -> Result<&[u8], CfdpError> {
75 let offset_len = if large_file_flag { 8 } else { 4 };
76 self.rest
77 .get(offset_len..)
78 .ok_or_else(|| CfdpError::Custom("Invalid file data slice"))
79 }
80 pub fn file_data_mut(&mut self, large_file_flag: bool) -> Result<&mut [u8], CfdpError> {
82 let offset_len = if large_file_flag { 8 } else { 4 };
83 self.rest
84 .get_mut(offset_len..)
85 .ok_or_else(|| CfdpError::Custom("Invalid file data slice"))
86 }
87
88 pub fn rest(&self) -> &[u8] {
90 &self.rest
91 }
92}
93
94#[bon]
95impl FileDataPduWithoutMeta {
96 #[builder]
99 pub fn new<'a>(
100 buffer: &'a mut [u8],
101 source_entity_id: EntityId,
103 dest_entity_id: EntityId,
104 transaction_seq_num: TransactionSeqNum,
105 transmission_mode: TransmissionMode,
106 large_file_flag: bool,
107 crc_flag: bool,
108 segmentation_control: bool,
110 offset: u64,
111 file_data_len: usize,
112 ) -> Result<&'a mut Pdu, CfdpError> {
113 let offset_len = if large_file_flag { 8 } else { 4 };
114 let data_field_len = (offset_len + file_data_len) as u16;
115
116 let header = PduHeaderFixedPart::builder()
117 .version(1)
118 .pdu_type(PduType::FileData)
119 .direction(Direction::TowardReceiver)
120 .tx_mode(transmission_mode)
121 .crc_flag(crc_flag)
122 .large_file_flag(large_file_flag)
123 .data_field_len(data_field_len)
124 .seg_ctrl(segmentation_control)
125 .seg_meta_flag(false) .build()?;
127
128 let pdu = Pdu::builder()
129 .buffer(buffer)
130 .header_fixed(header)
131 .source_entity_id(source_entity_id)
132 .destination_entity_id(dest_entity_id)
133 .transaction_seq_num(transaction_seq_num)
134 .build()?;
135
136 let data_field = pdu.data_field_mut()?;
138 let actual_data_field_len = data_field.len();
139 let fd_pdu = FileDataPduWithoutMeta::mut_from_bytes(data_field).map_err(|_| {
140 CfdpError::BufferTooSmall {
141 required: data_field_len as usize,
142 provided: actual_data_field_len,
143 }
144 })?;
145 fd_pdu.set_offset(offset, large_file_flag)?;
146
147 Ok(pdu)
150 }
151}