binja/ser/
serializer.rs

1use bytes::{BufMut, BytesMut};
2
3use crate::{
4    config::{Config, ContainerLengthStrategy, EndiannessStrategy},
5    error::{Error, Result},
6};
7
8#[derive(Debug, Default)]
9pub struct BinarySerializer {
10    // Buffer to store the serialized binary output
11    output: BytesMut,
12    // Configuration for serialization (e.g., endianness, optional strategy, etc.)
13    config: Config,
14}
15
16impl BinarySerializer {
17    /// Creates a new `BinarySerializer` with the specified configuration.
18    pub fn new(config: Config) -> Self {
19        Self {
20            output: BytesMut::new(),
21            config,
22        }
23    }
24
25    /// Consumes the serializer and returns the serialized output as `BytesMut`.
26    pub fn output(self) -> BytesMut {
27        self.output
28    }
29
30    /// Returns the current configuration of the serializer.
31    pub fn config(&self) -> &crate::config::Config {
32        &self.config
33    }
34
35    /// Returns a mutable reference to the output buffer.
36    pub fn size(&self) -> usize {
37        self.output.len()
38    }
39
40    /// Checks if the serialized output exceeds the configured size limit.
41    /// Returns an error if the limit is exceeded.
42    fn check_limit(&self) -> Result<()> {
43        if let Some(limit) = self.config.limit {
44            if self.output.len() > limit {
45                return Err(Error::LimitExceeded {
46                    limit,
47                    size: self.output.len(),
48                });
49            }
50        }
51        Ok(())
52    }
53
54    /// Writes the length of a container (e.g., sequence, string) to the output buffer
55    /// based on the configured endianness and container length strategy.
56    pub fn container_length(&mut self, length: usize) {
57        match (
58            self.config.endianness_strategy,
59            self.config.container_length_strategy,
60        ) {
61            (_, ContainerLengthStrategy::OneByte) => {
62                self.output.put_u8(length as u8);
63            }
64            (EndiannessStrategy::Big, ContainerLengthStrategy::TwoBytes) => {
65                self.output.put_u16(length as u16);
66            }
67            (EndiannessStrategy::Little, ContainerLengthStrategy::TwoBytes) => {
68                self.output.put_u16_le(length as u16);
69            }
70            (EndiannessStrategy::Big, ContainerLengthStrategy::FourBytes) => {
71                self.output.put_u32(length as u32);
72            }
73            (EndiannessStrategy::Little, ContainerLengthStrategy::FourBytes) => {
74                self.output.put_u32_le(length as u32);
75            }
76            (EndiannessStrategy::Big, ContainerLengthStrategy::EightBytes) => {
77                self.output.put_u64(length as u64);
78            }
79            (EndiannessStrategy::Little, ContainerLengthStrategy::EightBytes) => {
80                self.output.put_u64_le(length as u64);
81            }
82            (EndiannessStrategy::Big, ContainerLengthStrategy::SixteenBytes) => {
83                self.output.put_u128(length as u128);
84            }
85            (EndiannessStrategy::Little, ContainerLengthStrategy::SixteenBytes) => {
86                self.output.put_u128_le(length as u128);
87            }
88        }
89    }
90
91    pub fn bool(&mut self, v: bool) -> Result<()> {
92        self.output.put_u8(if v { 1 } else { 0 });
93        self.check_limit()
94    }
95
96    pub fn i8(&mut self, v: i8) -> Result<()> {
97        self.output.put_i8(v);
98        self.check_limit()
99    }
100
101    pub fn i16(&mut self, v: i16) -> Result<()> {
102        match self.config.endianness_strategy {
103            EndiannessStrategy::Big => self.output.put_i16(v),
104            EndiannessStrategy::Little => self.output.put_i16_le(v),
105        }
106        self.check_limit()
107    }
108
109    pub fn i32(&mut self, v: i32) -> Result<()> {
110        match self.config.endianness_strategy {
111            EndiannessStrategy::Big => self.output.put_i32(v),
112            EndiannessStrategy::Little => self.output.put_i32_le(v),
113        }
114        self.check_limit()
115    }
116
117    pub fn i64(&mut self, v: i64) -> Result<()> {
118        match self.config.endianness_strategy {
119            EndiannessStrategy::Big => self.output.put_i64(v),
120            EndiannessStrategy::Little => self.output.put_i64_le(v),
121        }
122        self.check_limit()
123    }
124
125    pub fn i128(&mut self, v: i128) -> Result<()> {
126        match self.config.endianness_strategy {
127            EndiannessStrategy::Big => self.output.put_i128(v),
128            EndiannessStrategy::Little => self.output.put_i128_le(v),
129        }
130        self.check_limit()
131    }
132
133    pub fn u8(&mut self, v: u8) -> Result<()> {
134        self.output.put_u8(v);
135        self.check_limit()
136    }
137
138    pub fn u16(&mut self, v: u16) -> Result<()> {
139        match self.config.endianness_strategy {
140            EndiannessStrategy::Big => self.output.put_u16(v),
141            EndiannessStrategy::Little => self.output.put_u16_le(v),
142        }
143        self.check_limit()
144    }
145
146    pub fn u32(&mut self, v: u32) -> Result<()> {
147        match self.config.endianness_strategy {
148            EndiannessStrategy::Big => self.output.put_u32(v),
149            EndiannessStrategy::Little => self.output.put_u32_le(v),
150        }
151        self.check_limit()
152    }
153
154    pub fn u64(&mut self, v: u64) -> Result<()> {
155        match self.config.endianness_strategy {
156            EndiannessStrategy::Big => self.output.put_u64(v),
157            EndiannessStrategy::Little => self.output.put_u64_le(v),
158        }
159        self.check_limit()
160    }
161
162    pub fn u128(&mut self, v: u128) -> Result<()> {
163        match self.config.endianness_strategy {
164            EndiannessStrategy::Big => self.output.put_u128(v),
165            EndiannessStrategy::Little => self.output.put_u128_le(v),
166        }
167        self.check_limit()
168    }
169
170    pub fn f32(&mut self, v: f32) -> Result<()> {
171        match self.config.endianness_strategy {
172            EndiannessStrategy::Big => self.output.put_f32(v),
173            EndiannessStrategy::Little => self.output.put_f32_le(v),
174        }
175        self.check_limit()
176    }
177
178    pub fn f64(&mut self, v: f64) -> Result<()> {
179        match self.config.endianness_strategy {
180            EndiannessStrategy::Big => self.output.put_f64(v),
181            EndiannessStrategy::Little => self.output.put_f64_le(v),
182        }
183        self.check_limit()
184    }
185
186    pub fn char(&mut self, v: char) -> Result<()> {
187        self.output.put_slice(v.to_string().as_bytes());
188        self.check_limit()
189    }
190
191    pub fn str(&mut self, v: &str) -> Result<()> {
192        self.container_length(v.len());
193        self.output.put_slice(v.as_bytes());
194        self.check_limit()
195    }
196
197    pub fn bytes(&mut self, v: &[u8]) -> Result<()> {
198        self.output.put_slice(v);
199        self.check_limit()
200    }
201}