Skip to main content

opentdf_protocol/binary/
mod.rs

1//! Binary serialization infrastructure for NanoTDF
2//!
3//! This module provides traits and utilities for reading and writing
4//! binary data in the NanoTDF format. All multi-byte integers use
5//! big-endian byte order as specified in the NanoTDF specification.
6
7use std::io::{self, Read, Write};
8
9pub mod traits;
10
11pub use traits::{BinaryRead, BinaryWrite};
12
13/// Read a u8 from a reader
14pub fn read_u8<R: Read>(reader: &mut R) -> io::Result<u8> {
15    let mut buf = [0u8; 1];
16    reader.read_exact(&mut buf)?;
17    Ok(buf[0])
18}
19
20/// Read a u16 (big-endian) from a reader
21pub fn read_u16_be<R: Read>(reader: &mut R) -> io::Result<u16> {
22    let mut buf = [0u8; 2];
23    reader.read_exact(&mut buf)?;
24    Ok(u16::from_be_bytes(buf))
25}
26
27/// Read a u24 (big-endian, 3 bytes) from a reader
28/// Returns as u32 since Rust doesn't have a u24 type
29pub fn read_u24_be<R: Read>(reader: &mut R) -> io::Result<u32> {
30    let mut buf = [0u8; 3];
31    reader.read_exact(&mut buf)?;
32    Ok(u32::from_be_bytes([0, buf[0], buf[1], buf[2]]))
33}
34
35/// Read a u32 (big-endian) from a reader
36pub fn read_u32_be<R: Read>(reader: &mut R) -> io::Result<u32> {
37    let mut buf = [0u8; 4];
38    reader.read_exact(&mut buf)?;
39    Ok(u32::from_be_bytes(buf))
40}
41
42/// Read exactly n bytes from a reader
43pub fn read_bytes<R: Read>(reader: &mut R, n: usize) -> io::Result<Vec<u8>> {
44    let mut buf = vec![0u8; n];
45    reader.read_exact(&mut buf)?;
46    Ok(buf)
47}
48
49/// Write a u8 to a writer
50pub fn write_u8<W: Write>(writer: &mut W, value: u8) -> io::Result<()> {
51    writer.write_all(&[value])
52}
53
54/// Write a u16 (big-endian) to a writer
55pub fn write_u16_be<W: Write>(writer: &mut W, value: u16) -> io::Result<()> {
56    writer.write_all(&value.to_be_bytes())
57}
58
59/// Write a u24 (big-endian, 3 bytes) to a writer
60/// Takes u32 but only writes the lower 24 bits
61pub fn write_u24_be<W: Write>(writer: &mut W, value: u32) -> io::Result<()> {
62    if value > 0x00FF_FFFF {
63        return Err(io::Error::new(
64            io::ErrorKind::InvalidInput,
65            "Value too large for u24",
66        ));
67    }
68    let bytes = value.to_be_bytes();
69    writer.write_all(&bytes[1..4])
70}
71
72/// Write a u32 (big-endian) to a writer
73pub fn write_u32_be<W: Write>(writer: &mut W, value: u32) -> io::Result<()> {
74    writer.write_all(&value.to_be_bytes())
75}
76
77/// Write bytes to a writer
78pub fn write_bytes<W: Write>(writer: &mut W, bytes: &[u8]) -> io::Result<()> {
79    writer.write_all(bytes)
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use std::io::Cursor;
86
87    #[test]
88    fn test_u8_roundtrip() {
89        let mut buf = Vec::new();
90        write_u8(&mut buf, 0x42).unwrap();
91        assert_eq!(buf, vec![0x42]);
92
93        let mut cursor = Cursor::new(buf);
94        assert_eq!(read_u8(&mut cursor).unwrap(), 0x42);
95    }
96
97    #[test]
98    fn test_u16_roundtrip() {
99        let mut buf = Vec::new();
100        write_u16_be(&mut buf, 0x1234).unwrap();
101        assert_eq!(buf, vec![0x12, 0x34]);
102
103        let mut cursor = Cursor::new(buf);
104        assert_eq!(read_u16_be(&mut cursor).unwrap(), 0x1234);
105    }
106
107    #[test]
108    fn test_u24_roundtrip() {
109        let mut buf = Vec::new();
110        write_u24_be(&mut buf, 0x12_3456).unwrap();
111        assert_eq!(buf, vec![0x12, 0x34, 0x56]);
112
113        let mut cursor = Cursor::new(buf);
114        assert_eq!(read_u24_be(&mut cursor).unwrap(), 0x12_3456);
115    }
116
117    #[test]
118    fn test_u24_overflow() {
119        let mut buf = Vec::new();
120        let result = write_u24_be(&mut buf, 0x01_000000);
121        assert!(result.is_err());
122    }
123
124    #[test]
125    fn test_u32_roundtrip() {
126        let mut buf = Vec::new();
127        write_u32_be(&mut buf, 0x12345678).unwrap();
128        assert_eq!(buf, vec![0x12, 0x34, 0x56, 0x78]);
129
130        let mut cursor = Cursor::new(buf);
131        assert_eq!(read_u32_be(&mut cursor).unwrap(), 0x12345678);
132    }
133
134    #[test]
135    fn test_bytes_roundtrip() {
136        let data = vec![0x01, 0x02, 0x03, 0x04, 0x05];
137        let mut buf = Vec::new();
138        write_bytes(&mut buf, &data).unwrap();
139        assert_eq!(buf, data);
140
141        let mut cursor = Cursor::new(buf);
142        assert_eq!(read_bytes(&mut cursor, 5).unwrap(), data);
143    }
144}