leodos_protocols/transport/cfdp/pdu/tlv/
filestore_request.rs1use zerocopy::FromBytes;
2use zerocopy::Immutable;
3use zerocopy::IntoBytes;
4use zerocopy::KnownLayout;
5use zerocopy::Unaligned;
6
7use crate::transport::cfdp::CfdpError;
8use crate::transport::cfdp::filestore::FileId;
9use crate::transport::cfdp::pdu::tlv::FilestoreAction;
10use crate::transport::cfdp::pdu::tlv::Tlv;
11use crate::utils::get_bits_u8;
12use crate::utils::set_bits_u8;
13
14#[repr(C)]
16#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
17pub struct TlvFilestoreRequest {
18 action_code_and_spare: u8,
20 rest: [u8],
22}
23
24#[derive(Debug, PartialEq, Eq, Clone)]
26pub struct FilestoreRequest {
27 pub action: FilestoreAction,
29 pub first_file_name: FileId,
31 pub second_file_name: Option<FileId>,
33}
34
35#[rustfmt::skip]
36mod bitmasks {
38 pub const ACTION_CODE_MASK: u8 = 0b1111_0000;
40 pub const _SPARE_MASK: u8 = 0b0000_1111;
42}
43
44impl TlvFilestoreRequest {
45 pub fn from_tlv(tlv: &Tlv) -> Result<&Self, CfdpError> {
47 if tlv.length() < 1 {
48 return Err(CfdpError::Custom("Filestore Request TLV too short"));
49 }
50 TlvFilestoreRequest::ref_from_bytes(tlv.value())
51 .map_err(|_| CfdpError::Custom("Failed to parse Filestore Request TLV"))
52 }
53
54 pub fn action(&self) -> Result<FilestoreAction, CfdpError> {
56 get_bits_u8(self.action_code_and_spare, bitmasks::ACTION_CODE_MASK).try_into()
57 }
58
59 pub fn set_action(&mut self, action: FilestoreAction) {
61 set_bits_u8(
62 &mut self.action_code_and_spare,
63 bitmasks::ACTION_CODE_MASK,
64 action as u8,
65 );
66 }
67
68 pub fn first_file_name(&self) -> Result<&[u8], CfdpError> {
70 let len = *self
71 .rest
72 .first()
73 .ok_or(CfdpError::Custom("Missing first file name length"))? as usize;
74 self.rest
75 .get(1..1 + len)
76 .ok_or(CfdpError::Custom("Invalid first file name slice"))
77 }
78
79 pub fn second_file_name(&self) -> Result<Option<&[u8]>, CfdpError> {
81 let has_second = matches!(
82 self.action()?,
83 FilestoreAction::RenameFile
84 | FilestoreAction::AppendFile
85 | FilestoreAction::ReplaceFile
86 );
87 if !has_second {
88 return Ok(None);
89 }
90
91 let first_lv_len = 1 + self.first_file_name()?.len();
92 let remainder = self
93 .rest
94 .get(first_lv_len..)
95 .ok_or(CfdpError::Custom("Invalid slice after first file name"))?;
96
97 let len = *remainder
98 .first()
99 .ok_or(CfdpError::Custom("Missing second file name length"))?
100 as usize;
101 let name = remainder
102 .get(1..1 + len)
103 .ok_or(CfdpError::Custom("Invalid second file name slice"))?;
104 Ok(Some(name))
105 }
106}