1
//! Abstractions for the Message to User CFDP TLV subtype.
2
#[cfg(feature = "alloc")]
3
use super::TlvOwned;
4
use super::{GenericTlv, ReadableTlv, Tlv, TlvLvError, TlvType, TlvTypeField, WritableTlv};
5
use crate::{cfdp::TlvLvDataTooLarge, ByteConversionError};
6
use delegate::delegate;
7

            
8
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9
pub struct MsgToUserTlv<'data> {
10
    pub tlv: Tlv<'data>,
11
}
12

            
13
impl<'data> MsgToUserTlv<'data> {
14
    /// Create a new message to user TLV where the type field is set correctly.
15
14
    pub fn new(value: &'data [u8]) -> Result<MsgToUserTlv<'data>, TlvLvDataTooLarge> {
16
14
        Ok(Self {
17
14
            tlv: Tlv::new(TlvType::MsgToUser, value)?,
18
        })
19
14
    }
20

            
21
    delegate! {
22
        to self.tlv {
23
27
            pub fn value(&self) -> &[u8];
24
            /// Helper method to retrieve the length of the value. Simply calls the [slice::len] method of
25
            /// [Self::value]
26
2
            pub fn len_value(&self) -> usize;
27
            /// Returns the full raw length, including the length byte.
28
6
            pub fn len_full(&self) -> usize;
29
            /// Checks whether the value field is empty.
30
2
            pub fn is_empty(&self) -> bool;
31
            /// If the TLV was generated from a raw bytestream using [Self::from_bytes], the raw start
32
            /// of the TLV can be retrieved with this method.
33
2
            pub fn raw_data(&self) -> Option<&[u8]>;
34
        }
35
    }
36

            
37
2
    pub fn is_standard_tlv(&self) -> bool {
38
2
        true
39
2
    }
40

            
41
6
    pub fn tlv_type(&self) -> Option<TlvType> {
42
6
        Some(TlvType::MsgToUser)
43
6
    }
44

            
45
    /// Check whether this message is a reserved CFDP message like a Proxy Operation Message.
46
6
    pub fn is_reserved_cfdp_msg(&self) -> bool {
47
6
        if self.value().len() < 4 {
48
2
            return false;
49
4
        }
50
4
        let value = self.value();
51
4
        if value[0] == b'c' && value[1] == b'f' && value[2] == b'd' && value[3] == b'p' {
52
2
            return true;
53
2
        }
54
2
        false
55
6
    }
56

            
57
    /// This is a thin wrapper around [Tlv::from_bytes] with the additional type check.
58
4
    pub fn from_bytes(buf: &'data [u8]) -> Result<MsgToUserTlv<'data>, TlvLvError> {
59
4
        let msg_to_user = Self {
60
4
            tlv: Tlv::from_bytes(buf)?,
61
        };
62
4
        match msg_to_user.tlv.tlv_type_field() {
63
4
            TlvTypeField::Standard(tlv_type) => {
64
4
                if tlv_type != TlvType::MsgToUser {
65
2
                    return Err(TlvLvError::InvalidTlvTypeField {
66
2
                        found: tlv_type as u8,
67
2
                        expected: Some(TlvType::MsgToUser as u8),
68
2
                    });
69
2
                }
70
            }
71
            TlvTypeField::Custom(raw) => {
72
                return Err(TlvLvError::InvalidTlvTypeField {
73
                    found: raw,
74
                    expected: Some(TlvType::MsgToUser as u8),
75
                });
76
            }
77
        }
78
2
        Ok(msg_to_user)
79
4
    }
80

            
81
6
    pub fn to_tlv(&self) -> Tlv<'data> {
82
6
        self.tlv
83
6
    }
84

            
85
    #[cfg(feature = "alloc")]
86
2
    pub fn to_owned(&self) -> TlvOwned {
87
2
        self.tlv.to_owned()
88
2
    }
89
}
90

            
91
impl<'a> From<MsgToUserTlv<'a>> for Tlv<'a> {
92
2
    fn from(value: MsgToUserTlv<'a>) -> Tlv<'a> {
93
2
        value.to_tlv()
94
2
    }
95
}
96

            
97
impl WritableTlv for MsgToUserTlv<'_> {
98
2
    fn len_written(&self) -> usize {
99
2
        self.len_full()
100
2
    }
101

            
102
    delegate!(
103
        to self.tlv {
104
6
            fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError>;
105
        }
106
    );
107
}
108

            
109
impl GenericTlv for MsgToUserTlv<'_> {
110
2
    fn tlv_type_field(&self) -> TlvTypeField {
111
2
        self.tlv.tlv_type_field()
112
2
    }
113
}
114

            
115
#[cfg(test)]
116
mod tests {
117
    use super::*;
118

            
119
    #[test]
120
2
    fn test_basic() {
121
2
        let custom_value: [u8; 4] = [1, 2, 3, 4];
122
2
        let msg_to_user = MsgToUserTlv::new(&custom_value);
123
2
        assert!(msg_to_user.is_ok());
124
2
        let msg_to_user = msg_to_user.unwrap();
125
2
        assert!(msg_to_user.is_standard_tlv());
126
2
        assert_eq!(msg_to_user.tlv_type().unwrap(), TlvType::MsgToUser);
127
2
        assert_eq!(
128
2
            msg_to_user.tlv_type_field(),
129
2
            TlvTypeField::Standard(TlvType::MsgToUser)
130
2
        );
131
2
        assert_eq!(msg_to_user.value(), custom_value);
132
2
        assert_eq!(msg_to_user.value().len(), 4);
133
2
        assert_eq!(msg_to_user.len_value(), 4);
134
2
        assert_eq!(msg_to_user.len_full(), 6);
135
2
        assert!(!msg_to_user.is_empty());
136
2
        assert!(msg_to_user.raw_data().is_none());
137
2
        assert!(!msg_to_user.is_reserved_cfdp_msg());
138
2
    }
139

            
140
    #[test]
141
2
    fn test_reserved_msg_serialization() {
142
2
        let custom_value: [u8; 4] = [1, 2, 3, 4];
143
2
        let msg_to_user = MsgToUserTlv::new(&custom_value).unwrap();
144
2
        let mut buf: [u8; 6] = [0; 6];
145
2
        msg_to_user.write_to_bytes(&mut buf).unwrap();
146
2
        assert_eq!(
147
2
            buf,
148
2
            [
149
2
                TlvType::MsgToUser as u8,
150
2
                custom_value.len() as u8,
151
2
                1,
152
2
                2,
153
2
                3,
154
2
                4
155
2
            ]
156
2
        );
157
2
    }
158

            
159
    #[test]
160
2
    fn test_msg_to_user_type_reduction() {
161
2
        let custom_value: [u8; 4] = [1, 2, 3, 4];
162
2
        let msg_to_user = MsgToUserTlv::new(&custom_value).unwrap();
163
2
        let tlv = msg_to_user.to_tlv();
164
2
        assert_eq!(
165
2
            tlv.tlv_type_field(),
166
2
            TlvTypeField::Standard(TlvType::MsgToUser)
167
2
        );
168

            
169
2
        assert_eq!(tlv.value(), custom_value);
170
2
    }
171

            
172
    #[test]
173
2
    fn test_msg_to_user_to_tlv() {
174
2
        let custom_value: [u8; 4] = [1, 2, 3, 4];
175
2
        let msg_to_user = MsgToUserTlv::new(&custom_value).unwrap();
176
2
        let tlv: Tlv = msg_to_user.into();
177
2
        assert_eq!(msg_to_user.to_tlv(), tlv);
178
2
    }
179

            
180
    #[test]
181
2
    fn test_msg_to_user_owner_converter() {
182
2
        let custom_value: [u8; 4] = [1, 2, 3, 4];
183
2
        let msg_to_user = MsgToUserTlv::new(&custom_value).unwrap();
184
2
        let tlv = msg_to_user.to_owned();
185
2
        assert_eq!(
186
2
            tlv.tlv_type_field(),
187
2
            TlvTypeField::Standard(TlvType::MsgToUser)
188
2
        );
189

            
190
2
        assert_eq!(tlv.value(), custom_value);
191
2
    }
192

            
193
    #[test]
194
2
    fn test_reserved_msg_deserialization() {
195
2
        let custom_value: [u8; 3] = [1, 2, 3];
196
2
        let msg_to_user = MsgToUserTlv::new(&custom_value).unwrap();
197
2
        let msg_to_user_vec = msg_to_user.to_vec();
198
2
        let msg_to_user_from_bytes = MsgToUserTlv::from_bytes(&msg_to_user_vec).unwrap();
199
2
        assert!(!msg_to_user.is_reserved_cfdp_msg());
200
2
        assert_eq!(msg_to_user_from_bytes, msg_to_user);
201
2
        assert_eq!(msg_to_user_from_bytes.value(), msg_to_user.value());
202
2
        assert_eq!(msg_to_user_from_bytes.tlv_type(), msg_to_user.tlv_type());
203
2
    }
204
    #[test]
205
2
    fn test_reserved_msg_deserialization_invalid_type() {
206
2
        let trash: [u8; 5] = [TlvType::FlowLabel as u8, 3, 1, 2, 3];
207
2
        let error = MsgToUserTlv::from_bytes(&trash).unwrap_err();
208
2
        if let TlvLvError::InvalidTlvTypeField { found, expected } = error {
209
2
            assert_eq!(found, TlvType::FlowLabel as u8);
210
2
            assert_eq!(expected, Some(TlvType::MsgToUser as u8));
211
        } else {
212
            panic!("Wrong error type returned: {:?}", error);
213
        }
214
2
    }
215

            
216
    #[test]
217
2
    fn test_reserved_msg() {
218
2
        let reserved_str = "cfdp";
219
2
        let msg_to_user = MsgToUserTlv::new(reserved_str.as_bytes());
220
2
        assert!(msg_to_user.is_ok());
221
2
        let msg_to_user = msg_to_user.unwrap();
222
2
        assert!(msg_to_user.is_reserved_cfdp_msg());
223
2
    }
224
}