1
//! Generic CFDP type-length-value (TLV) abstraction as specified in CFDP 5.1.9.
2
use crate::cfdp::lv::{
3
    generic_len_check_data_serialization, generic_len_check_deserialization, Lv, MIN_LV_LEN,
4
};
5
use crate::cfdp::TlvLvError;
6
use crate::util::{UnsignedByteField, UnsignedByteFieldError, UnsignedEnum};
7
use crate::ByteConversionError;
8
#[cfg(feature = "alloc")]
9
use alloc::vec;
10
#[cfg(feature = "alloc")]
11
use alloc::vec::Vec;
12
#[cfg(feature = "alloc")]
13
pub use alloc_mod::*;
14
use num_enum::{IntoPrimitive, TryFromPrimitive};
15
#[cfg(feature = "serde")]
16
use serde::{Deserialize, Serialize};
17

            
18
use super::TlvLvDataTooLarge;
19

            
20
pub mod msg_to_user;
21

            
22
pub const MIN_TLV_LEN: usize = 2;
23

            
24
pub trait GenericTlv {
25
    fn tlv_type_field(&self) -> TlvTypeField;
26

            
27
    /// Checks whether the type field contains one of the standard types specified in the CFDP
28
    /// standard and is part of the [TlvType] enum.
29
4
    fn is_standard_tlv(&self) -> bool {
30
4
        if let TlvTypeField::Standard(_) = self.tlv_type_field() {
31
2
            return true;
32
2
        }
33
2
        false
34
4
    }
35

            
36
    /// Returns the standard TLV type if the TLV field is not a custom field
37
4
    fn tlv_type(&self) -> Option<TlvType> {
38
4
        if let TlvTypeField::Standard(tlv_type) = self.tlv_type_field() {
39
2
            Some(tlv_type)
40
        } else {
41
2
            None
42
        }
43
4
    }
44
}
45

            
46
pub trait ReadableTlv {
47
    fn value(&self) -> &[u8];
48

            
49
    /// Checks whether the value field is empty.
50
14
    fn is_empty(&self) -> bool {
51
14
        self.value().is_empty()
52
14
    }
53

            
54
    /// Helper method to retrieve the length of the value. Simply calls the [slice::len] method of
55
    /// [Self::value]
56
114
    fn len_value(&self) -> usize {
57
114
        self.value().len()
58
114
    }
59

            
60
    /// Returns the full raw length, including the length byte.
61
102
    fn len_full(&self) -> usize {
62
102
        self.len_value() + 2
63
102
    }
64
}
65

            
66
pub trait WritableTlv {
67
    fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError>;
68
    fn len_written(&self) -> usize;
69
    #[cfg(feature = "alloc")]
70
14
    fn to_vec(&self) -> Vec<u8> {
71
14
        let mut buf = vec![0; self.len_written()];
72
14
        self.write_to_bytes(&mut buf).unwrap();
73
14
        buf
74
14
    }
75
}
76

            
77
80
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
78
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
79
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80
#[repr(u8)]
81
pub enum TlvType {
82
    FilestoreRequest = 0x00,
83
    FilestoreResponse = 0x01,
84
    MsgToUser = 0x02,
85
    FaultHandler = 0x04,
86
    FlowLabel = 0x05,
87
    EntityId = 0x06,
88
}
89

            
90
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
91
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
92
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
93
pub enum TlvTypeField {
94
    Standard(TlvType),
95
    Custom(u8),
96
}
97

            
98
14
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
99
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
100
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
101
#[repr(u8)]
102
pub enum FilestoreActionCode {
103
    CreateFile = 0b0000,
104
    DeleteFile = 0b0001,
105
    RenameFile = 0b0010,
106
    /// This operation appends one file to another. The first specified name will form the first
107
    /// part of the new file and the name of the new file. This function can be used to get
108
    /// similar functionality to the UNIX cat utility (albeit for only two files).
109
    AppendFile = 0b0011,
110
    /// This operation replaces the content of the first specified file with the content of
111
    /// the secondly specified file.
112
    ReplaceFile = 0b0100,
113
    CreateDirectory = 0b0101,
114
    RemoveDirectory = 0b0110,
115
    DenyFile = 0b0111,
116
    DenyDirectory = 0b1000,
117
}
118

            
119
impl From<u8> for TlvTypeField {
120
54
    fn from(value: u8) -> Self {
121
54
        match TlvType::try_from(value) {
122
52
            Ok(tlv_type) => TlvTypeField::Standard(tlv_type),
123
2
            Err(_) => TlvTypeField::Custom(value),
124
        }
125
54
    }
126
}
127

            
128
impl From<TlvTypeField> for u8 {
129
30
    fn from(value: TlvTypeField) -> Self {
130
30
        match value {
131
28
            TlvTypeField::Standard(std) => std as u8,
132
2
            TlvTypeField::Custom(custom) => custom,
133
        }
134
30
    }
135
}
136

            
137
/// Generic CFDP type-length-value (TLV) abstraction as specified in CFDP 5.1.9.
138
///
139
/// Please note that this class is zero-copy and does not generate a copy of the value data for
140
/// both the regular [Self::new] constructor and the [Self::from_bytes] constructor.
141
///
142
/// # Lifetimes
143
///  * `data`: If the TLV is generated from a raw bytestream, this will be the lifetime of
144
///    the raw bytestream. If the TLV is generated from a raw slice or a similar data reference,
145
///    this will be the lifetime of that data reference.
146
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
147
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
148
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
149
pub struct Tlv<'data> {
150
    tlv_type_field: TlvTypeField,
151
    #[cfg_attr(feature = "serde", serde(borrow))]
152
    lv: Lv<'data>,
153
}
154

            
155
impl<'data> Tlv<'data> {
156
34
    pub fn new(tlv_type: TlvType, data: &[u8]) -> Result<Tlv, TlvLvDataTooLarge> {
157
34
        Ok(Tlv {
158
34
            tlv_type_field: TlvTypeField::Standard(tlv_type),
159
34
            lv: Lv::new(data)?,
160
        })
161
34
    }
162

            
163
2
    pub fn new_with_custom_type(tlv_type: u8, data: &[u8]) -> Result<Tlv, TlvLvDataTooLarge> {
164
2
        Ok(Tlv {
165
2
            tlv_type_field: TlvTypeField::Custom(tlv_type),
166
2
            lv: Lv::new(data)?,
167
        })
168
2
    }
169

            
170
    /// Creates a TLV with an empty value field.
171
12
    pub fn new_empty(tlv_type: TlvType) -> Tlv<'data> {
172
12
        Tlv {
173
12
            tlv_type_field: TlvTypeField::Standard(tlv_type),
174
12
            lv: Lv::new_empty(),
175
12
        }
176
12
    }
177

            
178
    /// Creates a TLV give a raw bytestream. Please note that is is not necessary to pass the
179
    /// bytestream with the exact size of the expected TLV. This function will take care
180
    /// of parsing the length byte, and the length of the parsed TLV can be retrieved using
181
    /// [Self::len_full].
182
54
    pub fn from_bytes(buf: &'data [u8]) -> Result<Tlv<'data>, TlvLvError> {
183
54
        generic_len_check_deserialization(buf, MIN_TLV_LEN)?;
184
54
        let mut tlv = Self {
185
54
            tlv_type_field: TlvTypeField::from(buf[0]),
186
54
            lv: Lv::from_bytes(&buf[MIN_LV_LEN..])?,
187
        };
188
        // We re-use this field so we do not need an additional struct field to store the raw start
189
        // of the TLV.
190
54
        tlv.lv.raw_data = Some(buf);
191
54
        Ok(tlv)
192
54
    }
193

            
194
    /// If the TLV was generated from a raw bytestream using [Self::from_bytes], the raw start
195
    /// of the TLV can be retrieved with this method.
196
6
    pub fn raw_data(&self) -> Option<&[u8]> {
197
6
        self.lv.raw_data()
198
6
    }
199

            
200
    #[cfg(feature = "alloc")]
201
8
    pub fn to_owned(&self) -> TlvOwned {
202
8
        TlvOwned {
203
8
            tlv_type_field: self.tlv_type_field,
204
8
            data: self.value().to_vec(),
205
8
        }
206
8
    }
207
}
208

            
209
#[cfg(feature = "alloc")]
210
impl PartialEq<TlvOwned> for Tlv<'_> {
211
2
    fn eq(&self, other: &TlvOwned) -> bool {
212
2
        self.tlv_type_field == other.tlv_type_field && self.value() == other.value()
213
2
    }
214
}
215

            
216
impl ReadableTlv for Tlv<'_> {
217
194
    fn value(&self) -> &[u8] {
218
194
        self.lv.value()
219
194
    }
220
}
221

            
222
impl WritableTlv for Tlv<'_> {
223
24
    fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
224
24
        generic_len_check_data_serialization(buf, self.value().len(), MIN_TLV_LEN)?;
225
24
        buf[0] = self.tlv_type_field.into();
226
24
        self.lv.write_to_be_bytes_no_len_check(&mut buf[1..]);
227
24
        Ok(self.len_full())
228
24
    }
229
4
    fn len_written(&self) -> usize {
230
4
        self.len_full()
231
4
    }
232
}
233

            
234
impl GenericTlv for Tlv<'_> {
235
38
    fn tlv_type_field(&self) -> TlvTypeField {
236
38
        self.tlv_type_field
237
38
    }
238
}
239

            
240
#[cfg(feature = "alloc")]
241
pub mod alloc_mod {
242
    use crate::cfdp::TlvLvDataTooLarge;
243

            
244
    use super::*;
245

            
246
    /// Owned variant of [Tlv] which is consequently [Clone]able and does not have a lifetime
247
    /// associated to a data slice.
248
    #[derive(Debug, Clone, PartialEq, Eq)]
249
    #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
250
    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
251
    pub struct TlvOwned {
252
        pub(crate) tlv_type_field: TlvTypeField,
253
        pub(crate) data: Vec<u8>,
254
    }
255

            
256
    impl TlvOwned {
257
4
        pub fn new(tlv_type: TlvType, data: &[u8]) -> Result<Self, TlvLvDataTooLarge> {
258
4
            if data.len() > u8::MAX as usize {
259
                return Err(TlvLvDataTooLarge(data.len()));
260
4
            }
261
4
            Ok(Self {
262
4
                tlv_type_field: TlvTypeField::Standard(tlv_type),
263
4
                data: data.to_vec(),
264
4
            })
265
4
        }
266

            
267
2
        pub fn new_with_custom_type(tlv_type: u8, data: &[u8]) -> Result<Self, TlvLvDataTooLarge> {
268
2
            if data.len() > u8::MAX as usize {
269
                return Err(TlvLvDataTooLarge(data.len()));
270
2
            }
271
2
            Ok(Self {
272
2
                tlv_type_field: TlvTypeField::Custom(tlv_type),
273
2
                data: data.to_vec(),
274
2
            })
275
2
        }
276

            
277
        /// Creates a TLV with an empty value field.
278
4
        pub fn new_empty(tlv_type: TlvType) -> Self {
279
4
            Self {
280
4
                tlv_type_field: TlvTypeField::Standard(tlv_type),
281
4
                data: Vec::new(),
282
4
            }
283
4
        }
284

            
285
        pub fn as_tlv(&self) -> Tlv<'_> {
286
            Tlv {
287
                tlv_type_field: self.tlv_type_field,
288
                // The API should ensure that the data length is never to large, so the unwrap for the
289
                // LV creation should never be an issue.
290
                lv: Lv::new(&self.data).expect("lv creation failed unexpectedly"),
291
            }
292
        }
293
    }
294

            
295
    impl ReadableTlv for TlvOwned {
296
30
        fn value(&self) -> &[u8] {
297
30
            &self.data
298
30
        }
299
    }
300

            
301
    impl WritableTlv for TlvOwned {
302
6
        fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
303
6
            generic_len_check_data_serialization(buf, self.data.len(), MIN_TLV_LEN)?;
304
6
            buf[0] = self.tlv_type_field.into();
305
6
            buf[1] = self.data.len() as u8;
306
6
            buf[2..2 + self.data.len()].copy_from_slice(&self.data);
307
6
            Ok(self.len_written())
308
6
        }
309

            
310
12
        fn len_written(&self) -> usize {
311
12
            self.data.len() + 2
312
12
        }
313
    }
314

            
315
    impl GenericTlv for TlvOwned {
316
8
        fn tlv_type_field(&self) -> TlvTypeField {
317
8
            self.tlv_type_field
318
8
        }
319
    }
320

            
321
    impl From<Tlv<'_>> for TlvOwned {
322
4
        fn from(value: Tlv<'_>) -> Self {
323
4
            value.to_owned()
324
4
        }
325
    }
326

            
327
    impl PartialEq<Tlv<'_>> for TlvOwned {
328
6
        fn eq(&self, other: &Tlv) -> bool {
329
6
            self.tlv_type_field == other.tlv_type_field && self.data == other.value()
330
6
        }
331
    }
332
}
333

            
334
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
335
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
336
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
337
pub struct EntityIdTlv {
338
    entity_id: UnsignedByteField,
339
}
340

            
341
impl EntityIdTlv {
342
22
    pub fn new(entity_id: UnsignedByteField) -> Self {
343
22
        Self { entity_id }
344
22
    }
345

            
346
34
    fn check_min_len(buf: &[u8]) -> Result<(), ByteConversionError> {
347
34
        if buf.len() < 2 {
348
            return Err(ByteConversionError::ToSliceTooSmall {
349
                found: buf.len(),
350
                expected: 2,
351
            });
352
34
        }
353
34
        Ok(())
354
34
    }
355

            
356
12
    pub fn entity_id(&self) -> &UnsignedByteField {
357
12
        &self.entity_id
358
12
    }
359

            
360
6
    pub fn len_value(&self) -> usize {
361
6
        self.entity_id.size()
362
6
    }
363

            
364
42
    pub fn len_full(&self) -> usize {
365
42
        2 + self.entity_id.size()
366
42
    }
367

            
368
12
    pub fn from_bytes(buf: &[u8]) -> Result<Self, TlvLvError> {
369
12
        Self::check_min_len(buf)?;
370
12
        verify_tlv_type(buf[0], TlvType::EntityId)?;
371
12
        let len = buf[1];
372
12
        if len != 1 && len != 2 && len != 4 && len != 8 {
373
2
            return Err(TlvLvError::InvalidValueLength(len as usize));
374
10
        }
375
10
        // Okay to unwrap here. The checks before make sure that the deserialization never fails
376
10
        let entity_id = UnsignedByteField::new_from_be_bytes(len as usize, &buf[2..]).unwrap();
377
10
        Ok(Self { entity_id })
378
12
    }
379

            
380
    /// Convert to a generic [Tlv], which also erases the type information.
381
4
    pub fn to_tlv(self, buf: &mut [u8]) -> Result<Tlv, ByteConversionError> {
382
4
        Self::check_min_len(buf)?;
383
4
        self.entity_id
384
4
            .write_to_be_bytes(&mut buf[2..2 + self.entity_id.size()])?;
385
4
        if buf.len() < self.len_value() {
386
            return Err(ByteConversionError::ToSliceTooSmall {
387
                found: buf.len(),
388
                expected: self.len_value(),
389
            });
390
4
        }
391
4
        // We performed all checks necessary to ensure this call never panics.
392
4
        Ok(Tlv::new(TlvType::EntityId, &buf[2..2 + self.entity_id.size()]).unwrap())
393
4
    }
394

            
395
    #[cfg(feature = "alloc")]
396
    pub fn to_owned(&self) -> TlvOwned {
397
        // Unwrap is okay here, entity ID should never be larger than maximum allowed size.
398
        TlvOwned::new(TlvType::EntityId, &self.entity_id.to_vec()).unwrap()
399
    }
400
}
401

            
402
impl WritableTlv for EntityIdTlv {
403
18
    fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
404
18
        Self::check_min_len(buf)?;
405
18
        buf[0] = TlvType::EntityId as u8;
406
18
        buf[1] = self.entity_id.size() as u8;
407
18
        Ok(2 + self.entity_id.write_to_be_bytes(&mut buf[2..])?)
408
18
    }
409

            
410
2
    fn len_written(&self) -> usize {
411
2
        self.len_full()
412
2
    }
413
}
414

            
415
impl GenericTlv for EntityIdTlv {
416
4
    fn tlv_type_field(&self) -> TlvTypeField {
417
4
        TlvTypeField::Standard(TlvType::EntityId)
418
4
    }
419
}
420

            
421
impl<'data> TryFrom<Tlv<'data>> for EntityIdTlv {
422
    type Error = TlvLvError;
423

            
424
4
    fn try_from(value: Tlv) -> Result<Self, Self::Error> {
425
4
        match value.tlv_type_field {
426
4
            TlvTypeField::Standard(tlv_type) => {
427
4
                if tlv_type != TlvType::EntityId {
428
2
                    return Err(TlvLvError::InvalidTlvTypeField {
429
2
                        found: tlv_type as u8,
430
2
                        expected: Some(TlvType::EntityId as u8),
431
2
                    });
432
2
                }
433
            }
434
            TlvTypeField::Custom(val) => {
435
                return Err(TlvLvError::InvalidTlvTypeField {
436
                    found: val,
437
                    expected: Some(TlvType::EntityId as u8),
438
                });
439
            }
440
        }
441
2
        let len_value = value.value().len();
442
2
        if len_value != 1 && len_value != 2 && len_value != 4 && len_value != 8 {
443
            return Err(TlvLvError::InvalidValueLength(len_value));
444
2
        }
445
2
        Ok(Self::new(
446
2
            UnsignedByteField::new_from_be_bytes(len_value, value.value()).map_err(
447
2
                |e| match e {
448
                    UnsignedByteFieldError::ByteConversionError(e) => e,
449
                    // This can not happen, we checked for the length validity, and the data is always smaller than
450
                    // 255 bytes.
451
                    _ => panic!("unexpected error"),
452
2
                },
453
2
            )?,
454
        ))
455
4
    }
456
}
457

            
458
58
pub fn fs_request_has_second_filename(action_code: FilestoreActionCode) -> bool {
459
58
    if action_code == FilestoreActionCode::RenameFile
460
44
        || action_code == FilestoreActionCode::AppendFile
461
40
        || action_code == FilestoreActionCode::ReplaceFile
462
    {
463
22
        return true;
464
36
    }
465
36
    false
466
58
}
467

            
468
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
469
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
470
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
471
struct FilestoreTlvBase<'first_name, 'second_name> {
472
    pub action_code: FilestoreActionCode,
473
    #[cfg_attr(feature = "serde", serde(borrow))]
474
    pub first_name: Lv<'first_name>,
475
    #[cfg_attr(feature = "serde", serde(borrow))]
476
    pub second_name: Option<Lv<'second_name>>,
477
}
478

            
479
impl FilestoreTlvBase<'_, '_> {
480
182
    fn base_len_value(&self) -> usize {
481
182
        let mut len = 1 + self.first_name.len_full();
482
182
        if let Some(second_name) = self.second_name {
483
64
            len += second_name.len_full();
484
118
        }
485
182
        len
486
182
    }
487
}
488

            
489
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
490
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
491
pub struct FilestoreRequestTlv<'first_name, 'second_name> {
492
    #[cfg_attr(feature = "serde", serde(borrow))]
493
    base: FilestoreTlvBase<'first_name, 'second_name>,
494
}
495

            
496
impl<'first_name, 'second_name> FilestoreRequestTlv<'first_name, 'second_name> {
497
8
    pub fn new_create_file(file_name: Lv<'first_name>) -> Result<Self, TlvLvError> {
498
8
        Self::new(FilestoreActionCode::CreateFile, file_name, None)
499
8
    }
500

            
501
2
    pub fn new_delete_file(file_name: Lv<'first_name>) -> Result<Self, TlvLvError> {
502
2
        Self::new(FilestoreActionCode::DeleteFile, file_name, None)
503
2
    }
504

            
505
6
    pub fn new_rename_file(
506
6
        source_name: Lv<'first_name>,
507
6
        target_name: Lv<'second_name>,
508
6
    ) -> Result<Self, TlvLvError> {
509
6
        Self::new(
510
6
            FilestoreActionCode::RenameFile,
511
6
            source_name,
512
6
            Some(target_name),
513
6
        )
514
6
    }
515

            
516
    /// This operation appends one file to another. The first specified name will form the first
517
    /// part of the new file and the name of the new file. This function can be used to get
518
    /// similar functionality to the UNIX cat utility (albeit for only two files).
519
2
    pub fn new_append_file(
520
2
        first_file: Lv<'first_name>,
521
2
        second_file: Lv<'second_name>,
522
2
    ) -> Result<Self, TlvLvError> {
523
2
        Self::new(
524
2
            FilestoreActionCode::AppendFile,
525
2
            first_file,
526
2
            Some(second_file),
527
2
        )
528
2
    }
529

            
530
    /// This operation replaces the content of the first specified file with the content of
531
    /// the secondly specified file. This function can be used to get similar functionality to
532
    /// the UNIX copy (cp) utility if the target file already exists.
533
2
    pub fn new_replace_file(
534
2
        replaced_file: Lv<'first_name>,
535
2
        new_file: Lv<'second_name>,
536
2
    ) -> Result<Self, TlvLvError> {
537
2
        Self::new(
538
2
            FilestoreActionCode::ReplaceFile,
539
2
            replaced_file,
540
2
            Some(new_file),
541
2
        )
542
2
    }
543

            
544
2
    pub fn new_create_directory(dir_name: Lv<'first_name>) -> Result<Self, TlvLvError> {
545
2
        Self::new(FilestoreActionCode::CreateDirectory, dir_name, None)
546
2
    }
547

            
548
2
    pub fn new_remove_directory(dir_name: Lv<'first_name>) -> Result<Self, TlvLvError> {
549
2
        Self::new(FilestoreActionCode::RemoveDirectory, dir_name, None)
550
2
    }
551

            
552
2
    pub fn new_deny_file(file_name: Lv<'first_name>) -> Result<Self, TlvLvError> {
553
2
        Self::new(FilestoreActionCode::DenyFile, file_name, None)
554
2
    }
555

            
556
2
    pub fn new_deny_directory(dir_name: Lv<'first_name>) -> Result<Self, TlvLvError> {
557
2
        Self::new(FilestoreActionCode::DenyDirectory, dir_name, None)
558
2
    }
559

            
560
    /// This function will return [None] if the respective action code requires two names but
561
    /// only one is passed. It will also returns [None] if the cumulative length of the first
562
    /// name and the second name exceeds 255 bytes.
563
    ///
564
    /// Two file paths are required for the rename, append and replace filestore request.
565
28
    pub fn new(
566
28
        action_code: FilestoreActionCode,
567
28
        first_name: Lv<'first_name>,
568
28
        second_name: Option<Lv<'second_name>>,
569
28
    ) -> Result<Self, TlvLvError> {
570
28
        let mut base_value_len = first_name.len_full();
571
28
        if fs_request_has_second_filename(action_code) {
572
10
            if second_name.is_none() {
573
                return Err(TlvLvError::SecondNameMissing);
574
10
            }
575
10
            base_value_len += second_name.as_ref().unwrap().len_full();
576
18
        }
577
28
        if base_value_len > u8::MAX as usize {
578
            return Err(TlvLvError::InvalidValueLength(base_value_len));
579
28
        }
580
28
        Ok(Self {
581
28
            base: FilestoreTlvBase {
582
28
                action_code,
583
28
                first_name,
584
28
                second_name,
585
28
            },
586
28
        })
587
28
    }
588

            
589
26
    pub fn action_code(&self) -> FilestoreActionCode {
590
26
        self.base.action_code
591
26
    }
592

            
593
26
    pub fn first_name(&self) -> Lv<'first_name> {
594
26
        self.base.first_name
595
26
    }
596

            
597
36
    pub fn second_name(&self) -> Option<Lv<'second_name>> {
598
36
        self.base.second_name
599
36
    }
600

            
601
124
    pub fn len_value(&self) -> usize {
602
124
        self.base.base_len_value()
603
124
    }
604

            
605
64
    pub fn len_full(&self) -> usize {
606
64
        2 + self.len_value()
607
64
    }
608

            
609
6
    pub fn from_bytes<'longest: 'first_name + 'second_name>(
610
6
        buf: &'longest [u8],
611
6
    ) -> Result<Self, TlvLvError> {
612
6
        if buf.len() < 2 {
613
2
            return Err(ByteConversionError::FromSliceTooSmall {
614
2
                found: buf.len(),
615
2
                expected: 2,
616
2
            }
617
2
            .into());
618
4
        }
619
4
        verify_tlv_type(buf[0], TlvType::FilestoreRequest)?;
620
4
        let len = buf[1] as usize;
621
4
        let mut current_idx = 2;
622
4
        let action_code = FilestoreActionCode::try_from((buf[2] >> 4) & 0b1111)
623
4
            .map_err(|_| TlvLvError::InvalidFilestoreActionCode((buf[2] >> 4) & 0b1111))?;
624
4
        current_idx += 1;
625
4
        let first_name = Lv::from_bytes(&buf[current_idx..])?;
626
4
        let mut second_name = None;
627
4

            
628
4
        current_idx += first_name.len_full();
629
4
        if fs_request_has_second_filename(action_code) {
630
2
            if current_idx >= 2 + len {
631
                return Err(TlvLvError::SecondNameMissing);
632
2
            }
633
2
            second_name = Some(Lv::from_bytes(&buf[current_idx..])?);
634
2
        }
635
4
        Ok(Self {
636
4
            base: FilestoreTlvBase {
637
4
                action_code,
638
4
                first_name,
639
4
                second_name,
640
4
            },
641
4
        })
642
6
    }
643

            
644
    #[cfg(feature = "alloc")]
645
    pub fn to_owned(&self) -> TlvOwned {
646
        // The API should ensure the data field is never too large, so unwrapping here is okay.
647
        TlvOwned::new(TlvType::FilestoreRequest, &self.to_vec()[2..]).unwrap()
648
    }
649
}
650

            
651
impl WritableTlv for FilestoreRequestTlv<'_, '_> {
652
10
    fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
653
10
        if buf.len() < self.len_full() {
654
2
            return Err(ByteConversionError::ToSliceTooSmall {
655
2
                found: buf.len(),
656
2
                expected: self.len_full(),
657
2
            });
658
8
        }
659
8
        buf[0] = TlvType::FilestoreRequest as u8;
660
8
        buf[1] = self.len_value() as u8;
661
8
        buf[2] = (self.base.action_code as u8) << 4;
662
8
        let mut current_idx = 3;
663
8
        // Length checks were already performed.
664
8
        self.base.first_name.write_to_be_bytes_no_len_check(
665
8
            &mut buf[current_idx..current_idx + self.base.first_name.len_full()],
666
8
        );
667
8
        current_idx += self.base.first_name.len_full();
668
8
        if let Some(second_name) = self.base.second_name {
669
4
            second_name.write_to_be_bytes_no_len_check(
670
4
                &mut buf[current_idx..current_idx + second_name.len_full()],
671
4
            );
672
4
            current_idx += second_name.len_full();
673
4
        }
674
8
        Ok(current_idx)
675
10
    }
676

            
677
10
    fn len_written(&self) -> usize {
678
10
        self.len_full()
679
10
    }
680
}
681

            
682
impl GenericTlv for FilestoreRequestTlv<'_, '_> {
683
10
    fn tlv_type_field(&self) -> TlvTypeField {
684
10
        TlvTypeField::Standard(TlvType::FilestoreRequest)
685
10
    }
686
}
687

            
688
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
689
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
690
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
691
pub struct FilestoreResponseTlv<'first_name, 'second_name, 'fs_msg> {
692
    #[cfg_attr(feature = "serde", serde(borrow))]
693
    base: FilestoreTlvBase<'first_name, 'second_name>,
694
    status_code: u8,
695
    #[cfg_attr(feature = "serde", serde(borrow))]
696
    filestore_message: Lv<'fs_msg>,
697
}
698

            
699
impl<'first_name, 'second_name, 'fs_msg> FilestoreResponseTlv<'first_name, 'second_name, 'fs_msg> {
700
    /// This function will return [None] if the respective action code requires two names but
701
    /// only one is passed. It will also returns [None] if the cumulative length of the first
702
    /// name and the second name exceeds 255 bytes.
703
    ///
704
    /// Two file paths are required for the rename, append and replace filestore request.
705
16
    pub fn new_no_filestore_message(
706
16
        action_code: FilestoreActionCode,
707
16
        status_code: u8,
708
16
        first_name: Lv<'first_name>,
709
16
        second_name: Option<Lv<'second_name>>,
710
16
    ) -> Result<Self, TlvLvError> {
711
16
        Self::new(
712
16
            action_code,
713
16
            status_code,
714
16
            first_name,
715
16
            second_name,
716
16
            Lv::new_empty(),
717
16
        )
718
16
    }
719
16
    pub fn new(
720
16
        action_code: FilestoreActionCode,
721
16
        status_code: u8,
722
16
        first_name: Lv<'first_name>,
723
16
        second_name: Option<Lv<'second_name>>,
724
16
        filestore_message: Lv<'fs_msg>,
725
16
    ) -> Result<Self, TlvLvError> {
726
16
        let mut base_value_len = first_name.len_full();
727
16
        if Self::has_second_filename(action_code) {
728
2
            if second_name.is_none() {
729
                return Err(TlvLvError::SecondNameMissing);
730
2
            }
731
2
            base_value_len += second_name.as_ref().unwrap().len_full();
732
14
        }
733
16
        if base_value_len > u8::MAX as usize {
734
            return Err(TlvLvError::InvalidValueLength(base_value_len));
735
16
        }
736
16
        Ok(Self {
737
16
            base: FilestoreTlvBase {
738
16
                action_code,
739
16
                first_name,
740
16
                second_name,
741
16
            },
742
16
            status_code,
743
16
            filestore_message,
744
16
        })
745
16
    }
746

            
747
26
    pub fn has_second_filename(action_code: FilestoreActionCode) -> bool {
748
26
        if action_code == FilestoreActionCode::RenameFile
749
24
            || action_code == FilestoreActionCode::AppendFile
750
24
            || action_code == FilestoreActionCode::ReplaceFile
751
        {
752
2
            return true;
753
24
        }
754
24
        false
755
26
    }
756

            
757
4
    pub fn action_code(&self) -> FilestoreActionCode {
758
4
        self.base.action_code
759
4
    }
760

            
761
4
    pub fn status_code(&self) -> u8 {
762
4
        self.status_code
763
4
    }
764

            
765
4
    pub fn first_name(&self) -> Lv<'first_name> {
766
4
        self.base.first_name
767
4
    }
768

            
769
6
    pub fn second_name(&self) -> Option<Lv<'second_name>> {
770
6
        self.base.second_name
771
6
    }
772

            
773
58
    pub fn len_value(&self) -> usize {
774
58
        self.base.base_len_value() + self.filestore_message.len_full()
775
58
    }
776

            
777
46
    pub fn len_full(&self) -> usize {
778
46
        2 + self.len_value()
779
46
    }
780

            
781
10
    pub fn from_bytes<'buf: 'first_name + 'second_name + 'fs_msg>(
782
10
        buf: &'buf [u8],
783
10
    ) -> Result<Self, TlvLvError> {
784
10
        if buf.len() < 2 {
785
            return Err(ByteConversionError::FromSliceTooSmall {
786
                found: buf.len(),
787
                expected: 2,
788
            }
789
            .into());
790
10
        }
791
10
        verify_tlv_type(buf[0], TlvType::FilestoreResponse)?;
792
10
        let len = buf[1] as usize;
793
10
        let mut current_idx = 2;
794
35
        let len_check = |current_idx: &mut usize, add_len: usize| -> Result<(), TlvLvError> {
795
30
            if *current_idx + add_len > buf.len() {
796
                return Err(ByteConversionError::FromSliceTooSmall {
797
                    found: buf.len(),
798
                    expected: *current_idx,
799
                }
800
                .into());
801
30
            }
802
30
            Ok(())
803
30
        };
804
10
        len_check(&mut current_idx, len)?;
805
10
        let action_code = FilestoreActionCode::try_from((buf[2] >> 4) & 0b1111)
806
10
            .map_err(|_| TlvLvError::InvalidFilestoreActionCode((buf[2] >> 4) & 0b1111))?;
807
10
        let status_code = buf[2] & 0b1111;
808
10
        current_idx += 1;
809
10
        let first_name = Lv::from_bytes(&buf[current_idx..])?;
810
10
        len_check(&mut current_idx, first_name.len_full())?;
811
10
        current_idx += first_name.len_full();
812
10

            
813
10
        let mut second_name = None;
814
10
        if Self::has_second_filename(action_code) {
815
            if current_idx >= 2 + len {
816
                return Err(TlvLvError::SecondNameMissing);
817
            }
818
            let second_name_lv = Lv::from_bytes(&buf[current_idx..])?;
819
            current_idx += second_name_lv.len_full();
820
            second_name = Some(second_name_lv);
821
10
        }
822
10
        let filestore_message = Lv::from_bytes(&buf[current_idx..])?;
823
10
        len_check(&mut current_idx, filestore_message.len_full())?;
824
10
        Ok(Self {
825
10
            base: FilestoreTlvBase {
826
10
                action_code,
827
10
                first_name,
828
10
                second_name,
829
10
            },
830
10
            status_code,
831
10
            filestore_message,
832
10
        })
833
10
    }
834

            
835
    #[cfg(feature = "alloc")]
836
    pub fn to_owned(&self) -> TlvOwned {
837
        // The API should ensure the data field is never too large, so unwrap is okay here.
838
        TlvOwned::new(TlvType::FilestoreResponse, &self.to_vec()[2..]).unwrap()
839
    }
840
}
841

            
842
impl WritableTlv for FilestoreResponseTlv<'_, '_, '_> {
843
12
    fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
844
12
        if buf.len() < self.len_full() {
845
            return Err(ByteConversionError::ToSliceTooSmall {
846
                found: buf.len(),
847
                expected: self.len_full(),
848
            });
849
12
        }
850
12
        buf[0] = TlvType::FilestoreResponse as u8;
851
12
        buf[1] = self.len_value() as u8;
852
12
        buf[2] = ((self.base.action_code as u8) << 4) | (self.status_code & 0b1111);
853
12
        let mut current_idx = 3;
854
12
        // Length checks were already performed.
855
12
        self.base.first_name.write_to_be_bytes_no_len_check(
856
12
            &mut buf[current_idx..current_idx + self.base.first_name.len_full()],
857
12
        );
858
12
        current_idx += self.base.first_name.len_full();
859
12
        if let Some(second_name) = self.base.second_name {
860
            current_idx += second_name.write_to_be_bytes_no_len_check(
861
                &mut buf[current_idx..current_idx + second_name.len_full()],
862
            );
863
12
        }
864
12
        current_idx += self.filestore_message.write_to_be_bytes_no_len_check(
865
12
            &mut buf[current_idx..current_idx + self.filestore_message.len_full()],
866
12
        );
867
12
        Ok(current_idx)
868
12
    }
869

            
870
    fn len_written(&self) -> usize {
871
        self.len_full()
872
    }
873
}
874

            
875
impl GenericTlv for FilestoreResponseTlv<'_, '_, '_> {
876
    fn tlv_type_field(&self) -> TlvTypeField {
877
        TlvTypeField::Standard(TlvType::FilestoreResponse)
878
    }
879
}
880

            
881
26
pub(crate) fn verify_tlv_type(raw_type: u8, expected_tlv_type: TlvType) -> Result<(), TlvLvError> {
882
26
    let tlv_type = TlvType::try_from(raw_type).map_err(|_| TlvLvError::InvalidTlvTypeField {
883
        found: raw_type,
884
        expected: Some(expected_tlv_type.into()),
885
26
    })?;
886
26
    if tlv_type != expected_tlv_type {
887
        return Err(TlvLvError::InvalidTlvTypeField {
888
            found: tlv_type as u8,
889
            expected: Some(expected_tlv_type as u8),
890
        });
891
26
    }
892
26
    Ok(())
893
26
}
894

            
895
#[cfg(test)]
896
mod tests {
897
    use super::*;
898
    use crate::cfdp::lv::Lv;
899
    use crate::cfdp::tlv::{FilestoreActionCode, FilestoreRequestTlv, Tlv, TlvType, TlvTypeField};
900
    use crate::cfdp::TlvLvError;
901
    use crate::util::{UbfU16, UbfU8, UnsignedEnum};
902
    use alloc::string::ToString;
903

            
904
    const TLV_TEST_STR_0: &str = "hello.txt";
905
    const TLV_TEST_STR_1: &str = "hello2.txt";
906

            
907
    #[test]
908
2
    fn test_basic() {
909
2
        let entity_id = UbfU8::new(5);
910
2
        let mut buf: [u8; 4] = [0; 4];
911
2
        assert!(entity_id.write_to_be_bytes(&mut buf).is_ok());
912
2
        let tlv_res = Tlv::new(TlvType::EntityId, &buf[0..1]);
913
2
        assert!(tlv_res.is_ok());
914
2
        let tlv_res = tlv_res.unwrap();
915
2
        assert_eq!(
916
2
            tlv_res.tlv_type_field(),
917
2
            TlvTypeField::Standard(TlvType::EntityId)
918
2
        );
919
2
        assert_eq!(tlv_res.len_full(), 3);
920
2
        assert_eq!(tlv_res.value().len(), 1);
921
2
        assert_eq!(tlv_res.len_value(), 1);
922
2
        assert!(!tlv_res.is_empty());
923
2
        assert_eq!(tlv_res.value()[0], 5);
924
2
    }
925

            
926
    #[test]
927
2
    fn test_serialization() {
928
2
        let entity_id = UbfU8::new(5);
929
2
        let mut buf: [u8; 4] = [0; 4];
930
2
        assert!(entity_id.write_to_be_bytes(&mut buf).is_ok());
931
2
        let tlv_res = Tlv::new(TlvType::EntityId, &buf[0..1]);
932
2
        assert!(tlv_res.is_ok());
933
2
        let tlv_res = tlv_res.unwrap();
934
2
        let mut ser_buf: [u8; 4] = [0; 4];
935
2
        assert!(tlv_res.write_to_bytes(&mut ser_buf).is_ok());
936
2
        assert_eq!(ser_buf[0], TlvType::EntityId as u8);
937
2
        assert_eq!(ser_buf[1], 1);
938
2
        assert_eq!(ser_buf[2], 5);
939
2
    }
940

            
941
    #[test]
942
2
    fn test_deserialization() {
943
2
        let entity_id = UbfU8::new(5);
944
2
        let mut buf: [u8; 4] = [0; 4];
945
2
        assert!(entity_id.write_to_be_bytes(&mut buf[2..]).is_ok());
946
2
        buf[0] = TlvType::EntityId as u8;
947
2
        buf[1] = 1;
948
2
        let tlv_from_raw = Tlv::from_bytes(&buf);
949
2
        assert!(tlv_from_raw.is_ok());
950
2
        let tlv_from_raw = tlv_from_raw.unwrap();
951
2
        assert!(tlv_from_raw.raw_data().is_some());
952
2
        assert_eq!(tlv_from_raw.raw_data().unwrap(), buf);
953
2
        assert_eq!(
954
2
            tlv_from_raw.tlv_type_field(),
955
2
            TlvTypeField::Standard(TlvType::EntityId)
956
2
        );
957
2
        assert_eq!(tlv_from_raw.value().len(), 1);
958
2
        assert_eq!(tlv_from_raw.len_full(), 3);
959
2
        assert_eq!(tlv_from_raw.value()[0], 5);
960
2
    }
961

            
962
    #[test]
963
2
    fn test_entity_id_tlv() {
964
2
        let entity_id = UbfU16::new(0x0102);
965
2
        let entity_id_tlv = EntityIdTlv::new(entity_id.into());
966
2
        let mut buf: [u8; 16] = [0; 16];
967
2
        let written_len = entity_id_tlv.write_to_bytes(&mut buf).unwrap();
968
2
        assert_eq!(written_len, entity_id_tlv.len_full());
969
2
        assert_eq!(entity_id_tlv.len_value(), 2);
970
2
        assert!(entity_id_tlv.is_standard_tlv());
971
2
        assert_eq!(entity_id_tlv.tlv_type().unwrap(), TlvType::EntityId);
972
2
        assert_eq!(buf[0], TlvType::EntityId as u8);
973
2
        assert_eq!(buf[1], 2);
974
2
        assert_eq!(u16::from_be_bytes(buf[2..4].try_into().unwrap()), 0x0102);
975
2
        let entity_id_as_vec = entity_id_tlv.to_vec();
976
2
        assert_eq!(entity_id_as_vec, buf[0..written_len].to_vec());
977
2
    }
978

            
979
    #[test]
980
2
    fn test_entity_id_from_generic_tlv() {
981
2
        let entity_id = UbfU16::new(0x0102);
982
2
        let entity_id_tlv = EntityIdTlv::new(entity_id.into());
983
2
        let mut buf: [u8; 16] = [0; 16];
984
2
        let entity_id_as_tlv: Tlv = entity_id_tlv.to_tlv(&mut buf).unwrap();
985
2
        let entity_id_converted_back: EntityIdTlv = entity_id_as_tlv.try_into().unwrap();
986
2
        assert_eq!(entity_id_converted_back, entity_id_tlv);
987
2
    }
988

            
989
    #[test]
990
2
    fn test_entity_id_from_raw() {
991
2
        let entity_id = UbfU16::new(0x0102);
992
2
        let entity_id_tlv = EntityIdTlv::new(entity_id.into());
993
2
        let mut buf: [u8; 16] = [0; 16];
994
2
        let _ = entity_id_tlv.write_to_bytes(&mut buf).unwrap();
995
2
        let entity_tlv_from_raw =
996
2
            EntityIdTlv::from_bytes(&buf).expect("creating entity ID TLV failed");
997
2
        assert_eq!(entity_tlv_from_raw, entity_id_tlv);
998
2
        assert_eq!(entity_tlv_from_raw.entity_id(), &entity_id.into());
999
2
    }
    #[test]
2
    fn test_empty() {
2
        let tlv_empty = Tlv::new_empty(TlvType::MsgToUser);
2
        assert_eq!(tlv_empty.value().len(), 0);
2
        assert!(tlv_empty.is_empty());
2
        assert_eq!(tlv_empty.len_full(), 2);
2
        assert!(tlv_empty.value().is_empty());
2
        assert_eq!(
2
            tlv_empty.tlv_type_field(),
2
            TlvTypeField::Standard(TlvType::MsgToUser)
2
        );
2
    }
    #[test]
2
    fn test_empty_serialization() {
2
        let tlv_empty = Tlv::new_empty(TlvType::MsgToUser);
2
        let mut buf: [u8; 4] = [0; 4];
2
        assert!(tlv_empty.write_to_bytes(&mut buf).is_ok());
2
        assert_eq!(buf[0], TlvType::MsgToUser as u8);
2
        assert_eq!(buf[1], 0);
2
    }
    #[test]
2
    fn test_empty_deserialization() {
2
        let mut buf: [u8; 4] = [0; 4];
2
        buf[0] = TlvType::MsgToUser as u8;
2
        buf[1] = 0;
2
        let tlv_empty = Tlv::from_bytes(&buf);
2
        assert!(tlv_empty.is_ok());
2
        let tlv_empty = tlv_empty.unwrap();
2
        assert!(tlv_empty.is_empty());
2
        assert_eq!(tlv_empty.value().len(), 0);
2
        assert_eq!(
2
            tlv_empty.tlv_type_field(),
2
            TlvTypeField::Standard(TlvType::MsgToUser)
2
        );
2
        assert_eq!(tlv_empty.len_full(), 2);
2
        assert!(tlv_empty.value().is_empty());
2
    }
    #[test]
2
    fn test_write_buf_too_small() {
2
        let mut buf: [u8; 2] = [0; 2];
2
        let fs_request =
2
            FilestoreRequestTlv::new_create_file(Lv::new_from_str(TLV_TEST_STR_0).unwrap())
2
                .unwrap();
2
        let error = fs_request.write_to_bytes(&mut buf);
2
        assert!(error.is_err());
2
        let error = error.unwrap_err();
2
        if let ByteConversionError::ToSliceTooSmall { found, expected } = error {
2
            assert_eq!(found, 2);
2
            assert_eq!(expected, 13);
        } else {
            panic!("unexpected error {:?}", error);
        }
2
    }
    #[test]
2
    fn test_read_from_buf_too_small() {
2
        let buf: [u8; 1] = [0; 1];
2
        let error = FilestoreRequestTlv::from_bytes(&buf);
2
        assert!(error.is_err());
2
        let error = error.unwrap_err();
        if let TlvLvError::ByteConversion(ByteConversionError::FromSliceTooSmall {
2
            found,
2
            expected,
2
        }) = error
        {
2
            assert_eq!(found, 1);
2
            assert_eq!(expected, 2);
        } else {
            panic!("unexpected error {:?}", error);
        }
2
    }
    #[test]
2
    fn test_buf_too_large() {
2
        let buf_too_large: [u8; u8::MAX as usize + 1] = [0; u8::MAX as usize + 1];
2
        let tlv_res = Tlv::new(TlvType::MsgToUser, &buf_too_large);
2
        assert!(tlv_res.is_err());
2
        let error = tlv_res.unwrap_err();
2
        assert_eq!(error.0, u8::MAX as usize + 1);
2
        assert_eq!(
2
            error.to_string(),
2
            "data with size 256 larger than allowed 255 bytes"
2
        );
2
    }
    #[test]
2
    fn test_deserialization_custom_tlv_type() {
2
        let mut buf: [u8; 4] = [0; 4];
2
        buf[0] = 3;
2
        buf[1] = 1;
2
        buf[2] = 5;
2
        let tlv = Tlv::from_bytes(&buf);
2
        assert!(tlv.is_ok());
2
        let tlv = tlv.unwrap();
2
        assert_eq!(tlv.tlv_type_field(), TlvTypeField::Custom(3));
2
        assert!(!tlv.is_standard_tlv());
2
        assert_eq!(tlv.value().len(), 1);
2
        assert_eq!(tlv.len_full(), 3);
2
    }
16
    fn generic_fs_request_test_one_file(
16
        action_code: FilestoreActionCode,
16
    ) -> FilestoreRequestTlv<'static, 'static> {
16
        assert!(!fs_request_has_second_filename(action_code));
16
        let first_name = Lv::new_from_str(TLV_TEST_STR_0).unwrap();
16
        let fs_request = match action_code {
6
            FilestoreActionCode::CreateFile => FilestoreRequestTlv::new_create_file(first_name),
2
            FilestoreActionCode::DeleteFile => FilestoreRequestTlv::new_delete_file(first_name),
            FilestoreActionCode::CreateDirectory => {
2
                FilestoreRequestTlv::new_create_directory(first_name)
            }
            FilestoreActionCode::RemoveDirectory => {
2
                FilestoreRequestTlv::new_remove_directory(first_name)
            }
2
            FilestoreActionCode::DenyFile => FilestoreRequestTlv::new_deny_file(first_name),
            FilestoreActionCode::DenyDirectory => {
2
                FilestoreRequestTlv::new_deny_directory(first_name)
            }
            _ => panic!("invalid action code"),
        };
16
        assert!(fs_request.is_ok());
16
        let fs_request = fs_request.unwrap();
16
        assert_eq!(fs_request.len_value(), 1 + first_name.len_full());
16
        assert_eq!(fs_request.len_full(), fs_request.len_value() + 2);
16
        assert_eq!(fs_request.action_code(), action_code);
16
        assert_eq!(fs_request.first_name(), first_name);
16
        assert_eq!(fs_request.second_name(), None);
16
        fs_request
16
    }
10
    fn generic_fs_request_test_two_files(
10
        action_code: FilestoreActionCode,
10
    ) -> FilestoreRequestTlv<'static, 'static> {
10
        assert!(fs_request_has_second_filename(action_code));
10
        let first_name = Lv::new_from_str(TLV_TEST_STR_0).unwrap();
10
        let second_name = Lv::new_from_str(TLV_TEST_STR_1).unwrap();
10
        let fs_request = match action_code {
            FilestoreActionCode::ReplaceFile => {
2
                FilestoreRequestTlv::new_replace_file(first_name, second_name)
            }
            FilestoreActionCode::AppendFile => {
2
                FilestoreRequestTlv::new_append_file(first_name, second_name)
            }
            FilestoreActionCode::RenameFile => {
6
                FilestoreRequestTlv::new_rename_file(first_name, second_name)
            }
            _ => panic!("invalid action code"),
        };
10
        assert!(fs_request.is_ok());
10
        let fs_request = fs_request.unwrap();
10
        assert_eq!(
10
            fs_request.len_value(),
10
            1 + first_name.len_full() + second_name.len_full()
10
        );
10
        assert_eq!(
10
            fs_request.tlv_type_field(),
10
            TlvTypeField::Standard(TlvType::FilestoreRequest)
10
        );
10
        assert_eq!(fs_request.len_full(), fs_request.len_value() + 2);
10
        assert_eq!(fs_request.len_written(), fs_request.len_full());
10
        assert_eq!(fs_request.action_code(), action_code);
10
        assert_eq!(fs_request.first_name(), first_name);
10
        assert!(fs_request.second_name().is_some());
10
        assert_eq!(fs_request.second_name().unwrap(), second_name);
10
        fs_request
10
    }
    #[test]
2
    fn test_fs_request_basic_create_file() {
2
        generic_fs_request_test_one_file(FilestoreActionCode::CreateFile);
2
    }
    #[test]
2
    fn test_fs_request_basic_delete() {
2
        generic_fs_request_test_one_file(FilestoreActionCode::DeleteFile);
2
    }
    #[test]
2
    fn test_fs_request_basic_create_dir() {
2
        generic_fs_request_test_one_file(FilestoreActionCode::CreateDirectory);
2
    }
    #[test]
2
    fn test_fs_request_basic_remove_dir() {
2
        generic_fs_request_test_one_file(FilestoreActionCode::RemoveDirectory);
2
    }
    #[test]
2
    fn test_fs_request_basic_deny_file() {
2
        generic_fs_request_test_one_file(FilestoreActionCode::DenyFile);
2
    }
    #[test]
2
    fn test_fs_request_basic_deny_dir() {
2
        generic_fs_request_test_one_file(FilestoreActionCode::DenyDirectory);
2
    }
    #[test]
2
    fn test_fs_request_basic_append_file() {
2
        generic_fs_request_test_two_files(FilestoreActionCode::AppendFile);
2
    }
    #[test]
2
    fn test_fs_request_basic_rename_file() {
2
        generic_fs_request_test_two_files(FilestoreActionCode::RenameFile);
2
    }
    #[test]
2
    fn test_fs_request_basic_replace_file() {
2
        generic_fs_request_test_two_files(FilestoreActionCode::ReplaceFile);
2
    }
4
    fn check_fs_request_first_part(
4
        buf: &[u8],
4
        action_code: FilestoreActionCode,
4
        expected_val_len: u8,
4
    ) -> usize {
4
        assert_eq!(buf[0], TlvType::FilestoreRequest as u8);
4
        assert_eq!(buf[1], expected_val_len);
4
        assert_eq!((buf[2] >> 4) & 0b1111, action_code as u8);
4
        let lv = Lv::from_bytes(&buf[3..]);
4
        assert!(lv.is_ok());
4
        let lv = lv.unwrap();
4
        assert_eq!(lv.value_as_str().unwrap().unwrap(), TLV_TEST_STR_0);
4
        3 + lv.len_full()
4
    }
    #[test]
2
    fn test_fs_request_serialization_one_file() {
2
        let req = generic_fs_request_test_one_file(FilestoreActionCode::CreateFile);
2
        let mut buf: [u8; 64] = [0; 64];
2
        let res = req.write_to_bytes(&mut buf);
2
        assert!(res.is_ok());
2
        let written = res.unwrap();
2
        assert_eq!(written, 3 + 1 + TLV_TEST_STR_0.len());
2
        assert_eq!(written, req.len_full());
2
        check_fs_request_first_part(
2
            &buf,
2
            FilestoreActionCode::CreateFile,
2
            1 + 1 + TLV_TEST_STR_0.len() as u8,
2
        );
2
    }
    #[test]
2
    fn test_fs_request_deserialization_one_file() {
2
        let req = generic_fs_request_test_one_file(FilestoreActionCode::CreateFile);
2
        let mut buf: [u8; 64] = [0; 64];
2
        let res = req.write_to_bytes(&mut buf);
2
        assert!(res.is_ok());
2
        let req_conv_back = FilestoreRequestTlv::from_bytes(&buf);
2
        assert!(req_conv_back.is_ok());
2
        let req_conv_back = req_conv_back.unwrap();
2
        assert_eq!(req_conv_back, req);
2
    }
    #[test]
2
    fn test_fs_request_serialization_two_files() {
2
        let req = generic_fs_request_test_two_files(FilestoreActionCode::RenameFile);
2
        let mut buf: [u8; 64] = [0; 64];
2
        let res = req.write_to_bytes(&mut buf);
2
        assert!(res.is_ok());
2
        let written = res.unwrap();
2
        assert_eq!(written, req.len_full());
2
        assert_eq!(
2
            written,
2
            3 + 1 + TLV_TEST_STR_0.len() + 1 + TLV_TEST_STR_1.len()
2
        );
2
        let current_idx = check_fs_request_first_part(
2
            &buf,
2
            FilestoreActionCode::RenameFile,
2
            1 + 1 + TLV_TEST_STR_0.len() as u8 + 1 + TLV_TEST_STR_1.len() as u8,
2
        );
2
        let second_lv = Lv::from_bytes(&buf[current_idx..]);
2
        assert!(second_lv.is_ok());
2
        let second_lv = second_lv.unwrap();
2
        assert_eq!(second_lv.value_as_str().unwrap().unwrap(), TLV_TEST_STR_1);
2
        assert_eq!(current_idx + second_lv.len_full(), req.len_full());
2
    }
    #[test]
2
    fn test_fs_request_deserialization_two_files() {
2
        let req = generic_fs_request_test_two_files(FilestoreActionCode::RenameFile);
2
        let mut buf: [u8; 64] = [0; 64];
2
        req.write_to_bytes(&mut buf).unwrap();
2
        let req_conv_back = FilestoreRequestTlv::from_bytes(&buf);
2
        assert!(req_conv_back.is_ok());
2
        let req_conv_back = req_conv_back.unwrap();
2
        assert_eq!(req_conv_back, req);
2
    }
    #[test]
2
    fn test_fs_response_state_one_path() {
2
        let lv_0 = Lv::new_from_str(TLV_TEST_STR_0).unwrap();
2
        let response = FilestoreResponseTlv::new_no_filestore_message(
2
            FilestoreActionCode::CreateFile,
2
            0b0001,
2
            lv_0,
2
            None,
2
        )
2
        .expect("creating response failed");
2
        assert_eq!(response.status_code(), 0b0001);
2
        assert_eq!(response.action_code(), FilestoreActionCode::CreateFile);
2
        assert_eq!(response.first_name(), lv_0);
2
        assert!(response.second_name().is_none());
2
    }
    #[test]
2
    fn test_fs_response_state_two_paths() {
2
        let lv_0 = Lv::new_from_str(TLV_TEST_STR_0).unwrap();
2
        let lv_1 = Lv::new_from_str(TLV_TEST_STR_1).unwrap();
2
        let response = FilestoreResponseTlv::new_no_filestore_message(
2
            FilestoreActionCode::RenameFile,
2
            0b0001,
2
            lv_0,
2
            Some(lv_1),
2
        )
2
        .expect("creating response failed");
2
        assert_eq!(response.status_code(), 0b0001);
2
        assert_eq!(response.action_code(), FilestoreActionCode::RenameFile);
2
        assert_eq!(response.first_name(), lv_0);
2
        assert!(response.second_name().is_some());
2
        assert!(response.second_name().unwrap() == lv_1);
2
        assert_eq!(
2
            response.len_full(),
2
            2 + 1 + lv_0.len_full() + lv_1.len_full() + 1
2
        );
2
    }
    #[test]
2
    fn test_fs_response_serialization() {
2
        let lv_0 = Lv::new_from_str(TLV_TEST_STR_0).unwrap();
2
        let response = FilestoreResponseTlv::new_no_filestore_message(
2
            FilestoreActionCode::CreateFile,
2
            0b0001,
2
            lv_0,
2
            None,
2
        )
2
        .expect("creating response failed");
2
        let mut buf: [u8; 32] = [0; 32];
2
        let written_len = response.write_to_bytes(&mut buf).unwrap();
2
        assert_eq!(written_len, 2 + 1 + lv_0.len_full() + 1);
2
        assert_eq!(buf[0], TlvType::FilestoreResponse as u8);
2
        assert_eq!(buf[1], written_len as u8 - 2);
2
        assert_eq!(
2
            (buf[2] >> 4) & 0b1111,
2
            FilestoreActionCode::CreateFile as u8
2
        );
2
        assert_eq!(buf[2] & 0b1111, 0b0001);
2
        let lv_read_back = Lv::from_bytes(&buf[3..]).unwrap();
2
        assert_eq!(lv_0, lv_read_back);
2
        let current_idx = 3 + lv_0.len_full();
2
        let fs_msg_empty = Lv::from_bytes(&buf[current_idx..]).unwrap();
2
        assert!(fs_msg_empty.is_empty());
2
    }
    #[test]
2
    fn test_fs_response_deserialization() {
2
        let lv_0 = Lv::new_from_str(TLV_TEST_STR_0).unwrap();
2
        let response = FilestoreResponseTlv::new_no_filestore_message(
2
            FilestoreActionCode::CreateFile,
2
            0b0001,
2
            lv_0,
2
            None,
2
        )
2
        .expect("creating response failed");
2
        let mut buf: [u8; 32] = [0; 32];
2
        response.write_to_bytes(&mut buf).unwrap();
2
        let response_read_back = FilestoreResponseTlv::from_bytes(&buf).unwrap();
2
        assert_eq!(response_read_back, response);
2
    }
    #[test]
2
    fn test_entity_it_tlv_to_tlv() {
2
        let entity_id = UbfU16::new(0x0102);
2
        let entity_id_tlv = EntityIdTlv::new(entity_id.into());
2
        let mut binding = [0; 16];
2
        let tlv = entity_id_tlv.to_tlv(&mut binding).unwrap();
2
        assert_eq!(
2
            tlv.tlv_type_field(),
2
            TlvTypeField::Standard(TlvType::EntityId)
2
        );
2
        assert_eq!(tlv.len_full(), 4);
2
        assert_eq!(tlv.len_value(), 2);
2
        assert_eq!(tlv.value(), &[0x01, 0x02]);
2
    }
    #[test]
2
    fn test_invalid_tlv_conversion() {
2
        let msg_to_user_tlv = Tlv::new_empty(TlvType::MsgToUser);
2
        let error = EntityIdTlv::try_from(msg_to_user_tlv);
2
        assert!(error.is_err());
2
        let error = error.unwrap_err();
2
        if let TlvLvError::InvalidTlvTypeField { found, expected } = error {
2
            assert_eq!(found, TlvType::MsgToUser as u8);
2
            assert_eq!(expected, Some(TlvType::EntityId as u8));
2
            assert_eq!(
2
                error.to_string(),
2
                "invalid TLV type field, found 2, expected Some(6)"
2
            );
        } else {
            panic!("unexpected error");
        }
2
    }
    #[test]
2
    fn test_entity_id_invalid_value_len() {
2
        let entity_id = UbfU16::new(0x0102);
2
        let entity_id_tlv = EntityIdTlv::new(entity_id.into());
2
        let mut buf: [u8; 32] = [0; 32];
2
        entity_id_tlv.write_to_bytes(&mut buf).unwrap();
2
        buf[1] = 12;
2
        let error = EntityIdTlv::from_bytes(&buf);
2
        assert!(error.is_err());
2
        let error = error.unwrap_err();
2
        if let TlvLvError::InvalidValueLength(len) = error {
2
            assert_eq!(len, 12);
2
            assert_eq!(error.to_string(), "invalid value length 12");
        } else {
            panic!("unexpected error");
        }
2
    }
    #[test]
2
    fn test_custom_tlv() {
2
        let custom_tlv = Tlv::new_with_custom_type(20, &[]).unwrap();
2
        assert!(custom_tlv.tlv_type().is_none());
2
        if let TlvTypeField::Custom(val) = custom_tlv.tlv_type_field() {
2
            assert_eq!(val, 20);
        } else {
            panic!("unexpected type field");
        }
2
        let tlv_as_vec = custom_tlv.to_vec();
2
        assert_eq!(tlv_as_vec.len(), 2);
2
        assert_eq!(tlv_as_vec[0], 20);
2
        assert_eq!(tlv_as_vec[1], 0);
2
    }
    #[test]
2
    fn test_tlv_to_owned() {
2
        let entity_id = UbfU8::new(5);
2
        let mut buf: [u8; 4] = [0; 4];
2
        assert!(entity_id.write_to_be_bytes(&mut buf).is_ok());
2
        let tlv_res = Tlv::new(TlvType::EntityId, &buf[0..1]);
2
        assert!(tlv_res.is_ok());
2
        let tlv_res = tlv_res.unwrap();
2
        let tlv_owned = tlv_res.to_owned();
2
        assert_eq!(tlv_res, tlv_owned);
2
        let tlv_owned_from_conversion: TlvOwned = tlv_res.into();
2
        assert_eq!(tlv_owned_from_conversion, tlv_owned);
2
        assert_eq!(tlv_owned_from_conversion, tlv_res);
2
    }
    #[test]
2
    fn test_owned_tlv() {
2
        let entity_id = UbfU8::new(5);
2
        let mut buf: [u8; 4] = [0; 4];
2
        assert!(entity_id.write_to_be_bytes(&mut buf).is_ok());
2
        let tlv_res = TlvOwned::new(TlvType::EntityId, &buf[0..1]).expect("creating TLV failed");
2
        assert_eq!(
2
            tlv_res.tlv_type_field(),
2
            TlvTypeField::Standard(TlvType::EntityId)
2
        );
2
        assert_eq!(tlv_res.len_full(), 3);
2
        assert_eq!(tlv_res.value().len(), 1);
2
        assert_eq!(tlv_res.len_value(), 1);
2
        assert!(!tlv_res.is_empty());
2
        assert_eq!(tlv_res.value()[0], 5);
2
    }
    #[test]
2
    fn test_owned_tlv_empty() {
2
        let tlv_res = TlvOwned::new_empty(TlvType::FlowLabel);
2
        assert_eq!(
2
            tlv_res.tlv_type_field(),
2
            TlvTypeField::Standard(TlvType::FlowLabel)
2
        );
2
        assert_eq!(tlv_res.len_full(), 2);
2
        assert_eq!(tlv_res.value().len(), 0);
2
        assert_eq!(tlv_res.len_value(), 0);
2
        assert!(tlv_res.is_empty());
2
    }
    #[test]
2
    fn test_owned_tlv_custom_type() {
2
        let tlv_res = TlvOwned::new_with_custom_type(32, &[]).unwrap();
2
        assert_eq!(tlv_res.tlv_type_field(), TlvTypeField::Custom(32));
2
        assert_eq!(tlv_res.len_full(), 2);
2
        assert_eq!(tlv_res.value().len(), 0);
2
        assert_eq!(tlv_res.len_value(), 0);
2
        assert!(tlv_res.is_empty());
2
    }
    #[test]
2
    fn test_owned_tlv_conversion_to_bytes() {
2
        let entity_id = UbfU8::new(5);
2
        let mut buf: [u8; 4] = [0; 4];
2
        assert!(entity_id.write_to_be_bytes(&mut buf).is_ok());
2
        let tlv_res = Tlv::new(TlvType::EntityId, &buf[0..1]);
2
        assert!(tlv_res.is_ok());
2
        let tlv_res = tlv_res.unwrap();
2
        let tlv_owned_from_conversion: TlvOwned = tlv_res.into();
2
        assert_eq!(tlv_res.to_vec(), tlv_owned_from_conversion.to_vec());
2
    }
}