1use crate::r#struct::Struct;
18use crate::reflection_generated::reflection::{Field, Schema};
19use crate::reflection_verifier::verify_with_options;
20use crate::{
21 get_any_field_float, get_any_field_float_in_struct, get_any_field_integer,
22 get_any_field_integer_in_struct, get_any_field_string, get_any_field_string_in_struct,
23 get_any_root, get_field_float, get_field_integer, get_field_string, get_field_struct,
24 get_field_struct_in_struct, get_field_table, get_field_vector, FlatbufferError,
25 FlatbufferResult, ForwardsUOffset,
26};
27use flatbuffers::{Follow, Table, Vector, VerifierOptions};
28use num_traits::float::Float;
29use num_traits::int::PrimInt;
30use num_traits::FromPrimitive;
31use std::collections::HashMap;
32
33#[derive(Debug)]
34pub struct SafeBuffer<'a> {
35 buf: &'a [u8],
36 schema: &'a Schema<'a>,
37 buf_loc_to_obj_idx: HashMap<usize, i32>,
38}
39
40impl<'a> SafeBuffer<'a> {
41 pub fn new(buf: &'a [u8], schema: &'a Schema) -> FlatbufferResult<Self> {
42 Self::new_with_options(buf, schema, &VerifierOptions::default())
43 }
44
45 pub fn new_with_options(
46 buf: &'a [u8],
47 schema: &'a Schema,
48 opts: &VerifierOptions,
49 ) -> FlatbufferResult<Self> {
50 let mut buf_loc_to_obj_idx = HashMap::new();
51 verify_with_options(&buf, schema, opts, &mut buf_loc_to_obj_idx)?;
52 Ok(SafeBuffer {
53 buf,
54 schema,
55 buf_loc_to_obj_idx,
56 })
57 }
58
59 pub fn get_root(&self) -> SafeTable {
61 let table = unsafe { get_any_root(self.buf) };
63
64 SafeTable {
65 safe_buf: self,
66 loc: table.loc(),
67 }
68 }
69
70 fn find_field_by_name(
71 &self,
72 buf_loc: usize,
73 field_name: &str,
74 ) -> FlatbufferResult<Option<Field>> {
75 Ok(self
76 .get_all_fields(buf_loc)?
77 .lookup_by_key(field_name, |field: &Field<'_>, key| {
78 field.key_compare_with_value(key)
79 }))
80 }
81
82 fn get_all_fields(&self, buf_loc: usize) -> FlatbufferResult<Vector<ForwardsUOffset<Field>>> {
83 if let Some(&obj_idx) = self.buf_loc_to_obj_idx.get(&buf_loc) {
84 let obj = if obj_idx == -1 {
85 self.schema.root_table().unwrap()
86 } else {
87 self.schema.objects().get(obj_idx.try_into()?)
88 };
89 Ok(obj.fields())
90 } else {
91 Err(FlatbufferError::InvalidTableOrStruct)
92 }
93 }
94}
95
96#[derive(Debug)]
97pub struct SafeTable<'a> {
98 safe_buf: &'a SafeBuffer<'a>,
99 loc: usize,
100}
101
102impl<'a> SafeTable<'a> {
103 pub fn get_field_integer<T: for<'b> Follow<'b, Inner = T> + PrimInt + FromPrimitive>(
108 &self,
109 field_name: &str,
110 ) -> FlatbufferResult<Option<T>> {
111 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
112 unsafe { get_field_integer::<T>(&Table::new(&self.safe_buf.buf, self.loc), &field) }
114 } else {
115 Err(FlatbufferError::FieldNotFound)
116 }
117 }
118
119 pub fn get_field_float<T: for<'b> Follow<'b, Inner = T> + Float>(
124 &self,
125 field_name: &str,
126 ) -> FlatbufferResult<Option<T>> {
127 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
128 unsafe { get_field_float::<T>(&Table::new(&self.safe_buf.buf, self.loc), &field) }
130 } else {
131 Err(FlatbufferError::FieldNotFound)
132 }
133 }
134
135 pub fn get_field_string(&self, field_name: &str) -> FlatbufferResult<Option<&str>> {
140 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
141 unsafe { get_field_string(&Table::new(&self.safe_buf.buf, self.loc), &field) }
143 } else {
144 Err(FlatbufferError::FieldNotFound)
145 }
146 }
147
148 pub fn get_field_struct(&self, field_name: &str) -> FlatbufferResult<Option<SafeStruct<'a>>> {
153 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
154 let optional_st =
156 unsafe { get_field_struct(&Table::new(&self.safe_buf.buf, self.loc), &field)? };
157 Ok(optional_st.map(|st| SafeStruct {
158 safe_buf: self.safe_buf,
159 loc: st.loc(),
160 }))
161 } else {
162 Err(FlatbufferError::FieldNotFound)
163 }
164 }
165
166 pub fn get_field_vector<T: Follow<'a, Inner = T>>(
171 &self,
172 field_name: &str,
173 ) -> FlatbufferResult<Option<Vector<'a, T>>> {
174 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
175 unsafe { get_field_vector(&Table::new(&self.safe_buf.buf, self.loc), &field) }
177 } else {
178 Err(FlatbufferError::FieldNotFound)
179 }
180 }
181
182 pub fn get_field_table(&self, field_name: &str) -> FlatbufferResult<Option<SafeTable<'a>>> {
187 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
188 let optional_table =
190 unsafe { get_field_table(&Table::new(&self.safe_buf.buf, self.loc), &field)? };
191 Ok(optional_table.map(|t| SafeTable {
192 safe_buf: self.safe_buf,
193 loc: t.loc(),
194 }))
195 } else {
196 Err(FlatbufferError::FieldNotFound)
197 }
198 }
199
200 pub fn get_any_field_integer(&self, field_name: &str) -> FlatbufferResult<i64> {
206 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
207 unsafe { get_any_field_integer(&Table::new(&self.safe_buf.buf, self.loc), &field) }
209 } else {
210 Err(FlatbufferError::FieldNotFound)
211 }
212 }
213
214 pub fn get_any_field_float(&self, field_name: &str) -> FlatbufferResult<f64> {
219 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
220 unsafe { get_any_field_float(&Table::new(&self.safe_buf.buf, self.loc), &field) }
222 } else {
223 Err(FlatbufferError::FieldNotFound)
224 }
225 }
226
227 pub fn get_any_field_string(&self, field_name: &str) -> FlatbufferResult<String> {
231 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
232 unsafe {
234 Ok(get_any_field_string(
235 &Table::new(&self.safe_buf.buf, self.loc),
236 &field,
237 self.safe_buf.schema,
238 ))
239 }
240 } else {
241 Err(FlatbufferError::FieldNotFound)
242 }
243 }
244}
245
246#[derive(Debug)]
247pub struct SafeStruct<'a> {
248 safe_buf: &'a SafeBuffer<'a>,
249 loc: usize,
250}
251
252impl<'a> SafeStruct<'a> {
253 pub fn get_field_struct(&self, field_name: &str) -> FlatbufferResult<SafeStruct<'a>> {
258 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
259 let st = unsafe {
261 get_field_struct_in_struct(&Struct::new(&self.safe_buf.buf, self.loc), &field)?
262 };
263 Ok(SafeStruct {
264 safe_buf: self.safe_buf,
265 loc: st.loc(),
266 })
267 } else {
268 Err(FlatbufferError::FieldNotFound)
269 }
270 }
271
272 pub fn get_any_field_integer(&self, field_name: &str) -> FlatbufferResult<i64> {
277 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
278 unsafe {
280 get_any_field_integer_in_struct(&Struct::new(&self.safe_buf.buf, self.loc), &field)
281 }
282 } else {
283 Err(FlatbufferError::FieldNotFound)
284 }
285 }
286
287 pub fn get_any_field_float(&self, field_name: &str) -> FlatbufferResult<f64> {
292 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
293 unsafe {
295 get_any_field_float_in_struct(&Struct::new(&self.safe_buf.buf, self.loc), &field)
296 }
297 } else {
298 Err(FlatbufferError::FieldNotFound)
299 }
300 }
301
302 pub fn get_any_field_string(&self, field_name: &str) -> FlatbufferResult<String> {
306 if let Some(field) = self.safe_buf.find_field_by_name(self.loc, field_name)? {
307 unsafe {
309 Ok(get_any_field_string_in_struct(
310 &Struct::new(&self.safe_buf.buf, self.loc),
311 &field,
312 self.safe_buf.schema,
313 ))
314 }
315 } else {
316 Err(FlatbufferError::FieldNotFound)
317 }
318 }
319}