oxihuman_core/
flatbuffer_stub.rs1#![allow(dead_code)]
4
5#[derive(Debug, Default)]
9pub struct FlatBuilder {
10 buf: Vec<u8>,
11 vtables: Vec<usize>,
12 finished: bool,
13}
14
15#[derive(Debug, Clone, PartialEq)]
17pub enum FlatError {
18 AlreadyFinished,
19 NotFinished,
20 InvalidOffset,
21}
22
23impl std::fmt::Display for FlatError {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 match self {
26 Self::AlreadyFinished => write!(f, "builder already finished"),
27 Self::NotFinished => write!(f, "builder not yet finished"),
28 Self::InvalidOffset => write!(f, "invalid FlatBuffers offset"),
29 }
30 }
31}
32
33impl FlatBuilder {
34 pub fn new() -> Self {
36 Self::default()
37 }
38
39 pub fn with_capacity(cap: usize) -> Self {
41 FlatBuilder {
42 buf: Vec::with_capacity(cap),
43 vtables: vec![],
44 finished: false,
45 }
46 }
47
48 pub fn len(&self) -> usize {
50 self.buf.len()
51 }
52
53 pub fn is_empty(&self) -> bool {
55 self.buf.is_empty()
56 }
57
58 pub fn push_u8(&mut self, v: u8) -> Result<usize, FlatError> {
60 if self.finished {
61 return Err(FlatError::AlreadyFinished);
62 }
63 let offset = self.buf.len();
64 self.buf.push(v);
65 Ok(offset)
66 }
67
68 pub fn push_u32(&mut self, v: u32) -> Result<usize, FlatError> {
70 if self.finished {
71 return Err(FlatError::AlreadyFinished);
72 }
73 let offset = self.buf.len();
74 self.buf.extend_from_slice(&v.to_le_bytes());
75 Ok(offset)
76 }
77
78 pub fn push_bytes(&mut self, data: &[u8]) -> Result<usize, FlatError> {
80 if self.finished {
81 return Err(FlatError::AlreadyFinished);
82 }
83 let offset = self.buf.len();
84 self.buf.extend_from_slice(data);
85 Ok(offset)
86 }
87
88 pub fn finish(mut self) -> Result<Vec<u8>, FlatError> {
90 self.finished = true;
91 Ok(self.buf)
92 }
93
94 pub fn bytes(&self) -> &[u8] {
96 &self.buf
97 }
98
99 pub fn align(&mut self, alignment: usize) {
101 while !self.buf.len().is_multiple_of(alignment) {
102 self.buf.push(0);
103 }
104 }
105}
106
107pub fn read_u32(data: &[u8], offset: usize) -> Result<u32, FlatError> {
109 if offset + 4 > data.len() {
110 return Err(FlatError::InvalidOffset);
111 }
112 let bytes: [u8; 4] = data[offset..offset + 4].try_into().unwrap_or_default();
113 Ok(u32::from_le_bytes(bytes))
114}
115
116pub fn padded_size(size: usize, alignment: usize) -> usize {
118 let rem = size % alignment;
119 if rem == 0 {
120 size
121 } else {
122 size + alignment - rem
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn test_new_builder_empty() {
132 let b = FlatBuilder::new();
134 assert!(b.is_empty());
135 }
136
137 #[test]
138 fn test_push_u8() {
139 let mut b = FlatBuilder::new();
141 b.push_u8(0xAB).expect("should succeed");
142 assert_eq!(b.len(), 1);
143 }
144
145 #[test]
146 fn test_push_u32() {
147 let mut b = FlatBuilder::new();
149 b.push_u32(0xDEAD_BEEF).expect("should succeed");
150 assert_eq!(b.len(), 4);
151 }
152
153 #[test]
154 fn test_push_after_finish_fails() {
155 let b = FlatBuilder::new();
157 b.finish().expect("should succeed");
158 let mut b2 = FlatBuilder::new();
160 b2.finished = true;
161 assert!(b2.push_u8(1).is_err());
162 }
163
164 #[test]
165 fn test_push_bytes() {
166 let mut b = FlatBuilder::new();
168 b.push_bytes(&[1, 2, 3]).expect("should succeed");
169 assert_eq!(b.len(), 3);
170 }
171
172 #[test]
173 fn test_finish_returns_bytes() {
174 let mut b = FlatBuilder::new();
176 b.push_u8(99).expect("should succeed");
177 let data = b.finish().expect("should succeed");
178 assert_eq!(data, &[99]);
179 }
180
181 #[test]
182 fn test_align_pads_to_boundary() {
183 let mut b = FlatBuilder::new();
185 b.push_u8(1).expect("should succeed");
186 b.align(4);
187 assert_eq!(b.len() % 4, 0);
188 }
189
190 #[test]
191 fn test_read_u32_ok() {
192 let data = [1u8, 0, 0, 0];
194 assert_eq!(read_u32(&data, 0).expect("should succeed"), 1);
195 }
196
197 #[test]
198 fn test_read_u32_overflow() {
199 let data = [0u8; 3];
201 assert!(read_u32(&data, 0).is_err());
202 }
203
204 #[test]
205 fn test_padded_size() {
206 assert_eq!(padded_size(5, 4), 8);
208 assert_eq!(padded_size(8, 4), 8);
209 }
210}