winter_utils/serde/byte_writer.rs
1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6use super::Serializable;
7
8// BYTE WRITER TRAIT
9// ================================================================================================
10
11/// Defines how primitive values are to be written into `Self`.
12pub trait ByteWriter: Sized {
13 // REQUIRED METHODS
14 // --------------------------------------------------------------------------------------------
15
16 /// Writes a single byte into `self`.
17 ///
18 /// # Panics
19 /// Panics if the byte could not be written into `self`.
20 fn write_u8(&mut self, value: u8);
21
22 /// Writes a sequence of bytes into `self`.
23 ///
24 /// # Panics
25 /// Panics if the sequence of bytes could not be written into `self`.
26 fn write_bytes(&mut self, values: &[u8]);
27
28 // PROVIDED METHODS
29 // --------------------------------------------------------------------------------------------
30
31 /// Writes a boolean value into `self`.
32 ///
33 /// A boolean value is written as a single byte.
34 ///
35 /// # Panics
36 /// Panics if the value could not be written into `self`.
37 fn write_bool(&mut self, val: bool) {
38 self.write_u8(val as u8);
39 }
40
41 /// Writes a u16 value in little-endian byte order into `self`.
42 ///
43 /// # Panics
44 /// Panics if the value could not be written into `self`.
45 fn write_u16(&mut self, value: u16) {
46 self.write_bytes(&value.to_le_bytes());
47 }
48
49 /// Writes a u32 value in little-endian byte order into `self`.
50 ///
51 /// # Panics
52 /// Panics if the value could not be written into `self`.
53 fn write_u32(&mut self, value: u32) {
54 self.write_bytes(&value.to_le_bytes());
55 }
56
57 /// Writes a u64 value in little-endian byte order into `self`.
58 ///
59 /// # Panics
60 /// Panics if the value could not be written into `self`.
61 fn write_u64(&mut self, value: u64) {
62 self.write_bytes(&value.to_le_bytes());
63 }
64
65 /// Writes a u128 value in little-endian byte order into `self`.
66 ///
67 /// # Panics
68 /// Panics if the value could not be written into `self`.
69 fn write_u128(&mut self, value: u128) {
70 self.write_bytes(&value.to_le_bytes());
71 }
72
73 /// Writes a usize value in [vint64](https://docs.rs/vint64/latest/vint64/) format into `self`.
74 ///
75 /// # Panics
76 /// Panics if the value could not be written into `self`.
77 fn write_usize(&mut self, value: usize) {
78 // convert the value into a u64 so that we always get 8 bytes from to_le_bytes() call
79 let value = value as u64;
80 let length = usize_encoded_len(value);
81
82 // 9-byte special case
83 if length == 9 {
84 // length byte is zero in this case
85 self.write_u8(0);
86 self.write(value.to_le_bytes());
87 } else {
88 let encoded_bytes = (((value << 1) | 1) << (length - 1)).to_le_bytes();
89 self.write_bytes(&encoded_bytes[..length]);
90 }
91 }
92
93 /// Writes a serializable value into `self`.
94 ///
95 /// # Panics
96 /// Panics if the value could not be written into `self`.
97 fn write<S: Serializable>(&mut self, value: S) {
98 value.write_into(self)
99 }
100
101 /// Serializes all `elements` and writes the resulting bytes into `self`.
102 ///
103 /// This method does not write any metadata (e.g. number of serialized elements) into `self`.
104 fn write_many<S, T>(&mut self, elements: T)
105 where
106 T: IntoIterator<Item = S>,
107 S: Serializable,
108 {
109 for element in elements {
110 element.write_into(self);
111 }
112 }
113}
114
115// BYTE WRITER IMPLEMENTATIONS
116// ================================================================================================
117
118#[cfg(feature = "std")]
119impl<W: std::io::Write> ByteWriter for W {
120 #[inline(always)]
121 fn write_u8(&mut self, byte: u8) {
122 <W as std::io::Write>::write_all(self, &[byte]).expect("write failed")
123 }
124 #[inline(always)]
125 fn write_bytes(&mut self, bytes: &[u8]) {
126 <W as std::io::Write>::write_all(self, bytes).expect("write failed")
127 }
128}
129
130#[cfg(not(feature = "std"))]
131impl ByteWriter for alloc::vec::Vec<u8> {
132 fn write_u8(&mut self, value: u8) {
133 self.push(value);
134 }
135
136 fn write_bytes(&mut self, values: &[u8]) {
137 self.extend_from_slice(values);
138 }
139}
140
141// HELPER FUNCTIONS
142// ================================================================================================
143
144/// Returns the length of the usize value in vint64 encoding.
145pub(super) fn usize_encoded_len(value: u64) -> usize {
146 let zeros = value.leading_zeros() as usize;
147 let len = zeros.saturating_sub(1) / 7;
148 9 - core::cmp::min(len, 8)
149}
150
151#[cfg(all(test, feature = "std"))]
152mod tests {
153 use std::io::Cursor;
154
155 use super::*;
156
157 #[test]
158 fn write_adapter_passthrough() {
159 let mut writer = Cursor::new([0u8; 128]);
160 writer.write_bytes(b"nope");
161 let buf = writer.get_ref();
162 assert_eq!(&buf[..4], b"nope");
163 }
164
165 #[test]
166 #[should_panic]
167 fn write_adapter_writer_out_of_capacity() {
168 let mut writer = Cursor::new([0; 2]);
169 writer.write_bytes(b"nope");
170 }
171}