Skip to main content

copybook_rdw/
record.rs

1use crate::{RDW_HEADER_LEN, RdwHeader};
2use copybook_error::Result;
3
4/// An RDW record with header and payload bytes.
5#[derive(Debug, Clone)]
6pub struct RDWRecord {
7    /// 4-byte RDW header (length + reserved).
8    pub header: [u8; RDW_HEADER_LEN],
9    /// Record payload bytes.
10    pub payload: Vec<u8>,
11}
12
13impl RDWRecord {
14    /// Create a new RDW record from payload (fallible constructor).
15    ///
16    /// Constructs an [`RDWRecord`] with a computed header (payload length + zero reserved bytes).
17    ///
18    /// # Examples
19    ///
20    /// ```
21    /// use copybook_rdw::RDWRecord;
22    ///
23    /// let record = RDWRecord::try_new(vec![0xC8; 80]).unwrap();
24    /// assert_eq!(record.length(), 80);
25    /// assert_eq!(record.payload.len(), 80);
26    /// ```
27    ///
28    /// # Errors
29    /// Returns an error when payload length exceeds `u16::MAX`.
30    #[inline]
31    #[must_use = "Handle the Result or propagate the error"]
32    pub fn try_new(payload: Vec<u8>) -> Result<Self> {
33        let header = RdwHeader::from_payload_len(payload.len(), 0)?.bytes();
34        Ok(Self { header, payload })
35    }
36
37    /// Create an RDW record preserving reserved bytes (fallible constructor).
38    ///
39    /// # Errors
40    /// Returns an error when payload length exceeds `u16::MAX`.
41    #[inline]
42    #[must_use = "Handle the Result or propagate the error"]
43    pub fn try_with_reserved(payload: Vec<u8>, reserved: u16) -> Result<Self> {
44        let header = RdwHeader::from_payload_len(payload.len(), reserved)?.bytes();
45        Ok(Self { header, payload })
46    }
47
48    /// Get payload length from header.
49    #[inline]
50    #[must_use]
51    pub fn length(&self) -> u16 {
52        RdwHeader::from_bytes(self.header).length()
53    }
54
55    /// Get reserved bytes from header.
56    #[inline]
57    #[must_use]
58    pub fn reserved(&self) -> u16 {
59        RdwHeader::from_bytes(self.header).reserved()
60    }
61
62    /// Recompute the header length field from payload length.
63    ///
64    /// # Errors
65    /// Returns an error when payload length exceeds `u16::MAX`.
66    #[inline]
67    #[must_use = "Handle the Result or propagate the error"]
68    pub fn try_recompute_length(&mut self) -> Result<()> {
69        self.header = RdwHeader::from_payload_len(self.payload.len(), self.reserved())?.bytes();
70        Ok(())
71    }
72
73    /// Serialize record as `header + payload`.
74    #[inline]
75    #[must_use]
76    pub fn as_bytes(&self) -> Vec<u8> {
77        let mut result = Vec::with_capacity(RDW_HEADER_LEN + self.payload.len());
78        result.extend_from_slice(&self.header);
79        result.extend_from_slice(&self.payload);
80        result
81    }
82}