oximedia_bitstream/write/byte_writer.rs
1// Copyright 2017 Brian Langenberger
2// Copyright 2024-2026 COOLJAPAN OU (Team Kitasan)
3//
4// Licensed under the Apache License, Version 2.0 or the MIT license,
5// at your option. See the LICENSE-APACHE / LICENSE-MIT files for details.
6
7//! `ByteWriter` and the `ByteWrite` trait for whole-byte output.
8
9use std::io;
10
11use super::{
12 BitWriter, Endianness, PhantomData, Primitive, ToByteStream, ToByteStreamUsing,
13 ToByteStreamWith,
14};
15
16/// For writing aligned bytes to a stream of bytes in a given endianness.
17///
18/// This only writes aligned values and maintains no internal state.
19pub struct ByteWriter<W: io::Write, E: Endianness> {
20 phantom: PhantomData<E>,
21 writer: W,
22}
23
24impl<W: io::Write, E: Endianness> ByteWriter<W, E> {
25 /// Wraps a ByteWriter around something that implements `Write`
26 pub fn new(writer: W) -> ByteWriter<W, E> {
27 ByteWriter {
28 phantom: PhantomData,
29 writer,
30 }
31 }
32
33 /// Wraps a BitWriter around something that implements `Write`
34 /// with the given endianness.
35 pub fn endian(writer: W, _endian: E) -> ByteWriter<W, E> {
36 ByteWriter {
37 phantom: PhantomData,
38 writer,
39 }
40 }
41
42 /// Unwraps internal writer and disposes of `ByteWriter`.
43 /// Any unwritten partial bits are discarded.
44 #[inline]
45 pub fn into_writer(self) -> W {
46 self.writer
47 }
48
49 /// Provides mutable reference to internal writer.
50 #[inline]
51 pub fn writer(&mut self) -> &mut W {
52 &mut self.writer
53 }
54
55 /// Converts `ByteWriter` to `BitWriter` in the same endianness.
56 #[inline]
57 pub fn into_bitwriter(self) -> BitWriter<W, E> {
58 BitWriter::new(self.into_writer())
59 }
60
61 /// Provides temporary `BitWriter` in the same endianness.
62 ///
63 /// # Warning
64 ///
65 /// Any unwritten bits left over when `BitWriter` is dropped are lost.
66 #[inline]
67 pub fn bitwriter(&mut self) -> BitWriter<&mut W, E> {
68 BitWriter::new(self.writer())
69 }
70}
71
72/// A trait for anything that can write aligned values to an output stream
73pub trait ByteWrite {
74 /// Writes whole numeric value to stream
75 ///
76 /// # Errors
77 ///
78 /// Passes along any I/O error from the underlying stream.
79 /// # Examples
80 /// ```
81 /// use std::io::Write;
82 /// use oximedia_bitstream::{BigEndian, ByteWriter, ByteWrite};
83 /// let mut writer = ByteWriter::endian(Vec::new(), BigEndian);
84 /// writer.write(0b0000000011111111u16).unwrap();
85 /// assert_eq!(writer.into_writer(), [0b00000000, 0b11111111]);
86 /// ```
87 ///
88 /// ```
89 /// use std::io::Write;
90 /// use oximedia_bitstream::{LittleEndian, ByteWriter, ByteWrite};
91 /// let mut writer = ByteWriter::endian(Vec::new(), LittleEndian);
92 /// writer.write(0b0000000011111111u16).unwrap();
93 /// assert_eq!(writer.into_writer(), [0b11111111, 0b00000000]);
94 /// ```
95 fn write<V>(&mut self, value: V) -> io::Result<()>
96 where
97 V: Primitive;
98
99 /// Writes whole numeric value to stream in a potentially different endianness
100 ///
101 /// # Errors
102 ///
103 /// Passes along any I/O error from the underlying stream.
104 ///
105 /// # Examples
106 /// ```
107 /// use std::io::Write;
108 /// use oximedia_bitstream::{BigEndian, ByteWriter, ByteWrite, LittleEndian};
109 /// let mut writer = ByteWriter::endian(Vec::new(), BigEndian);
110 /// writer.write_as::<LittleEndian, u16>(0b0000000011111111).unwrap();
111 /// assert_eq!(writer.into_writer(), [0b11111111, 0b00000000]);
112 /// ```
113 ///
114 /// ```
115 /// use std::io::Write;
116 /// use oximedia_bitstream::{BigEndian, ByteWriter, ByteWrite, LittleEndian};
117 /// let mut writer = ByteWriter::endian(Vec::new(), LittleEndian);
118 /// writer.write_as::<BigEndian, u16>(0b0000000011111111).unwrap();
119 /// assert_eq!(writer.into_writer(), [0b00000000, 0b11111111]);
120 /// ```
121 fn write_as<F, V>(&mut self, value: V) -> io::Result<()>
122 where
123 F: Endianness,
124 V: Primitive;
125
126 /// Writes the entirety of a byte buffer to the stream.
127 ///
128 /// # Errors
129 ///
130 /// Passes along any I/O error from the underlying stream.
131 fn write_bytes(&mut self, buf: &[u8]) -> io::Result<()>;
132
133 /// Pads the stream by writing 0 over the given number of bytes.
134 ///
135 /// # Errors
136 ///
137 /// Passes along any I/O error from the underlying stream.
138 fn pad(&mut self, bytes: u32) -> io::Result<()>;
139
140 /// Builds and writes complex type
141 fn build<T: ToByteStream>(&mut self, build: &T) -> Result<(), T::Error> {
142 build.to_writer(self)
143 }
144
145 /// Builds and writes complex type with context
146 fn build_with<'a, T: ToByteStreamWith<'a>>(
147 &mut self,
148 build: &T,
149 context: &T::Context,
150 ) -> Result<(), T::Error> {
151 build.to_writer(self, context)
152 }
153
154 /// Builds and writes complex type with owned context
155 fn build_using<T: ToByteStreamUsing>(
156 &mut self,
157 build: &T,
158 context: T::Context,
159 ) -> Result<(), T::Error> {
160 build.to_writer(self, context)
161 }
162
163 /// Returns mutable reference to underlying writer
164 fn writer_ref(&mut self) -> &mut dyn io::Write;
165}
166
167impl<W: io::Write, E: Endianness> ByteWrite for ByteWriter<W, E> {
168 #[inline]
169 fn write<V>(&mut self, value: V) -> io::Result<()>
170 where
171 V: Primitive,
172 {
173 self.writer.write_all(E::primitive_to_bytes(value).as_ref())
174 }
175
176 #[inline]
177 fn write_as<F, V>(&mut self, value: V) -> io::Result<()>
178 where
179 F: Endianness,
180 V: Primitive,
181 {
182 self.writer.write_all(F::primitive_to_bytes(value).as_ref())
183 }
184
185 #[inline]
186 fn pad(&mut self, mut bytes: u32) -> io::Result<()> {
187 let buf = [0u8; 8];
188
189 while bytes > 0 {
190 let to_write = bytes.min(8);
191 self.write_bytes(&buf[0..to_write as usize])?;
192 bytes -= to_write;
193 }
194 Ok(())
195 }
196
197 #[inline]
198 fn write_bytes(&mut self, buf: &[u8]) -> io::Result<()> {
199 self.writer.write_all(buf)
200 }
201
202 #[inline]
203 fn writer_ref(&mut self) -> &mut dyn io::Write {
204 &mut self.writer
205 }
206}