dotnet_binary_io/
writer.rs1use zerocopy::IntoBytes;
2
3extern crate alloc;
4use alloc::vec::Vec;
5
6pub type Result<T> = core::result::Result<T, BinaryWriterError>;
7
8pub struct BinaryWriter {
10 pub out: Vec<u8>,
12}
13
14impl BinaryWriter {
15 pub fn wrap(out: Vec<u8>) -> Self {
17 Self { out }
18 }
19
20 pub fn into_inner(self) -> Vec<u8> {
22 self.out
23 }
24
25 pub fn inner_mut(&mut self) -> &mut Vec<u8> {
27 &mut self.out
28 }
29
30 pub fn new() -> Self {
32 Self { out: Vec::new() }
33 }
34
35 pub fn with_capacity(len: usize) -> Self {
37 Self {
38 out: Vec::with_capacity(len),
39 }
40 }
41
42 pub fn write_bytes(&mut self, bytes: &[u8]) {
44 self.out.extend_from_slice(bytes);
45 }
46
47 pub fn write_cbytes<const N: usize>(&mut self, value: [u8; N]) {
49 self.write_bytes(&value)
50 }
51
52 pub fn write_u8(&mut self, value: u8) {
54 self.write_bytes(&[value])
55 }
56
57 pub fn write_i8(&mut self, value: i8) {
59 self.write_bytes(&[value as u8])
60 }
61
62 pub fn write_u16(&mut self, value: u16) {
64 self.write_cbytes(value.to_le_bytes())
65 }
66
67 pub fn write_u32(&mut self, value: u32) {
69 self.write_cbytes(value.to_le_bytes())
70 }
71
72 pub fn write_u64(&mut self, value: u64) {
74 self.write_cbytes(value.to_le_bytes())
75 }
76
77 pub fn write_i16(&mut self, value: i16) {
79 self.write_cbytes(value.to_le_bytes())
80 }
81
82 pub fn write_i32(&mut self, value: i32) {
84 self.write_cbytes(value.to_le_bytes())
85 }
86
87 pub fn write_i64(&mut self, value: i64) {
89 self.write_cbytes(value.to_le_bytes())
90 }
91
92 pub fn write_7bit_encoded_i32(&mut self, value: i32) {
99 const MORE: u8 = 0x80; const MASK: u8 = 0x7f;
101
102 let w0: u8 = value as u8 & MASK; let w1: u8 = (value >> 7) as u8 & MASK; let w2: u8 = (value >> 14) as u8 & MASK; let w3: u8 = (value >> 21) as u8 & MASK; let w4: u8 = (value >> 28) as u8 & 0xF; if w4 != 0 {
109 self.write_cbytes([w0 | MORE, w1 | MORE, w2 | MORE, w3 | MORE, w4]);
110 } else if w3 != 0 {
111 self.write_cbytes([w0 | MORE, w1 | MORE, w2 | MORE, w3]);
112 } else if w2 != 0 {
113 self.write_cbytes([w0 | MORE, w1 | MORE, w2]);
114 } else if w1 != 0 {
115 self.write_cbytes([w0 | MORE, w1]);
116 } else {
117 self.write_cbytes([w0]);
118 }
119 }
120
121 pub fn write_7bit_encoded_i64(&mut self, value: i64) {
128 let mut n: u64 = value as u64;
129
130 loop {
131 if n < 0x80 {
132 self.write_u8(n as u8);
133 break;
134 }
135 self.write_u8((n & 0x7f) as u8 | 0x80);
136 n >>= 7;
137 }
138 }
139
140 pub fn write_bool(&mut self, value: bool) {
142 self.write_u8(value as u8)
143 }
144
145 pub fn write_f32(&mut self, value: f32) {
148 self.write_cbytes(value.to_le_bytes());
149 }
150
151 pub fn write_f64(&mut self, value: f64) {
154 self.write_cbytes(value.to_le_bytes());
155 }
156
157 pub fn write_utf8_str(&mut self, s: &str) -> Result<()> {
159 let len_i32 = i32::try_from(s.len()).map_err(|_| BinaryWriterError::CannotEncode)?;
160 self.write_7bit_encoded_i32(len_i32);
161 self.write_bytes(s.as_bytes());
162 Ok(())
163 }
164
165 pub fn write_utf8_bytes(&mut self, s: &[u8]) -> Result<()> {
169 let len_i32 = i32::try_from(s.len()).map_err(|_| BinaryWriterError::CannotEncode)?;
170 self.write_7bit_encoded_i32(len_i32);
171 self.write_bytes(s);
172 Ok(())
173 }
174
175 pub fn write_utf16_wchars(&mut self, s: &[u16]) -> Result<()> {
179 let s_bytes = s.as_bytes();
180 let len_i32 = i32::try_from(s_bytes.len()).map_err(|_| BinaryWriterError::CannotEncode)?;
181 self.write_7bit_encoded_i32(len_i32);
182 self.write_bytes(s_bytes);
183 Ok(())
184 }
185
186 pub fn write_utf16_encode(&mut self, s: &str) {
188 let num_utf16_code_units = s.encode_utf16().count();
189 let len_bytes: usize = num_utf16_code_units * 2;
190 self.write_7bit_encoded_i32(len_bytes as i32);
191
192 self.out.reserve(len_bytes);
193 for c in s.encode_utf16() {
194 self.write_u16(c);
195 }
196 }
197}
198
199#[derive(Clone, Eq, PartialEq, Debug)]
201pub enum BinaryWriterError {
202 CannotEncode,
205}
206
207impl core::error::Error for BinaryWriterError {}
208
209impl core::fmt::Display for BinaryWriterError {
210 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
211 match self {
212 Self::CannotEncode => f.write_str("The data cannot be encoded"),
213 }
214 }
215}