• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2025 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 use crate::r#struct::Struct;
18 use crate::reflection_generated::reflection::{Field, Schema};
19 use crate::reflection_verifier::verify_with_options;
20 use 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 };
27 use flatbuffers::{Follow, Table, Vector, VerifierOptions};
28 use num_traits::float::Float;
29 use num_traits::int::PrimInt;
30 use num_traits::FromPrimitive;
31 use std::collections::HashMap;
32 
33 #[derive(Debug)]
34 pub struct SafeBuffer<'a> {
35     buf: &'a [u8],
36     schema: &'a Schema<'a>,
37     buf_loc_to_obj_idx: HashMap<usize, i32>,
38 }
39 
40 impl<'a> SafeBuffer<'a> {
new(buf: &'a [u8], schema: &'a Schema) -> FlatbufferResult<Self>41     pub fn new(buf: &'a [u8], schema: &'a Schema) -> FlatbufferResult<Self> {
42         Self::new_with_options(buf, schema, &VerifierOptions::default())
43     }
44 
new_with_options( buf: &'a [u8], schema: &'a Schema, opts: &VerifierOptions, ) -> FlatbufferResult<Self>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     /// Gets the root table in the buffer.
get_root(&self) -> SafeTable60     pub fn get_root(&self) -> SafeTable {
61         // SAFETY: the buffer was verified during construction.
62         let table = unsafe { get_any_root(self.buf) };
63 
64         SafeTable {
65             safe_buf: self,
66             loc: table.loc(),
67         }
68     }
69 
find_field_by_name( &self, buf_loc: usize, field_name: &str, ) -> FlatbufferResult<Option<Field>>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 
get_all_fields(&self, buf_loc: usize) -> FlatbufferResult<Vector<ForwardsUOffset<Field>>>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)]
97 pub struct SafeTable<'a> {
98     safe_buf: &'a SafeBuffer<'a>,
99     loc: usize,
100 }
101 
102 impl<'a> SafeTable<'a> {
103     /// Gets an integer table field given its exact type. Returns default integer value if the field is not set. Returns [None] if no default value is found. Returns error if
104     /// the table doesn't match the buffer or
105     /// the [field_name] doesn't match the table or
106     /// the field type doesn't match.
get_field_integer<T: for<'b> Follow<'b, Inner = T> + PrimInt + FromPrimitive>( &self, field_name: &str, ) -> FlatbufferResult<Option<T>>107     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             // SAFETY: the buffer was verified during construction.
113             unsafe { get_field_integer::<T>(&Table::new(&self.safe_buf.buf, self.loc), &field) }
114         } else {
115             Err(FlatbufferError::FieldNotFound)
116         }
117     }
118 
119     /// Gets a floating point table field given its exact type. Returns default float value if the field is not set. Returns [None] if no default value is found. Returns error if
120     /// the table doesn't match the buffer or
121     /// the [field_name] doesn't match the table or
122     /// the field type doesn't match.
get_field_float<T: for<'b> Follow<'b, Inner = T> + Float>( &self, field_name: &str, ) -> FlatbufferResult<Option<T>>123     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             // SAFETY: the buffer was verified during construction.
129             unsafe { get_field_float::<T>(&Table::new(&self.safe_buf.buf, self.loc), &field) }
130         } else {
131             Err(FlatbufferError::FieldNotFound)
132         }
133     }
134 
135     /// Gets a String table field given its exact type. Returns empty string if the field is not set. Returns [None] if no default value is found. Returns error if
136     /// the table doesn't match the buffer or
137     /// the [field_name] doesn't match the table or
138     /// the field type doesn't match.
get_field_string(&self, field_name: &str) -> FlatbufferResult<Option<&str>>139     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             // SAFETY: the buffer was verified during construction.
142             unsafe { get_field_string(&Table::new(&self.safe_buf.buf, self.loc), &field) }
143         } else {
144             Err(FlatbufferError::FieldNotFound)
145         }
146     }
147 
148     /// Gets a [SafeStruct] table field given its exact type. Returns [None] if the field is not set. Returns error if
149     /// the table doesn't match the buffer or
150     /// the [field_name] doesn't match the table or
151     /// the field type doesn't match.
get_field_struct(&self, field_name: &str) -> FlatbufferResult<Option<SafeStruct<'a>>>152     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             // SAFETY: the buffer was verified during construction.
155             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     /// Gets a Vector table field given its exact type. Returns empty vector if the field is not set. Returns error if
167     /// the table doesn't match the buffer or
168     /// the [field_name] doesn't match the table or
169     /// the field type doesn't match.
get_field_vector<T: Follow<'a, Inner = T>>( &self, field_name: &str, ) -> FlatbufferResult<Option<Vector<'a, T>>>170     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             // SAFETY: the buffer was verified during construction.
176             unsafe { get_field_vector(&Table::new(&self.safe_buf.buf, self.loc), &field) }
177         } else {
178             Err(FlatbufferError::FieldNotFound)
179         }
180     }
181 
182     /// Gets a [SafeTable] table field given its exact type. Returns [None] if the field is not set. Returns error if
183     /// the table doesn't match the buffer or
184     /// the [field_name] doesn't match the table or
185     /// the field type doesn't match.
get_field_table(&self, field_name: &str) -> FlatbufferResult<Option<SafeTable<'a>>>186     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             // SAFETY: the buffer was verified during construction.
189             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     /// Returns the value of any table field as a 64-bit int, regardless of what type it is. Returns default integer if the field is not set or error if
201     /// the value cannot be parsed as integer or
202     /// the table doesn't match the buffer or
203     /// the [field_name] doesn't match the table.
204     /// [num_traits](https://docs.rs/num-traits/latest/num_traits/cast/trait.NumCast.html) is used for number casting.
get_any_field_integer(&self, field_name: &str) -> FlatbufferResult<i64>205     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             // SAFETY: the buffer was verified during construction.
208             unsafe { get_any_field_integer(&Table::new(&self.safe_buf.buf, self.loc), &field) }
209         } else {
210             Err(FlatbufferError::FieldNotFound)
211         }
212     }
213 
214     /// Returns the value of any table field as a 64-bit floating point, regardless of what type it is. Returns default float if the field is not set or error if
215     /// the value cannot be parsed as float or
216     /// the table doesn't match the buffer or
217     /// the [field_name] doesn't match the table.
get_any_field_float(&self, field_name: &str) -> FlatbufferResult<f64>218     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             // SAFETY: the buffer was verified during construction.
221             unsafe { get_any_field_float(&Table::new(&self.safe_buf.buf, self.loc), &field) }
222         } else {
223             Err(FlatbufferError::FieldNotFound)
224         }
225     }
226 
227     /// Returns the string representation of any table field value (e.g. integer 123 is returned as "123"), regardless of what type it is. Returns empty string if the field is not set. Returns error if
228     /// the table doesn't match the buffer or
229     /// the [field_name] doesn't match the table.
get_any_field_string(&self, field_name: &str) -> FlatbufferResult<String>230     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             // SAFETY: the buffer was verified during construction.
233             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)]
247 pub struct SafeStruct<'a> {
248     safe_buf: &'a SafeBuffer<'a>,
249     loc: usize,
250 }
251 
252 impl<'a> SafeStruct<'a> {
253     /// Gets a [SafeStruct] struct field given its exact type. Returns error if
254     /// the struct doesn't match the buffer or
255     /// the [field_name] doesn't match the struct or
256     /// the field type doesn't match.
get_field_struct(&self, field_name: &str) -> FlatbufferResult<SafeStruct<'a>>257     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             // SAFETY: the buffer was verified during construction.
260             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     /// Returns the value of any struct field as a 64-bit int, regardless of what type it is. Returns error if
273     /// the struct doesn't match the buffer or
274     /// the [field_name] doesn't match the struct or
275     /// the value cannot be parsed as integer.
get_any_field_integer(&self, field_name: &str) -> FlatbufferResult<i64>276     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             // SAFETY: the buffer was verified during construction.
279             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     /// Returns the value of any struct field as a 64-bit floating point, regardless of what type it is. Returns error if
288     /// the struct doesn't match the buffer or
289     /// the [field_name] doesn't match the struct or
290     /// the value cannot be parsed as float.
get_any_field_float(&self, field_name: &str) -> FlatbufferResult<f64>291     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             // SAFETY: the buffer was verified during construction.
294             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     /// Returns the string representation of any struct field value (e.g. integer 123 is returned as "123"), regardless of what type it is. Returns error if
303     /// the struct doesn't match the buffer or
304     /// the [field_name] doesn't match the struct.
get_any_field_string(&self, field_name: &str) -> FlatbufferResult<String>305     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             // SAFETY: the buffer was verified during construction.
308             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 }
320