font_test_data/
bebuffer.rs1use font_types::Scalar;
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Default)]
8pub struct BeBuffer {
9 data: Vec<u8>,
10 tagged_locations: HashMap<String, usize>,
11}
12
13impl BeBuffer {
14 pub fn new() -> Self {
15 Default::default()
16 }
17
18 pub fn len(&self) -> usize {
20 self.data.len()
21 }
22
23 pub fn is_empty(&self) -> bool {
25 self.data.is_empty()
26 }
27
28 pub fn as_slice(&self) -> &[u8] {
30 &self.data
31 }
32
33 pub fn push(mut self, item: impl Scalar) -> Self {
35 self.data.extend(item.to_raw().as_ref());
36 self
37 }
38
39 pub fn push_with_tag(mut self, item: impl Scalar, tag: &str) -> Self {
40 self.tagged_locations
41 .insert(tag.to_string(), self.data.len());
42 self.data.extend(item.to_raw().as_ref());
43 self
44 }
45
46 pub fn extend<T: Scalar>(mut self, iter: impl IntoIterator<Item = T>) -> Self {
48 for item in iter {
49 self.data.extend(item.to_raw().as_ref());
50 }
51 self
52 }
53
54 pub fn offset_for(&self, tag: &str) -> usize {
55 self.tagged_locations.get(tag).copied().unwrap()
57 }
58
59 fn data_for(&mut self, tag: &str) -> &mut [u8] {
60 let offset = self.offset_for(tag);
61 &mut self.data[offset..]
62 }
63
64 pub fn write_at(&mut self, tag: &str, item: impl Scalar) {
65 let data = self.data_for(tag);
66 let raw = item.to_raw();
67 let new_data: &[u8] = raw.as_ref();
68
69 if data.len() < new_data.len() {
70 panic!("not enough room left in buffer for the requested write.");
71 }
72
73 for (left, right) in data.iter_mut().zip(new_data) {
74 *left = *right
75 }
76 }
77
78 pub fn data(&self) -> &[u8] {
79 &self.data
80 }
81}
82
83impl std::ops::Deref for BeBuffer {
84 type Target = [u8];
85 fn deref(&self) -> &Self::Target {
86 &self.data
87 }
88}
89
90#[macro_export]
100macro_rules! be_buffer_add {
101 ($b:ident, $v:literal) => {
102 let $b = $b.push($v);
103 };
104 ($b:ident, {$v:tt : $tag:literal}) => {
105 let $b = $b.push_with_tag($v, $tag);
106 };
107 ($b:ident, [$($v:literal),+]) => {
108 let $b = $b.extend([$($v),*]);
109 };
110 ($b:ident, $v:tt) => {
111 let $b = $b.push($v);
112 };
113}
114
115#[macro_export]
123macro_rules! be_buffer {
124 ( $( $x:tt ),+ ) => {
125 {
126 let builder = BeBuffer::new();
127 $(
128 $crate::be_buffer_add!(builder, $x);
129 )*
130 builder
131 }
132 };
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn be_buffer_macro() {
141 let data: &[u8] = &be_buffer! {
142 1u8,
143 2u16,
144 3u32
145 };
146
147 assert_eq!([1, 0, 2, 0, 0, 0, 3], data);
148 }
149
150 #[test]
151 fn be_buffer_macro_array() {
152 let data: &[u8] = &be_buffer! {
153 1u8,
154 [2u8, 3, 4, 5, 6]
155 };
156
157 assert_eq!([1, 2, 3, 4, 5, 6], data);
158 }
159
160 #[test]
161 fn be_buffer_macro_tagged() {
162 let builder = be_buffer! {
163 1u8,
164 {2u16: "foo"},
165 {(u32::from(3u16)): "bar"}
166 };
167 let data: &[u8] = &builder;
168
169 assert_eq!([1, 0, 2, 0, 0, 0, 3], data);
170 assert_eq!(builder.offset_for("foo"), 1);
171 assert_eq!(builder.offset_for("bar"), 3);
172 }
173}