diff --git a/src/cfdp/pdu/eof.rs b/src/cfdp/pdu/eof.rs index bfe31d4..84484a4 100644 --- a/src/cfdp/pdu/eof.rs +++ b/src/cfdp/pdu/eof.rs @@ -8,6 +8,8 @@ use crate::ByteConversionError; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use super::WritablePduPacket; + /// Finished PDU abstraction. /// /// For more information, refer to CFDP chapter 5.2.2. @@ -68,36 +70,6 @@ impl EofPdu { len } - pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { - let expected_len = self.written_len(); - if buf.len() < expected_len { - return Err(ByteConversionError::ToSliceTooSmall { - found: buf.len(), - expected: expected_len, - } - .into()); - } - let mut current_idx = self.pdu_header.write_to_bytes(buf)?; - buf[current_idx] = FileDirectiveType::EofPdu as u8; - current_idx += 1; - buf[current_idx] = (self.condition_code as u8) << 4; - current_idx += 1; - buf[current_idx..current_idx + 4].copy_from_slice(&self.file_checksum.to_be_bytes()); - current_idx += 4; - current_idx += write_fss_field( - self.pdu_header.pdu_conf.file_flag, - self.file_size, - &mut buf[current_idx..], - )?; - if let Some(fault_location) = self.fault_location { - current_idx += fault_location.write_to_be_bytes(buf)?; - } - if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc { - current_idx = add_pdu_crc(buf, current_idx); - } - Ok(current_idx) - } - pub fn from_bytes(buf: &[u8]) -> Result { let (pdu_header, mut current_idx) = PduHeader::from_bytes(buf)?; let full_len_without_crc = pdu_header.verify_length_and_checksum(buf)?; @@ -143,9 +115,41 @@ impl EofPdu { } } +impl WritablePduPacket for EofPdu { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + let expected_len = self.written_len(); + if buf.len() < expected_len { + return Err(ByteConversionError::ToSliceTooSmall { + found: buf.len(), + expected: expected_len, + } + .into()); + } + let mut current_idx = self.pdu_header.write_to_bytes(buf)?; + buf[current_idx] = FileDirectiveType::EofPdu as u8; + current_idx += 1; + buf[current_idx] = (self.condition_code as u8) << 4; + current_idx += 1; + buf[current_idx..current_idx + 4].copy_from_slice(&self.file_checksum.to_be_bytes()); + current_idx += 4; + current_idx += write_fss_field( + self.pdu_header.pdu_conf.file_flag, + self.file_size, + &mut buf[current_idx..], + )?; + if let Some(fault_location) = self.fault_location { + current_idx += fault_location.write_to_be_bytes(buf)?; + } + if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc { + current_idx = add_pdu_crc(buf, current_idx); + } + Ok(current_idx) + } +} + #[cfg(test)] mod tests { - use crate::cfdp::pdu::eof::EofPdu; + use super::*; use crate::cfdp::pdu::tests::{common_pdu_conf, verify_raw_header}; use crate::cfdp::pdu::{FileDirectiveType, PduHeader}; use crate::cfdp::{ConditionCode, CrcFlag, LargeFileFlag}; diff --git a/src/cfdp/pdu/file_data.rs b/src/cfdp/pdu/file_data.rs index 5f3d232..dd8476e 100644 --- a/src/cfdp/pdu/file_data.rs +++ b/src/cfdp/pdu/file_data.rs @@ -8,6 +8,8 @@ use num_enum::{IntoPrimitive, TryFromPrimitive}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use super::WritablePduPacket; + #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(u8)] @@ -163,35 +165,6 @@ impl<'seg_meta, 'file_data> FileDataPdu<'seg_meta, 'file_data> { self.segment_metadata.as_ref() } - pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { - if buf.len() < self.written_len() { - return Err(ByteConversionError::ToSliceTooSmall { - found: buf.len(), - expected: self.written_len(), - } - .into()); - } - let mut current_idx = self.pdu_header.write_to_bytes(buf)?; - if self.segment_metadata.is_some() { - current_idx += self - .segment_metadata - .as_ref() - .unwrap() - .write_to_bytes(&mut buf[current_idx..])?; - } - current_idx += write_fss_field( - self.pdu_header.common_pdu_conf().file_flag, - self.offset, - &mut buf[current_idx..], - )?; - buf[current_idx..current_idx + self.file_data.len()].copy_from_slice(self.file_data); - current_idx += self.file_data.len(); - if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc { - current_idx = add_pdu_crc(buf, current_idx); - } - Ok(current_idx) - } - pub fn from_bytes<'longest: 'seg_meta + 'file_data>( buf: &'longest [u8], ) -> Result { @@ -222,9 +195,40 @@ impl<'seg_meta, 'file_data> FileDataPdu<'seg_meta, 'file_data> { } } +impl WritablePduPacket for FileDataPdu<'_, '_> { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + if buf.len() < self.written_len() { + return Err(ByteConversionError::ToSliceTooSmall { + found: buf.len(), + expected: self.written_len(), + } + .into()); + } + let mut current_idx = self.pdu_header.write_to_bytes(buf)?; + if self.segment_metadata.is_some() { + current_idx += self + .segment_metadata + .as_ref() + .unwrap() + .write_to_bytes(&mut buf[current_idx..])?; + } + current_idx += write_fss_field( + self.pdu_header.common_pdu_conf().file_flag, + self.offset, + &mut buf[current_idx..], + )?; + buf[current_idx..current_idx + self.file_data.len()].copy_from_slice(self.file_data); + current_idx += self.file_data.len(); + if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc { + current_idx = add_pdu_crc(buf, current_idx); + } + Ok(current_idx) + } +} + #[cfg(test)] mod tests { - use crate::cfdp::pdu::file_data::{FileDataPdu, RecordContinuationState, SegmentMetadata}; + use super::*; use crate::cfdp::pdu::{CommonPduConfig, PduHeader}; use crate::cfdp::{SegmentMetadataFlag, SegmentationControl}; use crate::util::UbfU8; diff --git a/src/cfdp/pdu/finished.rs b/src/cfdp/pdu/finished.rs index 9732863..cb25a98 100644 --- a/src/cfdp/pdu/finished.rs +++ b/src/cfdp/pdu/finished.rs @@ -8,6 +8,8 @@ use num_enum::{IntoPrimitive, TryFromPrimitive}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use super::WritablePduPacket; + #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(u8)] @@ -135,36 +137,6 @@ impl<'fs_responses> FinishedPdu<'fs_responses> { base_len } - pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { - let expected_len = self.written_len(); - if buf.len() < expected_len { - return Err(ByteConversionError::ToSliceTooSmall { - found: buf.len(), - expected: expected_len, - } - .into()); - } - - let mut current_idx = self.pdu_header.write_to_bytes(buf)?; - buf[current_idx] = FileDirectiveType::FinishedPdu as u8; - current_idx += 1; - buf[current_idx] = ((self.condition_code as u8) << 4) - | ((self.delivery_code as u8) << 2) - | self.file_status as u8; - current_idx += 1; - if let Some(fs_responses) = self.fs_responses { - buf[current_idx..current_idx + fs_responses.len()].copy_from_slice(fs_responses); - current_idx += fs_responses.len(); - } - if let Some(fault_location) = self.fault_location { - current_idx += fault_location.write_to_be_bytes(&mut buf[current_idx..])?; - } - if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc { - current_idx = add_pdu_crc(buf, current_idx); - } - Ok(current_idx) - } - /// Generates [Self] from a raw bytestream. pub fn from_bytes(buf: &'fs_responses [u8]) -> Result { let (pdu_header, mut current_idx) = PduHeader::from_bytes(buf)?; @@ -246,9 +218,41 @@ impl<'fs_responses> FinishedPdu<'fs_responses> { } } +impl WritablePduPacket for FinishedPdu<'_> { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + let expected_len = self.written_len(); + if buf.len() < expected_len { + return Err(ByteConversionError::ToSliceTooSmall { + found: buf.len(), + expected: expected_len, + } + .into()); + } + + let mut current_idx = self.pdu_header.write_to_bytes(buf)?; + buf[current_idx] = FileDirectiveType::FinishedPdu as u8; + current_idx += 1; + buf[current_idx] = ((self.condition_code as u8) << 4) + | ((self.delivery_code as u8) << 2) + | self.file_status as u8; + current_idx += 1; + if let Some(fs_responses) = self.fs_responses { + buf[current_idx..current_idx + fs_responses.len()].copy_from_slice(fs_responses); + current_idx += fs_responses.len(); + } + if let Some(fault_location) = self.fault_location { + current_idx += fault_location.write_to_be_bytes(&mut buf[current_idx..])?; + } + if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc { + current_idx = add_pdu_crc(buf, current_idx); + } + Ok(current_idx) + } +} + #[cfg(test)] mod tests { - use crate::cfdp::pdu::finished::{DeliveryCode, FileStatus, FinishedPdu}; + use super::*; use crate::cfdp::pdu::tests::{common_pdu_conf, verify_raw_header}; use crate::cfdp::pdu::{FileDirectiveType, PduHeader}; use crate::cfdp::{ConditionCode, CrcFlag, Direction, LargeFileFlag}; diff --git a/src/cfdp/pdu/metadata.rs b/src/cfdp/pdu/metadata.rs index a90bb45..84d1275 100644 --- a/src/cfdp/pdu/metadata.rs +++ b/src/cfdp/pdu/metadata.rs @@ -11,6 +11,8 @@ use alloc::vec::Vec; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use super::WritablePduPacket; + #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct MetadataGenericParams { @@ -199,43 +201,6 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> { &self.pdu_header } - pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { - let expected_len = self.written_len(); - if buf.len() < expected_len { - return Err(ByteConversionError::ToSliceTooSmall { - found: buf.len(), - expected: expected_len, - } - .into()); - } - - let mut current_idx = self.pdu_header.write_to_bytes(buf)?; - buf[current_idx] = FileDirectiveType::MetadataPdu as u8; - current_idx += 1; - buf[current_idx] = ((self.metadata_params.closure_requested as u8) << 7) - | (self.metadata_params.checksum_type as u8); - current_idx += 1; - current_idx += write_fss_field( - self.pdu_header.common_pdu_conf().file_flag, - self.metadata_params.file_size, - &mut buf[current_idx..], - )?; - current_idx += self - .src_file_name - .write_to_be_bytes(&mut buf[current_idx..])?; - current_idx += self - .dest_file_name - .write_to_be_bytes(&mut buf[current_idx..])?; - if let Some(opts) = self.options { - buf[current_idx..current_idx + opts.len()].copy_from_slice(opts); - current_idx += opts.len(); - } - if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc { - current_idx = add_pdu_crc(buf, current_idx); - } - Ok(current_idx) - } - pub fn from_bytes<'longest: 'src_name + 'dest_name + 'opts>( buf: &'longest [u8], ) -> Result { @@ -289,8 +254,48 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> { } } +impl WritablePduPacket for MetadataPdu<'_, '_, '_> { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + let expected_len = self.written_len(); + if buf.len() < expected_len { + return Err(ByteConversionError::ToSliceTooSmall { + found: buf.len(), + expected: expected_len, + } + .into()); + } + + let mut current_idx = self.pdu_header.write_to_bytes(buf)?; + buf[current_idx] = FileDirectiveType::MetadataPdu as u8; + current_idx += 1; + buf[current_idx] = ((self.metadata_params.closure_requested as u8) << 7) + | (self.metadata_params.checksum_type as u8); + current_idx += 1; + current_idx += write_fss_field( + self.pdu_header.common_pdu_conf().file_flag, + self.metadata_params.file_size, + &mut buf[current_idx..], + )?; + current_idx += self + .src_file_name + .write_to_be_bytes(&mut buf[current_idx..])?; + current_idx += self + .dest_file_name + .write_to_be_bytes(&mut buf[current_idx..])?; + if let Some(opts) = self.options { + buf[current_idx..current_idx + opts.len()].copy_from_slice(opts); + current_idx += opts.len(); + } + if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc { + current_idx = add_pdu_crc(buf, current_idx); + } + Ok(current_idx) + } +} + #[cfg(test)] pub mod tests { + use super::*; use crate::cfdp::lv::Lv; use crate::cfdp::pdu::metadata::{ build_metadata_opts_from_slice, build_metadata_opts_from_vec, MetadataGenericParams, @@ -304,18 +309,14 @@ pub mod tests { }; use std::vec; - const SRC_FILENAME: &'static str = "hello-world.txt"; - const DEST_FILENAME: &'static str = "hello-world2.txt"; + const SRC_FILENAME: &str = "hello-world.txt"; + const DEST_FILENAME: &str = "hello-world2.txt"; - fn generic_metadata_pdu<'opts>( + fn generic_metadata_pdu( crc_flag: CrcFlag, fss: LargeFileFlag, - opts: Option<&'opts [u8]>, - ) -> ( - Lv<'static>, - Lv<'static>, - MetadataPdu<'static, 'static, 'opts>, - ) { + opts: Option<&[u8]>, + ) -> (Lv<'static>, Lv<'static>, MetadataPdu<'static, 'static, '_>) { let pdu_header = PduHeader::new_no_file_data(common_pdu_conf(crc_flag, fss), 0); let metadata_params = MetadataGenericParams::new(false, ChecksumType::Crc32, 0x1010); let src_filename = Lv::new_from_str(SRC_FILENAME).expect("Generating string LV failed"); diff --git a/src/cfdp/pdu/mod.rs b/src/cfdp/pdu/mod.rs index 669ff5f..048d515 100644 --- a/src/cfdp/pdu/mod.rs +++ b/src/cfdp/pdu/mod.rs @@ -149,6 +149,10 @@ impl From for PduError { } } +pub trait WritablePduPacket { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result; +} + /// Common configuration fields for a PDU. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]