leodos_protocols/transport/cfdp/pdu/tlv/
filestore_response.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::utils::get_bits_u8;
11
12#[repr(C)]
14#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
15pub struct TlvFilestoreResponse {
16 action_and_status_code: u8,
18 rest: [u8],
20}
21
22#[derive(Debug, PartialEq, Eq, Clone)]
24pub struct FilestoreResponse {
25 pub action: FilestoreAction,
27 pub first_file_name: FileId,
29 pub second_file_name: FileId,
31}
32
33#[rustfmt::skip]
34mod bitmasks {
35 pub const ACTION_CODE_MASK: u8 = 0b1111_0000;
36 pub const STATUS_CODE_MASK: u8 = 0b0000_1111;
37}
38
39impl TlvFilestoreResponse {
40 pub fn action(&self) -> Result<FilestoreAction, CfdpError> {
42 get_bits_u8(self.action_and_status_code, bitmasks::ACTION_CODE_MASK).try_into()
43 }
44
45 pub fn status_code(&self) -> u8 {
47 get_bits_u8(self.action_and_status_code, bitmasks::STATUS_CODE_MASK)
48 }
49
50 pub fn first_file_name(&self) -> Result<&[u8], CfdpError> {
56 let len = *self
57 .rest
58 .first()
59 .ok_or(CfdpError::Custom("Missing first file name length"))? as usize;
60 self.rest
61 .get(1..1 + len)
62 .ok_or(CfdpError::Custom("Invalid first file name slice"))
63 }
64
65 fn parse_after_first_name(&self) -> Result<(Option<&[u8]>, &[u8]), CfdpError> {
69 let first_lv_len = 1 + self.first_file_name()?.len();
70 let mut remainder = self
71 .rest
72 .get(first_lv_len..)
73 .ok_or(CfdpError::Custom("Invalid slice after first file name"))?;
74
75 let has_second = matches!(
76 self.action()?,
77 FilestoreAction::RenameFile
78 | FilestoreAction::AppendFile
79 | FilestoreAction::ReplaceFile
80 );
81
82 let second_file_name = if has_second {
83 let len = *remainder
84 .first()
85 .ok_or(CfdpError::Custom("Missing second name len"))?
86 as usize;
87 remainder = remainder
88 .get(1..)
89 .ok_or(CfdpError::Custom("Invalid FS Response"))?;
90 let (name, rest) = remainder.split_at(len);
91 remainder = rest;
92 Some(name)
93 } else {
94 None
95 };
96
97 let msg_len = *remainder
98 .first()
99 .ok_or(CfdpError::Custom("Missing message len"))? as usize;
100 let message = remainder
101 .get(1..1 + msg_len)
102 .ok_or(CfdpError::Custom("Invalid message slice"))?;
103
104 Ok((second_file_name, message))
105 }
106
107 pub fn second_file_name(&self) -> Result<Option<&[u8]>, CfdpError> {
109 self.parse_after_first_name().map(|(name, _)| name)
110 }
111
112 pub fn message(&self) -> Result<&[u8], CfdpError> {
114 self.parse_after_first_name().map(|(_, msg)| msg)
115 }
116}