Skip to main content

qubit_io/ext/
binary_write_ext.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10
11use std::io::{
12    Result,
13    Write,
14};
15
16use crate::codec::{
17    BigEndian,
18    BinaryCodec,
19    ByteOrder,
20    LittleEndian,
21};
22
23macro_rules! write_binary_value {
24    ($writer:expr, $value:expr, $ty:ty, $order:ty) => {
25        write_binary::<{ BinaryCodec::<$ty, $order>::REQUIRED_MIN_BUFFER_LEN }, _, _, _>(
26            $writer,
27            $value,
28            |bytes, value| {
29                // SAFETY: The local buffer is exactly the codec's minimum buffer length.
30                unsafe { BinaryCodec::<$ty, $order>::write_unchecked(bytes, 0, value) }
31            },
32        )
33    };
34}
35
36/// Extension methods for writing fixed-width binary values to byte streams.
37pub trait BinaryWriteExt: Write {
38    /// Writes an unsigned 8-bit integer.
39    #[inline]
40    fn write_u8(&mut self, value: u8) -> Result<()> {
41        write_binary_value!(self, value, u8, BigEndian)
42    }
43
44    /// Writes a signed 8-bit integer.
45    #[inline]
46    fn write_i8(&mut self, value: i8) -> Result<()> {
47        write_binary_value!(self, value, i8, BigEndian)
48    }
49
50    /// Writes an unsigned 16-bit integer using a runtime byte order.
51    #[inline]
52    fn write_u16(&mut self, value: u16, byte_order: ByteOrder) -> Result<()> {
53        match byte_order {
54            ByteOrder::BigEndian => self.write_u16_be(value),
55            ByteOrder::LittleEndian => self.write_u16_le(value),
56        }
57    }
58
59    /// Writes a big-endian unsigned 16-bit integer.
60    #[inline]
61    fn write_u16_be(&mut self, value: u16) -> Result<()> {
62        write_binary_value!(self, value, u16, BigEndian)
63    }
64
65    /// Writes a little-endian unsigned 16-bit integer.
66    #[inline]
67    fn write_u16_le(&mut self, value: u16) -> Result<()> {
68        write_binary_value!(self, value, u16, LittleEndian)
69    }
70
71    /// Writes an unsigned 32-bit integer using a runtime byte order.
72    #[inline]
73    fn write_u32(&mut self, value: u32, byte_order: ByteOrder) -> Result<()> {
74        match byte_order {
75            ByteOrder::BigEndian => self.write_u32_be(value),
76            ByteOrder::LittleEndian => self.write_u32_le(value),
77        }
78    }
79
80    /// Writes a big-endian unsigned 32-bit integer.
81    #[inline]
82    fn write_u32_be(&mut self, value: u32) -> Result<()> {
83        write_binary_value!(self, value, u32, BigEndian)
84    }
85
86    /// Writes a little-endian unsigned 32-bit integer.
87    #[inline]
88    fn write_u32_le(&mut self, value: u32) -> Result<()> {
89        write_binary_value!(self, value, u32, LittleEndian)
90    }
91
92    /// Writes an unsigned 64-bit integer using a runtime byte order.
93    #[inline]
94    fn write_u64(&mut self, value: u64, byte_order: ByteOrder) -> Result<()> {
95        match byte_order {
96            ByteOrder::BigEndian => self.write_u64_be(value),
97            ByteOrder::LittleEndian => self.write_u64_le(value),
98        }
99    }
100
101    /// Writes a big-endian unsigned 64-bit integer.
102    #[inline]
103    fn write_u64_be(&mut self, value: u64) -> Result<()> {
104        write_binary_value!(self, value, u64, BigEndian)
105    }
106
107    /// Writes a little-endian unsigned 64-bit integer.
108    #[inline]
109    fn write_u64_le(&mut self, value: u64) -> Result<()> {
110        write_binary_value!(self, value, u64, LittleEndian)
111    }
112
113    /// Writes an unsigned 128-bit integer using a runtime byte order.
114    #[inline]
115    fn write_u128(&mut self, value: u128, byte_order: ByteOrder) -> Result<()> {
116        match byte_order {
117            ByteOrder::BigEndian => self.write_u128_be(value),
118            ByteOrder::LittleEndian => self.write_u128_le(value),
119        }
120    }
121
122    /// Writes a big-endian unsigned 128-bit integer.
123    #[inline]
124    fn write_u128_be(&mut self, value: u128) -> Result<()> {
125        write_binary_value!(self, value, u128, BigEndian)
126    }
127
128    /// Writes a little-endian unsigned 128-bit integer.
129    #[inline]
130    fn write_u128_le(&mut self, value: u128) -> Result<()> {
131        write_binary_value!(self, value, u128, LittleEndian)
132    }
133
134    /// Writes a signed 16-bit integer using a runtime byte order.
135    #[inline]
136    fn write_i16(&mut self, value: i16, byte_order: ByteOrder) -> Result<()> {
137        match byte_order {
138            ByteOrder::BigEndian => self.write_i16_be(value),
139            ByteOrder::LittleEndian => self.write_i16_le(value),
140        }
141    }
142
143    /// Writes a big-endian signed 16-bit integer.
144    #[inline]
145    fn write_i16_be(&mut self, value: i16) -> Result<()> {
146        write_binary_value!(self, value, i16, BigEndian)
147    }
148
149    /// Writes a little-endian signed 16-bit integer.
150    #[inline]
151    fn write_i16_le(&mut self, value: i16) -> Result<()> {
152        write_binary_value!(self, value, i16, LittleEndian)
153    }
154
155    /// Writes a signed 32-bit integer using a runtime byte order.
156    #[inline]
157    fn write_i32(&mut self, value: i32, byte_order: ByteOrder) -> Result<()> {
158        match byte_order {
159            ByteOrder::BigEndian => self.write_i32_be(value),
160            ByteOrder::LittleEndian => self.write_i32_le(value),
161        }
162    }
163
164    /// Writes a big-endian signed 32-bit integer.
165    #[inline]
166    fn write_i32_be(&mut self, value: i32) -> Result<()> {
167        write_binary_value!(self, value, i32, BigEndian)
168    }
169
170    /// Writes a little-endian signed 32-bit integer.
171    #[inline]
172    fn write_i32_le(&mut self, value: i32) -> Result<()> {
173        write_binary_value!(self, value, i32, LittleEndian)
174    }
175
176    /// Writes a signed 64-bit integer using a runtime byte order.
177    #[inline]
178    fn write_i64(&mut self, value: i64, byte_order: ByteOrder) -> Result<()> {
179        match byte_order {
180            ByteOrder::BigEndian => self.write_i64_be(value),
181            ByteOrder::LittleEndian => self.write_i64_le(value),
182        }
183    }
184
185    /// Writes a big-endian signed 64-bit integer.
186    #[inline]
187    fn write_i64_be(&mut self, value: i64) -> Result<()> {
188        write_binary_value!(self, value, i64, BigEndian)
189    }
190
191    /// Writes a little-endian signed 64-bit integer.
192    #[inline]
193    fn write_i64_le(&mut self, value: i64) -> Result<()> {
194        write_binary_value!(self, value, i64, LittleEndian)
195    }
196
197    /// Writes a signed 128-bit integer using a runtime byte order.
198    #[inline]
199    fn write_i128(&mut self, value: i128, byte_order: ByteOrder) -> Result<()> {
200        match byte_order {
201            ByteOrder::BigEndian => self.write_i128_be(value),
202            ByteOrder::LittleEndian => self.write_i128_le(value),
203        }
204    }
205
206    /// Writes a big-endian signed 128-bit integer.
207    #[inline]
208    fn write_i128_be(&mut self, value: i128) -> Result<()> {
209        write_binary_value!(self, value, i128, BigEndian)
210    }
211
212    /// Writes a little-endian signed 128-bit integer.
213    #[inline]
214    fn write_i128_le(&mut self, value: i128) -> Result<()> {
215        write_binary_value!(self, value, i128, LittleEndian)
216    }
217
218    /// Writes a 32-bit float using a runtime byte order.
219    #[inline]
220    fn write_f32(&mut self, value: f32, byte_order: ByteOrder) -> Result<()> {
221        match byte_order {
222            ByteOrder::BigEndian => self.write_f32_be(value),
223            ByteOrder::LittleEndian => self.write_f32_le(value),
224        }
225    }
226
227    /// Writes a big-endian 32-bit float.
228    #[inline]
229    fn write_f32_be(&mut self, value: f32) -> Result<()> {
230        write_binary_value!(self, value, f32, BigEndian)
231    }
232
233    /// Writes a little-endian 32-bit float.
234    #[inline]
235    fn write_f32_le(&mut self, value: f32) -> Result<()> {
236        write_binary_value!(self, value, f32, LittleEndian)
237    }
238
239    /// Writes a 64-bit float using a runtime byte order.
240    #[inline]
241    fn write_f64(&mut self, value: f64, byte_order: ByteOrder) -> Result<()> {
242        match byte_order {
243            ByteOrder::BigEndian => self.write_f64_be(value),
244            ByteOrder::LittleEndian => self.write_f64_le(value),
245        }
246    }
247
248    /// Writes a big-endian 64-bit float.
249    #[inline]
250    fn write_f64_be(&mut self, value: f64) -> Result<()> {
251        write_binary_value!(self, value, f64, BigEndian)
252    }
253
254    /// Writes a little-endian 64-bit float.
255    #[inline]
256    fn write_f64_le(&mut self, value: f64) -> Result<()> {
257        write_binary_value!(self, value, f64, LittleEndian)
258    }
259}
260
261impl<W> BinaryWriteExt for W where W: Write + ?Sized {}
262
263#[inline]
264fn write_binary<const N: usize, T, W, F>(writer: &mut W, value: T, encode: F) -> Result<()>
265where
266    W: Write + ?Sized,
267    F: FnOnce(&mut [u8], T),
268{
269    let mut bytes = [0u8; N];
270    encode(&mut bytes, value);
271    writer.write_all(&bytes)
272}