1use crate::encode::{FLAG_INLINE_SCHEMA, HEADER_LEN, MESSAGE_MAGIC};
9use crate::error::{Error, Result};
10use crate::message::Budget;
11
12#[inline]
19pub fn charge(budget: Option<&Budget>, bytes: u64) -> Result<()> {
20 match budget {
21 Some(b) => b.charge(bytes),
22 None => Ok(()),
23 }
24}
25
26pub fn read_str_budgeted<'b>(buf: &'b [u8], slot: u64, budget: Option<&Budget>) -> Result<&'b str> {
29 let off = read_u32(buf, slot)? as u64;
30 let len = read_u32(buf, off)? as u64;
31 charge(budget, 8 + len)?;
32 let bytes = read_slice(buf, off + 4, len)?;
33 std::str::from_utf8(bytes).map_err(|_| Error::BadUtf8)
34}
35
36pub fn read_bytes_budgeted<'b>(
38 buf: &'b [u8],
39 slot: u64,
40 budget: Option<&Budget>,
41) -> Result<&'b [u8]> {
42 let off = read_u32(buf, slot)? as u64;
43 let len = read_u32(buf, off)? as u64;
44 charge(budget, 8 + len)?;
45 read_slice(buf, off + 4, len)
46}
47
48pub fn message_header(
54 schema_id: u128,
55 inline_schema: Option<&[u8]>,
56 capacity_hint: usize,
57) -> Result<Vec<u8>> {
58 let mut buf = Vec::with_capacity(capacity_hint.max(HEADER_LEN));
59 buf.extend_from_slice(MESSAGE_MAGIC);
60 let flags: u16 = if inline_schema.is_some() {
61 FLAG_INLINE_SCHEMA
62 } else {
63 0
64 };
65 buf.extend_from_slice(&flags.to_le_bytes());
66 buf.extend_from_slice(&0u16.to_le_bytes()); buf.extend_from_slice(&schema_id.to_le_bytes()); buf.extend_from_slice(&0u32.to_le_bytes()); let schema_len = inline_schema.map(|s| s.len()).unwrap_or(0);
70 let schema_len = u32::try_from(schema_len).map_err(|_| Error::MessageTooLarge)?;
71 buf.extend_from_slice(&schema_len.to_le_bytes());
72 if let Some(s) = inline_schema {
73 buf.extend_from_slice(s);
74 }
75 while buf.len() % 8 != 0 {
76 buf.push(0);
77 }
78 Ok(buf)
79}
80
81pub fn finish_message(buf: &mut [u8], root_offset: u32) {
83 buf[24..28].copy_from_slice(&root_offset.to_le_bytes());
84}
85
86pub fn pos(buf: &[u8]) -> Result<u32> {
87 u32::try_from(buf.len()).map_err(|_| Error::MessageTooLarge)
88}
89
90pub fn pad_to(buf: &mut Vec<u8>, align: u32) -> Result<u32> {
91 let p = pos(buf)?;
92 let target = (p as u64 + align as u64 - 1) & !(align as u64 - 1);
93 let target = u32::try_from(target).map_err(|_| Error::MessageTooLarge)?;
94 buf.resize(buf.len() + (target - p) as usize, 0);
95 Ok(target)
96}
97
98pub fn alloc_block(buf: &mut Vec<u8>, size: u32, align: u32) -> Result<u32> {
100 let base = pad_to(buf, align)?;
101 buf.resize(buf.len() + size as usize, 0);
102 pos(buf)?;
103 Ok(base)
104}
105
106pub fn alloc_bytes(buf: &mut Vec<u8>, n: usize) -> Result<u32> {
108 let base = pos(buf)?;
109 buf.resize(buf.len().checked_add(n).ok_or(Error::MessageTooLarge)?, 0);
110 pos(buf)?;
111 Ok(base)
112}
113
114pub fn set_presence_bit(buf: &mut [u8], base: u32, bit: usize) -> Result<()> {
116 let at = base as usize + bit / 8;
117 let b = buf.get_mut(at).ok_or(Error::OutOfBounds)?;
118 *b |= 1 << (bit % 8);
119 Ok(())
120}
121
122fn put(buf: &mut [u8], at: u32, bytes: &[u8]) -> Result<()> {
123 let start = at as usize;
124 let end = start.checked_add(bytes.len()).ok_or(Error::OutOfBounds)?;
125 buf.get_mut(start..end)
126 .ok_or(Error::OutOfBounds)?
127 .copy_from_slice(bytes);
128 Ok(())
129}
130
131macro_rules! put_fns {
132 ($($name:ident: $ty:ty),* $(,)?) => {$(
133 pub fn $name(buf: &mut [u8], at: u32, v: $ty) -> Result<()> {
134 put(buf, at, &v.to_le_bytes())
135 }
136 )*};
137}
138put_fns!(put_u16: u16, put_u32: u32, put_u64: u64, put_i16: i16, put_i32: i32, put_i64: i64, put_f32: f32, put_f64: f64);
139
140pub fn put_u8(buf: &mut [u8], at: u32, v: u8) -> Result<()> {
141 put(buf, at, &[v])
142}
143
144pub fn put_i8(buf: &mut [u8], at: u32, v: i8) -> Result<()> {
145 put(buf, at, &[v as u8])
146}
147
148pub fn put_bool(buf: &mut [u8], at: u32, v: bool) -> Result<()> {
149 put(buf, at, &[v as u8])
150}
151
152pub fn patch_u32(buf: &mut [u8], at: u32, v: u32) -> Result<()> {
153 put_u32(buf, at, v)
154}
155
156pub fn write_blob(buf: &mut Vec<u8>, bytes: &[u8]) -> Result<u32> {
158 let len = u32::try_from(bytes.len()).map_err(|_| Error::MessageTooLarge)?;
159 let off = pad_to(buf, 4)?;
160 buf.extend_from_slice(&len.to_le_bytes());
161 buf.extend_from_slice(bytes);
162 pos(buf)?;
163 Ok(off)
164}
165
166pub fn begin_list(buf: &mut Vec<u8>, count: u32, elem_align: u32) -> Result<u32> {
170 let off = pad_to(buf, 4)?;
171 buf.extend_from_slice(&count.to_le_bytes());
172 pad_to(buf, elem_align)?;
173 Ok(off)
174}
175
176macro_rules! push_fns {
177 ($($name:ident: $ty:ty),* $(,)?) => {$(
178 pub fn $name(buf: &mut Vec<u8>, v: $ty) {
179 buf.extend_from_slice(&v.to_le_bytes());
180 }
181 )*};
182}
183push_fns!(push_u16: u16, push_u32: u32, push_u64: u64, push_i16: i16, push_i32: i32, push_i64: i64, push_f32: f32, push_f64: f64);
184
185pub fn push_u8(buf: &mut Vec<u8>, v: u8) {
186 buf.push(v);
187}
188
189pub fn push_i8(buf: &mut Vec<u8>, v: i8) {
190 buf.push(v as u8);
191}
192
193pub fn push_bool(buf: &mut Vec<u8>, v: bool) {
194 buf.push(v as u8);
195}
196
197macro_rules! push_slice_fns {
204 ($($name:ident: $ty:ty = $n:literal),* $(,)?) => {$(
205 pub fn $name(buf: &mut Vec<u8>, vals: &[$ty]) {
206 let start = buf.len();
207 buf.resize(start + vals.len() * $n, 0);
208 for (chunk, v) in buf[start..].chunks_exact_mut($n).zip(vals) {
209 chunk.copy_from_slice(&v.to_le_bytes());
210 }
211 }
212 )*};
213}
214push_slice_fns!(
215 push_u16_slice: u16 = 2, push_u32_slice: u32 = 4, push_u64_slice: u64 = 8,
216 push_i16_slice: i16 = 2, push_i32_slice: i32 = 4, push_i64_slice: i64 = 8,
217 push_f32_slice: f32 = 4, push_f64_slice: f64 = 8,
218);
219
220pub fn push_u8_slice(buf: &mut Vec<u8>, vals: &[u8]) {
221 buf.extend_from_slice(vals);
222}
223
224pub fn push_i8_slice(buf: &mut Vec<u8>, vals: &[i8]) {
225 let start = buf.len();
226 buf.resize(start + vals.len(), 0);
227 for (b, &v) in buf[start..].iter_mut().zip(vals) {
228 *b = v as u8;
229 }
230}
231
232pub fn push_bool_slice(buf: &mut Vec<u8>, vals: &[bool]) {
233 let start = buf.len();
234 buf.resize(start + vals.len(), 0);
235 for (b, &v) in buf[start..].iter_mut().zip(vals) {
236 *b = v as u8;
237 }
238}
239
240pub fn read_slice(buf: &[u8], at: u64, len: u64) -> Result<&[u8]> {
245 let start = usize::try_from(at).map_err(|_| Error::OutOfBounds)?;
246 let len = usize::try_from(len).map_err(|_| Error::OutOfBounds)?;
247 let end = start.checked_add(len).ok_or(Error::OutOfBounds)?;
248 buf.get(start..end).ok_or(Error::OutOfBounds)
249}
250
251macro_rules! read_fns {
252 ($($name:ident: $ty:ty = $n:literal),* $(,)?) => {$(
253 pub fn $name(buf: &[u8], at: u64) -> Result<$ty> {
254 Ok(<$ty>::from_le_bytes(read_slice(buf, at, $n)?.try_into().unwrap()))
255 }
256 )*};
257}
258read_fns!(
259 read_u16: u16 = 2, read_u32: u32 = 4, read_u64: u64 = 8,
260 read_i16: i16 = 2, read_i32: i32 = 4, read_i64: i64 = 8,
261 read_f32: f32 = 4, read_f64: f64 = 8,
262);
263
264pub fn read_u8(buf: &[u8], at: u64) -> Result<u8> {
265 Ok(read_slice(buf, at, 1)?[0])
266}
267
268pub fn read_i8(buf: &[u8], at: u64) -> Result<i8> {
269 Ok(read_u8(buf, at)? as i8)
270}
271
272pub fn read_bool(buf: &[u8], at: u64) -> Result<bool> {
273 Ok(read_u8(buf, at)? != 0)
274}
275
276pub fn read_str(buf: &[u8], slot: u64) -> Result<&str> {
278 let bytes = read_bytes(buf, slot)?;
279 std::str::from_utf8(bytes).map_err(|_| Error::BadUtf8)
280}
281
282pub fn read_bytes(buf: &[u8], slot: u64) -> Result<&[u8]> {
284 let off = read_u32(buf, slot)? as u64;
285 let len = read_u32(buf, off)? as u64;
286 read_slice(buf, off + 4, len)
287}
288
289pub fn list_header(buf: &[u8], slot: u64, elem_align: u32) -> Result<(u64, u32)> {
292 let off = read_u32(buf, slot)? as u64;
293 let count = read_u32(buf, off)?;
294 let a = elem_align as u64;
295 let elems = (off + 4 + a - 1) & !(a - 1);
296 Ok((elems, count))
297}