1
//! Generic CFDP length-value (LV) abstraction as specified in CFDP 5.1.8.
2
use crate::ByteConversionError;
3
use core::str::Utf8Error;
4
#[cfg(feature = "serde")]
5
use serde::{Deserialize, Serialize};
6
#[cfg(feature = "std")]
7
use std::string::String;
8

            
9
use super::TlvLvDataTooLarge;
10

            
11
pub const MIN_LV_LEN: usize = 1;
12

            
13
/// Generic CFDP length-value (LV) abstraction as specified in CFDP 5.1.8.
14
///
15
/// Please note that this class is zero-copy and does not generate a copy of the value data for
16
/// both the regular [Self::new] constructor and the [Self::from_bytes] constructor.
17
///
18
/// # Lifetimes
19
///  * `data`: If the LV is generated from a raw bytestream, this will be the lifetime of
20
///    the raw bytestream. If the LV is generated from a raw slice or a similar data reference,
21
///    this will be the lifetime of that data reference.
22
#[derive(Debug, Copy, Clone, Eq)]
23
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
24
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25
pub struct Lv<'data> {
26
    data: &'data [u8],
27
    // If the LV was generated from a raw bytestream, this will contain the start of the
28
    // full LV.
29
    pub(crate) raw_data: Option<&'data [u8]>,
30
}
31

            
32
impl PartialEq for Lv<'_> {
33
126
    fn eq(&self, other: &Self) -> bool {
34
126
        self.data == other.data
35
126
    }
36
}
37

            
38
84
pub(crate) fn generic_len_check_data_serialization(
39
84
    buf: &[u8],
40
84
    data_len: usize,
41
84
    min_overhead: usize,
42
84
) -> Result<(), ByteConversionError> {
43
84
    if buf.len() < data_len + min_overhead {
44
2
        return Err(ByteConversionError::ToSliceTooSmall {
45
2
            found: buf.len(),
46
2
            expected: data_len + min_overhead,
47
2
        });
48
82
    }
49
82
    Ok(())
50
84
}
51

            
52
302
pub(crate) fn generic_len_check_deserialization(
53
302
    buf: &[u8],
54
302
    min_overhead: usize,
55
302
) -> Result<(), ByteConversionError> {
56
302
    if buf.len() < min_overhead {
57
2
        return Err(ByteConversionError::FromSliceTooSmall {
58
2
            found: buf.len(),
59
2
            expected: min_overhead,
60
2
        });
61
300
    }
62
300
    Ok(())
63
302
}
64

            
65
impl<'data> Lv<'data> {
66
    #[inline]
67
148
    pub fn new(data: &[u8]) -> Result<Lv, TlvLvDataTooLarge> {
68
148
        if data.len() > u8::MAX as usize {
69
4
            return Err(TlvLvDataTooLarge(data.len()));
70
144
        }
71
144
        Ok(Lv {
72
144
            data,
73
144
            raw_data: None,
74
144
        })
75
148
    }
76

            
77
    /// Creates a LV with an empty value field.
78
    #[inline]
79
30
    pub fn new_empty() -> Lv<'data> {
80
30
        Lv {
81
30
            data: &[],
82
30
            raw_data: None,
83
30
        }
84
30
    }
85

            
86
    /// Helper function to build a string LV. This is especially useful for the file or directory
87
    /// path LVs
88
    #[inline]
89
102
    pub fn new_from_str(str_slice: &str) -> Result<Lv, TlvLvDataTooLarge> {
90
102
        Self::new(str_slice.as_bytes())
91
102
    }
92

            
93
    /// Helper function to build a string LV. This is especially useful for the file or directory
94
    /// path LVs
95
    #[cfg(feature = "std")]
96
    #[inline]
97
2
    pub fn new_from_string(string: &'data String) -> Result<Lv<'data>, TlvLvDataTooLarge> {
98
2
        Self::new(string.as_bytes())
99
2
    }
100

            
101
    /// Returns the length of the value part, not including the length byte.
102
    #[inline]
103
738
    pub fn len_value(&self) -> usize {
104
738
        self.data.len()
105
738
    }
106

            
107
    /// Returns the full raw length, including the length byte.
108
    #[inline]
109
678
    pub fn len_full(&self) -> usize {
110
678
        self.len_value() + 1
111
678
    }
112

            
113
    /// Checks whether the value field is empty.
114
    #[inline]
115
128
    pub fn is_empty(&self) -> bool {
116
128
        self.data.len() == 0
117
128
    }
118

            
119
    #[inline]
120
200
    pub fn value(&self) -> &[u8] {
121
200
        self.data
122
200
    }
123

            
124
    /// If the LV was generated from a raw bytestream using [Self::from_bytes], the raw start
125
    /// of the LV can be retrieved with this method.
126
    #[inline]
127
10
    pub fn raw_data(&self) -> Option<&[u8]> {
128
10
        self.raw_data
129
10
    }
130

            
131
    /// Convenience function to extract the value as a [str]. This is useful if the LV is
132
    /// known to contain a [str], for example being a file name.
133
    #[inline]
134
6
    pub fn value_as_str(&self) -> Option<Result<&'data str, Utf8Error>> {
135
6
        if self.is_empty() {
136
            return None;
137
6
        }
138
6
        Some(core::str::from_utf8(self.data))
139
6
    }
140

            
141
    /// Writes the LV to a raw buffer. Please note that the first byte will contain the length
142
    /// of the value, but the values may not exceed a length of [u8::MAX].
143
54
    pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
144
54
        generic_len_check_data_serialization(buf, self.len_value(), MIN_LV_LEN)?;
145
52
        Ok(self.write_to_be_bytes_no_len_check(buf))
146
54
    }
147

            
148
    /// Reads a LV  from a raw buffer.
149
    #[inline]
150
124
    pub fn from_bytes(buf: &'data [u8]) -> Result<Lv<'data>, ByteConversionError> {
151
124
        generic_len_check_deserialization(buf, MIN_LV_LEN)?;
152
124
        Self::from_be_bytes_no_len_check(buf)
153
124
    }
154

            
155
112
    pub(crate) fn write_to_be_bytes_no_len_check(&self, buf: &mut [u8]) -> usize {
156
112
        if self.is_empty() {
157
24
            buf[0] = 0;
158
24
            return MIN_LV_LEN;
159
88
        }
160
88
        // Length check in constructor ensures the length always has a valid value.
161
88
        buf[0] = self.data.len() as u8;
162
88
        buf[MIN_LV_LEN..self.data.len() + MIN_LV_LEN].copy_from_slice(self.data);
163
88
        MIN_LV_LEN + self.data.len()
164
112
    }
165

            
166
    #[inline]
167
124
    pub(crate) fn from_be_bytes_no_len_check(
168
124
        buf: &'data [u8],
169
124
    ) -> Result<Lv<'data>, ByteConversionError> {
170
124
        let value_len = buf[0] as usize;
171
124
        generic_len_check_deserialization(buf, value_len + MIN_LV_LEN)?;
172
122
        Ok(Self {
173
122
            data: &buf[MIN_LV_LEN..MIN_LV_LEN + value_len],
174
122
            raw_data: Some(buf),
175
122
        })
176
124
    }
177
}
178

            
179
#[cfg(test)]
180
pub mod tests {
181
    use alloc::string::ToString;
182

            
183
    use super::*;
184

            
185
    use crate::ByteConversionError;
186
    use std::string::String;
187

            
188
    #[test]
189
2
    fn test_basic() {
190
2
        let lv_data: [u8; 4] = [1, 2, 3, 4];
191
2
        let lv_res = Lv::new(&lv_data);
192
2
        assert!(lv_res.is_ok());
193
2
        let lv = lv_res.unwrap();
194
2
        assert!(!lv.value().is_empty());
195
2
        let val = lv.value();
196
2
        assert_eq!(val[0], 1);
197
2
        assert_eq!(val[1], 2);
198
2
        assert_eq!(val[2], 3);
199
2
        assert_eq!(val[3], 4);
200
2
        assert!(!lv.is_empty());
201
2
        assert_eq!(lv.len_full(), 5);
202
2
        assert_eq!(lv.len_value(), 4);
203
2
    }
204

            
205
    #[test]
206
2
    fn test_empty() {
207
2
        let lv_empty = Lv::new_empty();
208
2
        assert_eq!(lv_empty.len_value(), 0);
209
2
        assert_eq!(lv_empty.len_full(), 1);
210
2
        assert!(lv_empty.is_empty());
211
2
        let mut buf: [u8; 4] = [0xff; 4];
212
2
        let res = lv_empty.write_to_be_bytes(&mut buf);
213
2
        assert!(res.is_ok());
214
2
        let written = res.unwrap();
215
2
        assert_eq!(written, 1);
216
2
        assert_eq!(buf[0], 0);
217
2
    }
218

            
219
    #[test]
220
2
    fn test_serialization() {
221
2
        let lv_data: [u8; 4] = [1, 2, 3, 4];
222
2
        let lv_res = Lv::new(&lv_data);
223
2
        assert!(lv_res.is_ok());
224
2
        let lv = lv_res.unwrap();
225
2
        let mut buf: [u8; 16] = [0; 16];
226
2
        let res = lv.write_to_be_bytes(&mut buf);
227
2
        assert!(res.is_ok());
228
2
        let written = res.unwrap();
229
2
        assert_eq!(written, 5);
230
2
        assert_eq!(buf[0], 4);
231
2
        assert_eq!(buf[1], 1);
232
2
        assert_eq!(buf[2], 2);
233
2
        assert_eq!(buf[3], 3);
234
2
        assert_eq!(buf[4], 4);
235
2
    }
236

            
237
    #[test]
238
2
    fn test_deserialization() {
239
2
        let mut buf: [u8; 16] = [0; 16];
240
2
        buf[0] = 4;
241
2
        buf[1] = 1;
242
2
        buf[2] = 2;
243
2
        buf[3] = 3;
244
2
        buf[4] = 4;
245
2
        let lv = Lv::from_bytes(&buf);
246
2
        assert!(lv.is_ok());
247
2
        let lv = lv.unwrap();
248
2
        assert!(!lv.is_empty());
249
2
        assert_eq!(lv.len_value(), 4);
250
2
        assert_eq!(lv.len_full(), 5);
251
2
        assert!(lv.raw_data().is_some());
252
2
        assert_eq!(lv.raw_data().unwrap(), buf);
253
2
        let val = lv.value();
254
2
        assert_eq!(val[0], 1);
255
2
        assert_eq!(val[1], 2);
256
2
        assert_eq!(val[2], 3);
257
2
        assert_eq!(val[3], 4);
258
2
    }
259

            
260
    #[test]
261
2
    fn test_deserialization_empty() {
262
2
        let buf: [u8; 2] = [0; 2];
263
2
        let lv_empty = Lv::from_bytes(&buf);
264
2
        assert!(lv_empty.is_ok());
265
2
        let lv_empty = lv_empty.unwrap();
266
2
        assert!(lv_empty.is_empty());
267
2
    }
268

            
269
    #[test]
270
2
    fn test_data_too_large() {
271
2
        let data_big: [u8; u8::MAX as usize + 1] = [0; u8::MAX as usize + 1];
272
2
        let lv = Lv::new(&data_big);
273
2
        assert!(lv.is_err());
274
2
        let error = lv.unwrap_err();
275
2
        assert_eq!(error.0, u8::MAX as usize + 1);
276
2
        assert_eq!(
277
2
            error.to_string(),
278
2
            "data with size 256 larger than allowed 255 bytes"
279
2
        );
280
2
    }
281

            
282
    #[test]
283
2
    fn test_serialization_buf_too_small() {
284
2
        let mut buf: [u8; 3] = [0; 3];
285
2
        let lv_data: [u8; 4] = [1, 2, 3, 4];
286
2
        let lv = Lv::new(&lv_data).unwrap();
287
2
        let res = lv.write_to_be_bytes(&mut buf);
288
2
        assert!(res.is_err());
289
2
        let error = res.unwrap_err();
290
2
        if let ByteConversionError::ToSliceTooSmall { found, expected } = error {
291
2
            assert_eq!(expected, 5);
292
2
            assert_eq!(found, 3);
293
        } else {
294
            panic!("invalid error {}", error);
295
        }
296
2
    }
297

            
298
    #[test]
299
2
    fn test_deserialization_buf_too_small() {
300
2
        let mut buf: [u8; 3] = [0; 3];
301
2
        buf[0] = 4;
302
2
        let res = Lv::from_bytes(&buf);
303
2
        assert!(res.is_err());
304
2
        let error = res.unwrap_err();
305
2
        if let ByteConversionError::FromSliceTooSmall { found, expected } = error {
306
2
            assert_eq!(found, 3);
307
2
            assert_eq!(expected, 5);
308
        } else {
309
            panic!("invalid error {}", error);
310
        }
311
2
    }
312

            
313
4
    fn verify_test_str_lv(lv: Lv) {
314
4
        let mut buf: [u8; 16] = [0; 16];
315
4
        let res = lv.write_to_be_bytes(&mut buf);
316
4
        assert!(res.is_ok());
317
4
        let res = res.unwrap();
318
4
        assert_eq!(res, 8 + 1);
319
4
        assert_eq!(buf[0], 8);
320
4
        assert_eq!(buf[1], b't');
321
4
        assert_eq!(buf[2], b'e');
322
4
        assert_eq!(buf[3], b's');
323
4
        assert_eq!(buf[4], b't');
324
4
        assert_eq!(buf[5], b'.');
325
4
        assert_eq!(buf[6], b'b');
326
4
        assert_eq!(buf[7], b'i');
327
4
        assert_eq!(buf[8], b'n');
328
4
    }
329
    #[test]
330
2
    fn test_str_helper() {
331
2
        let test_str = "test.bin";
332
2
        let str_lv = Lv::new_from_str(test_str);
333
2
        assert!(str_lv.is_ok());
334
2
        verify_test_str_lv(str_lv.unwrap());
335
2
    }
336

            
337
    #[test]
338
2
    fn test_string_helper() {
339
2
        let string = String::from("test.bin");
340
2
        let str_lv = Lv::new_from_string(&string);
341
2
        assert!(str_lv.is_ok());
342
2
        verify_test_str_lv(str_lv.unwrap());
343
2
    }
344
}