mod reflection_generated;
mod reflection_verifier;
mod safe_buffer;
mod r#struct;
pub use crate::r#struct::Struct;
pub use crate::reflection_generated::reflection;
pub use crate::safe_buffer::SafeBuffer;
use flatbuffers::{
emplace_scalar, read_scalar, EndianScalar, Follow, ForwardsUOffset, InvalidFlatbuffer,
SOffsetT, Table, UOffsetT, VOffsetT, Vector, SIZE_SOFFSET, SIZE_UOFFSET,
};
use reflection_generated::reflection::{BaseType, Field, Object, Schema};
use core::mem::size_of;
use num_traits::float::Float;
use num_traits::int::PrimInt;
use num_traits::FromPrimitive;
use thiserror::Error;
#[derive(Error, Debug, PartialEq)]
pub enum FlatbufferError {
#[error(transparent)]
VerificationError(#[from] flatbuffers::InvalidFlatbuffer),
#[error("Failed to convert between data type {0} and field type {1}")]
FieldTypeMismatch(String, String),
#[error("Set field value not supported for non-populated or non-scalar fields")]
SetValueNotSupported,
#[error(transparent)]
ParseFloatError(#[from] std::num::ParseFloatError),
#[error(transparent)]
TryFromIntError(#[from] std::num::TryFromIntError),
#[error("Couldn't set string because cache vector is polluted")]
SetStringPolluted,
#[error("Invalid schema: Polluted buffer or the schema doesn't match the buffer.")]
InvalidSchema,
#[error("Type not supported: {0}")]
TypeNotSupported(String),
#[error("No type or invalid type found in union enum")]
InvalidUnionEnum,
#[error("Table or Struct doesn't belong to the buffer")]
InvalidTableOrStruct,
#[error("Field not found in the table schema")]
FieldNotFound,
}
pub type FlatbufferResult<T, E = FlatbufferError> = core::result::Result<T, E>;
pub unsafe fn get_any_root(data: &[u8]) -> Table {
<ForwardsUOffset<Table>>::follow(data, 0)
}
pub unsafe fn get_field_integer<T: for<'a> Follow<'a, Inner = T> + PrimInt + FromPrimitive>(
table: &Table,
field: &Field,
) -> FlatbufferResult<Option<T>> {
if size_of::<T>() != get_type_size(field.type_().base_type()) {
return Err(FlatbufferError::FieldTypeMismatch(
std::any::type_name::<T>().to_string(),
field
.type_()
.base_type()
.variant_name()
.unwrap_or_default()
.to_string(),
));
}
let default = T::from_i64(field.default_integer());
Ok(table.get::<T>(field.offset(), default))
}
pub unsafe fn get_field_float<T: for<'a> Follow<'a, Inner = T> + Float>(
table: &Table,
field: &Field,
) -> FlatbufferResult<Option<T>> {
if size_of::<T>() != get_type_size(field.type_().base_type()) {
return Err(FlatbufferError::FieldTypeMismatch(
std::any::type_name::<T>().to_string(),
field
.type_()
.base_type()
.variant_name()
.unwrap_or_default()
.to_string(),
));
}
let default = T::from(field.default_real());
Ok(table.get::<T>(field.offset(), default))
}
pub unsafe fn get_field_string<'a>(
table: &Table<'a>,
field: &Field,
) -> FlatbufferResult<Option<&'a str>> {
if field.type_().base_type() != BaseType::String {
return Err(FlatbufferError::FieldTypeMismatch(
String::from("String"),
field
.type_()
.base_type()
.variant_name()
.unwrap_or_default()
.to_string(),
));
}
Ok(table.get::<ForwardsUOffset<&'a str>>(field.offset(), Some("")))
}
pub unsafe fn get_field_struct<'a>(
table: &Table<'a>,
field: &Field,
) -> FlatbufferResult<Option<Struct<'a>>> {
if field.type_().base_type() != BaseType::Obj {
return Err(FlatbufferError::FieldTypeMismatch(
String::from("Obj"),
field
.type_()
.base_type()
.variant_name()
.unwrap_or_default()
.to_string(),
));
}
Ok(table.get::<Struct>(field.offset(), None))
}
pub unsafe fn get_field_vector<'a, T: Follow<'a, Inner = T>>(
table: &Table<'a>,
field: &Field,
) -> FlatbufferResult<Option<Vector<'a, T>>> {
if field.type_().base_type() != BaseType::Vector {
return Err(FlatbufferError::FieldTypeMismatch(
std::any::type_name::<T>().to_string(),
field
.type_()
.base_type()
.variant_name()
.unwrap_or_default()
.to_string(),
));
}
Ok(table.get::<ForwardsUOffset<Vector<'a, T>>>(field.offset(), Some(Vector::<T>::default())))
}
pub unsafe fn get_field_table<'a>(
table: &Table<'a>,
field: &Field,
) -> FlatbufferResult<Option<Table<'a>>> {
if field.type_().base_type() != BaseType::Obj {
return Err(FlatbufferError::FieldTypeMismatch(
String::from("Obj"),
field
.type_()
.base_type()
.variant_name()
.unwrap_or_default()
.to_string(),
));
}
Ok(table.get::<ForwardsUOffset<Table<'a>>>(field.offset(), None))
}
pub unsafe fn get_any_field_integer(table: &Table, field: &Field) -> FlatbufferResult<i64> {
if let Some(field_loc) = get_field_loc(table, field) {
get_any_value_integer(field.type_().base_type(), table.buf(), field_loc)
} else {
Ok(field.default_integer())
}
}
pub unsafe fn get_any_field_float(table: &Table, field: &Field) -> FlatbufferResult<f64> {
if let Some(field_loc) = get_field_loc(table, field) {
get_any_value_float(field.type_().base_type(), table.buf(), field_loc)
} else {
Ok(field.default_real())
}
}
pub unsafe fn get_any_field_string(table: &Table, field: &Field, schema: &Schema) -> String {
if let Some(field_loc) = get_field_loc(table, field) {
get_any_value_string(
field.type_().base_type(),
table.buf(),
field_loc,
schema,
field.type_().index() as usize,
)
} else {
String::from("")
}
}
pub unsafe fn get_field_struct_in_struct<'a>(
st: &Struct<'a>,
field: &Field,
) -> FlatbufferResult<Struct<'a>> {
if field.type_().base_type() != BaseType::Obj {
return Err(FlatbufferError::FieldTypeMismatch(
String::from("Obj"),
field
.type_()
.base_type()
.variant_name()
.unwrap_or_default()
.to_string(),
));
}
Ok(st.get::<Struct>(field.offset() as usize))
}
pub unsafe fn get_any_field_integer_in_struct(st: &Struct, field: &Field) -> FlatbufferResult<i64> {
let field_loc = st.loc() + field.offset() as usize;
get_any_value_integer(field.type_().base_type(), st.buf(), field_loc)
}
pub unsafe fn get_any_field_float_in_struct(st: &Struct, field: &Field) -> FlatbufferResult<f64> {
let field_loc = st.loc() + field.offset() as usize;
get_any_value_float(field.type_().base_type(), st.buf(), field_loc)
}
pub unsafe fn get_any_field_string_in_struct(
st: &Struct,
field: &Field,
schema: &Schema,
) -> String {
let field_loc = st.loc() + field.offset() as usize;
get_any_value_string(
field.type_().base_type(),
st.buf(),
field_loc,
schema,
field.type_().index() as usize,
)
}
pub unsafe fn set_any_field_integer(
buf: &mut [u8],
table_loc: usize,
field: &Field,
v: i64,
) -> FlatbufferResult<()> {
let field_type = field.type_().base_type();
let table = Table::follow(buf, table_loc);
let Some(field_loc) = get_field_loc(&table, field) else {
return Err(FlatbufferError::SetValueNotSupported);
};
if !is_scalar(field_type) {
return Err(FlatbufferError::SetValueNotSupported);
}
set_any_value_integer(field_type, buf, field_loc, v)
}
pub unsafe fn set_any_field_float(
buf: &mut [u8],
table_loc: usize,
field: &Field,
v: f64,
) -> FlatbufferResult<()> {
let field_type = field.type_().base_type();
let table = Table::follow(buf, table_loc);
let Some(field_loc) = get_field_loc(&table, field) else {
return Err(FlatbufferError::SetValueNotSupported);
};
if !is_scalar(field_type) {
return Err(FlatbufferError::SetValueNotSupported);
}
set_any_value_float(field_type, buf, field_loc, v)
}
pub unsafe fn set_any_field_string(
buf: &mut [u8],
table_loc: usize,
field: &Field,
v: &str,
) -> FlatbufferResult<()> {
let field_type = field.type_().base_type();
let table = Table::follow(buf, table_loc);
let Some(field_loc) = get_field_loc(&table, field) else {
return Err(FlatbufferError::SetValueNotSupported);
};
if !is_scalar(field_type) {
return Err(FlatbufferError::SetValueNotSupported);
}
set_any_value_float(field_type, buf, field_loc, v.parse::<f64>()?)
}
pub unsafe fn set_field<T: EndianScalar>(
buf: &mut [u8],
table_loc: usize,
field: &Field,
v: T,
) -> FlatbufferResult<()> {
let field_type = field.type_().base_type();
let table = Table::follow(buf, table_loc);
if !is_scalar(field_type) {
return Err(FlatbufferError::SetValueNotSupported);
}
if core::mem::size_of::<T>() != get_type_size(field_type) {
return Err(FlatbufferError::FieldTypeMismatch(
std::any::type_name::<T>().to_string(),
field_type.variant_name().unwrap_or_default().to_string(),
));
}
let Some(field_loc) = get_field_loc(&table, field) else {
return Err(FlatbufferError::SetValueNotSupported);
};
if buf.len() < field_loc.saturating_add(get_type_size(field_type)) {
return Err(FlatbufferError::VerificationError(
InvalidFlatbuffer::RangeOutOfBounds {
range: core::ops::Range {
start: field_loc,
end: field_loc.saturating_add(get_type_size(field_type)),
},
error_trace: Default::default(),
},
));
}
unsafe { Ok(emplace_scalar::<T>(&mut buf[field_loc..], v)) }
}
pub unsafe fn set_string(
buf: &mut Vec<u8>,
table_loc: usize,
field: &Field,
v: &str,
schema: &Schema,
) -> FlatbufferResult<()> {
if v.is_empty() {
return Ok(());
}
let field_type = field.type_().base_type();
if field_type != BaseType::String {
return Err(FlatbufferError::FieldTypeMismatch(
String::from("String"),
field_type.variant_name().unwrap_or_default().to_string(),
));
}
let table = Table::follow(buf, table_loc);
let Some(field_loc) = get_field_loc(&table, field) else {
return Err(FlatbufferError::SetValueNotSupported);
};
if buf.len() < field_loc + get_type_size(field_type) {
return Err(FlatbufferError::VerificationError(
InvalidFlatbuffer::RangeOutOfBounds {
range: core::ops::Range {
start: field_loc,
end: field_loc.saturating_add(get_type_size(field_type)),
},
error_trace: Default::default(),
},
));
}
let string_loc = unsafe { deref_uoffset(buf, field_loc)? };
if buf.len() < string_loc.saturating_add(SIZE_UOFFSET) {
return Err(FlatbufferError::VerificationError(
InvalidFlatbuffer::RangeOutOfBounds {
range: core::ops::Range {
start: string_loc,
end: string_loc.saturating_add(SIZE_UOFFSET),
},
error_trace: Default::default(),
},
));
}
let len_old = unsafe { read_uoffset(buf, string_loc) };
if buf.len()
< string_loc
.saturating_add(SIZE_UOFFSET)
.saturating_add(len_old.try_into()?)
{
return Err(FlatbufferError::VerificationError(
InvalidFlatbuffer::RangeOutOfBounds {
range: core::ops::Range {
start: string_loc,
end: string_loc
.saturating_add(SIZE_UOFFSET)
.saturating_add(len_old.try_into()?),
},
error_trace: Default::default(),
},
));
}
let len_new = v.len();
let delta = len_new as isize - len_old as isize;
let mut bytes_to_insert = v.as_bytes().to_vec();
if delta != 0 {
let mask = (size_of::<core::ffi::c_long>() - 1) as isize;
let offset = (delta + mask) & !mask;
let mut visited_vec = vec![false; buf.len()];
if offset != 0 {
update_offset(
buf,
table_loc,
&mut visited_vec,
&schema.root_table().unwrap(),
schema,
string_loc,
offset,
)?;
emplace_scalar::<SOffsetT>(
&mut buf[string_loc..string_loc + SIZE_UOFFSET],
len_new.try_into()?,
);
}
bytes_to_insert.resize(bytes_to_insert.len() + (offset - delta) as usize, 0);
}
buf.splice(
string_loc + SIZE_SOFFSET..string_loc + SIZE_UOFFSET + usize::try_from(len_old)?,
bytes_to_insert,
);
Ok(())
}
fn get_type_size(base_type: BaseType) -> usize {
match base_type {
BaseType::UType | BaseType::Bool | BaseType::Byte | BaseType::UByte => 1,
BaseType::Short | BaseType::UShort => 2,
BaseType::Int
| BaseType::UInt
| BaseType::Float
| BaseType::String
| BaseType::Vector
| BaseType::Obj
| BaseType::Union => 4,
BaseType::Long | BaseType::ULong | BaseType::Double | BaseType::Vector64 => 8,
_ => 0,
}
}
unsafe fn get_field_loc(table: &Table, field: &Field) -> Option<usize> {
let field_offset = table.vtable().get(field.offset()) as usize;
if field_offset == 0 {
return None;
}
Some(table.loc() + field_offset)
}
unsafe fn get_any_value_integer(
base_type: BaseType,
buf: &[u8],
loc: usize,
) -> FlatbufferResult<i64> {
match base_type {
BaseType::UType | BaseType::UByte => i64::from_u8(u8::follow(buf, loc)),
BaseType::Bool => bool::follow(buf, loc).try_into().ok(),
BaseType::Byte => i64::from_i8(i8::follow(buf, loc)),
BaseType::Short => i64::from_i16(i16::follow(buf, loc)),
BaseType::UShort => i64::from_u16(u16::follow(buf, loc)),
BaseType::Int => i64::from_i32(i32::follow(buf, loc)),
BaseType::UInt => i64::from_u32(u32::follow(buf, loc)),
BaseType::Long => Some(i64::follow(buf, loc)),
BaseType::ULong => i64::from_u64(u64::follow(buf, loc)),
BaseType::Float => i64::from_f32(f32::follow(buf, loc)),
BaseType::Double => i64::from_f64(f64::follow(buf, loc)),
BaseType::String => ForwardsUOffset::<&str>::follow(buf, loc)
.parse::<i64>()
.ok(),
_ => None, }
.ok_or(FlatbufferError::FieldTypeMismatch(
String::from("i64"),
base_type.variant_name().unwrap_or_default().to_string(),
))
}
unsafe fn get_any_value_float(
base_type: BaseType,
buf: &[u8],
loc: usize,
) -> FlatbufferResult<f64> {
match base_type {
BaseType::UType | BaseType::UByte => f64::from_u8(u8::follow(buf, loc)),
BaseType::Bool => bool::follow(buf, loc).try_into().ok(),
BaseType::Byte => f64::from_i8(i8::follow(buf, loc)),
BaseType::Short => f64::from_i16(i16::follow(buf, loc)),
BaseType::UShort => f64::from_u16(u16::follow(buf, loc)),
BaseType::Int => f64::from_i32(i32::follow(buf, loc)),
BaseType::UInt => f64::from_u32(u32::follow(buf, loc)),
BaseType::Long => f64::from_i64(i64::follow(buf, loc)),
BaseType::ULong => f64::from_u64(u64::follow(buf, loc)),
BaseType::Float => f64::from_f32(f32::follow(buf, loc)),
BaseType::Double => Some(f64::follow(buf, loc)),
BaseType::String => ForwardsUOffset::<&str>::follow(buf, loc)
.parse::<f64>()
.ok(),
_ => None,
}
.ok_or(FlatbufferError::FieldTypeMismatch(
String::from("f64"),
base_type.variant_name().unwrap_or_default().to_string(),
))
}
unsafe fn get_any_value_string(
base_type: BaseType,
buf: &[u8],
loc: usize,
schema: &Schema,
type_index: usize,
) -> String {
match base_type {
BaseType::Float | BaseType::Double => get_any_value_float(base_type, buf, loc)
.unwrap_or_default()
.to_string(),
BaseType::String => {
String::from_utf8_lossy(ForwardsUOffset::<&[u8]>::follow(buf, loc)).to_string()
}
BaseType::Obj => {
let object: Object = schema.objects().get(type_index);
let mut s = object.name().to_string();
s += " { ";
if object.is_struct() {
let st: Struct<'_> = Struct::follow(buf, loc);
for field in object.fields() {
let field_value = get_any_field_string_in_struct(&st, &field, schema);
s += field.name();
s += ": ";
s += field_value.as_str();
s += ", ";
}
} else {
let table = ForwardsUOffset::<Table>::follow(buf, loc);
for field in object.fields() {
if table.vtable().get(field.offset()) == 0 {
continue;
}
let mut field_value = get_any_field_string(&table, &field, schema);
if field.type_().base_type() == BaseType::String {
field_value = format!("{:?}", field_value.as_str());
}
s += field.name();
s += ": ";
s += field_value.as_str();
s += ", ";
}
}
s + "}"
}
BaseType::Vector => String::from("[(elements)]"), BaseType::Union => String::from("(union)"), _ => get_any_value_integer(base_type, buf, loc)
.unwrap_or_default()
.to_string(),
}
}
fn set_any_value_integer(
base_type: BaseType,
buf: &mut [u8],
field_loc: usize,
v: i64,
) -> FlatbufferResult<()> {
if buf.len() < get_type_size(base_type) {
return Err(FlatbufferError::VerificationError(
InvalidFlatbuffer::RangeOutOfBounds {
range: core::ops::Range {
start: field_loc,
end: field_loc.saturating_add(get_type_size(base_type)),
},
error_trace: Default::default(),
},
));
}
let buf = &mut buf[field_loc..];
let type_name = base_type.variant_name().unwrap_or_default().to_string();
macro_rules! try_emplace {
($ty:ty, $value:expr) => {
if let Ok(v) = TryInto::<$ty>::try_into($value) {
unsafe { Ok(emplace_scalar::<$ty>(buf, v)) }
} else {
Err(FlatbufferError::FieldTypeMismatch(
String::from("i64"),
type_name,
))
}
};
}
match base_type {
BaseType::UType | BaseType::UByte => {
try_emplace!(u8, v)
}
BaseType::Bool => {
unsafe { Ok(emplace_scalar::<bool>(buf, v != 0)) }
}
BaseType::Byte => {
try_emplace!(i8, v)
}
BaseType::Short => {
try_emplace!(i16, v)
}
BaseType::UShort => {
try_emplace!(u16, v)
}
BaseType::Int => {
try_emplace!(i32, v)
}
BaseType::UInt => {
try_emplace!(u32, v)
}
BaseType::Long => {
unsafe { Ok(emplace_scalar::<i64>(buf, v)) }
}
BaseType::ULong => {
try_emplace!(u64, v)
}
BaseType::Float => {
if let Some(value) = f32::from_i64(v) {
unsafe { Ok(emplace_scalar::<f32>(buf, value)) }
} else {
Err(FlatbufferError::FieldTypeMismatch(
String::from("i64"),
type_name,
))
}
}
BaseType::Double => {
if let Some(value) = f64::from_i64(v) {
unsafe { Ok(emplace_scalar::<f64>(buf, value)) }
} else {
Err(FlatbufferError::FieldTypeMismatch(
String::from("i64"),
type_name,
))
}
}
_ => Err(FlatbufferError::SetValueNotSupported),
}
}
fn set_any_value_float(
base_type: BaseType,
buf: &mut [u8],
field_loc: usize,
v: f64,
) -> FlatbufferResult<()> {
if buf.len() < get_type_size(base_type) {
return Err(FlatbufferError::VerificationError(
InvalidFlatbuffer::RangeOutOfBounds {
range: core::ops::Range {
start: field_loc,
end: field_loc.saturating_add(get_type_size(base_type)),
},
error_trace: Default::default(),
},
));
}
let buf = &mut buf[field_loc..];
let type_name = base_type.variant_name().unwrap_or_default().to_string();
match base_type {
BaseType::UType | BaseType::UByte => {
if let Some(value) = u8::from_f64(v) {
unsafe {
return Ok(emplace_scalar::<u8>(buf, value));
}
}
}
BaseType::Bool => {
unsafe {
return Ok(emplace_scalar::<bool>(buf, v != 0f64));
}
}
BaseType::Byte => {
if let Some(value) = i8::from_f64(v) {
unsafe {
return Ok(emplace_scalar::<i8>(buf, value));
}
}
}
BaseType::Short => {
if let Some(value) = i16::from_f64(v) {
unsafe {
return Ok(emplace_scalar::<i16>(buf, value));
}
}
}
BaseType::UShort => {
if let Some(value) = u16::from_f64(v) {
unsafe {
return Ok(emplace_scalar::<u16>(buf, value));
}
}
}
BaseType::Int => {
if let Some(value) = i32::from_f64(v) {
unsafe {
return Ok(emplace_scalar::<i32>(buf, value));
}
}
}
BaseType::UInt => {
if let Some(value) = u32::from_f64(v) {
unsafe {
return Ok(emplace_scalar::<u32>(buf, value));
}
}
}
BaseType::Long => {
if let Some(value) = i64::from_f64(v) {
unsafe {
return Ok(emplace_scalar::<i64>(buf, value));
}
}
}
BaseType::ULong => {
if let Some(value) = u64::from_f64(v) {
unsafe {
return Ok(emplace_scalar::<u64>(buf, value));
}
}
}
BaseType::Float => {
if let Some(value) = f32::from_f64(v) {
if value != f32::INFINITY {
unsafe {
return Ok(emplace_scalar::<f32>(buf, value));
}
}
}
}
BaseType::Double => {
unsafe {
return Ok(emplace_scalar::<f64>(buf, v));
}
}
_ => return Err(FlatbufferError::SetValueNotSupported),
}
return Err(FlatbufferError::FieldTypeMismatch(
String::from("f64"),
type_name,
));
}
fn is_scalar(base_type: BaseType) -> bool {
return base_type <= BaseType::Double;
}
unsafe fn update_offset(
buf: &mut [u8],
table_loc: usize,
updated: &mut [bool],
object: &Object,
schema: &Schema,
insertion_loc: usize,
offset: isize,
) -> FlatbufferResult<()> {
if updated.len() != buf.len() {
return Err(FlatbufferError::SetStringPolluted);
}
if updated[table_loc] {
return Ok(());
}
let slice = &mut buf[table_loc..table_loc + SIZE_SOFFSET];
let vtable_offset = isize::try_from(read_scalar::<SOffsetT>(slice))?;
let vtable_loc = (isize::try_from(table_loc)? - vtable_offset).try_into()?;
if insertion_loc <= table_loc {
if (vtable_loc..table_loc).contains(&insertion_loc) {
emplace_scalar::<SOffsetT>(slice, (vtable_offset + offset).try_into()?);
updated[table_loc] = true;
}
return Ok(());
}
for field in object.fields() {
let field_type = field.type_().base_type();
if is_scalar(field_type) {
continue;
}
let field_offset = VOffsetT::follow(buf, vtable_loc.saturating_add(field.offset().into()));
if field_offset == 0 {
continue;
}
let field_loc = table_loc + usize::from(field_offset);
if updated[field_loc] {
continue;
}
if field_type == BaseType::Obj
&& schema
.objects()
.get(field.type_().index().try_into()?)
.is_struct()
{
continue;
}
let slice = &mut buf[field_loc..field_loc + SIZE_UOFFSET];
let field_value_offset = read_scalar::<UOffsetT>(slice);
let field_value_loc = field_loc.saturating_add(field_value_offset.try_into()?);
if (field_loc..field_value_loc).contains(&insertion_loc) {
emplace_scalar::<UOffsetT>(
slice,
(isize::try_from(field_value_offset)? + offset).try_into()?,
);
updated[field_loc] = true;
}
match field_type {
BaseType::Obj => {
let field_obj = schema.objects().get(field.type_().index().try_into()?);
update_offset(
buf,
field_value_loc,
updated,
&field_obj,
schema,
insertion_loc,
offset,
)?;
}
BaseType::Vector => {
let elem_type = field.type_().element();
if elem_type != BaseType::Obj || elem_type != BaseType::String {
continue;
}
if elem_type == BaseType::Obj
&& schema
.objects()
.get(field.type_().index().try_into()?)
.is_struct()
{
continue;
}
let vec_size = usize::try_from(read_uoffset(buf, field_value_loc))?;
for index in 0..vec_size {
let elem_loc = field_value_loc + SIZE_UOFFSET + index * SIZE_UOFFSET;
if updated[elem_loc] {
continue;
}
let slice = &mut buf[elem_loc..elem_loc + SIZE_UOFFSET];
let elem_value_offset = read_scalar::<UOffsetT>(slice);
let elem_value_loc = elem_loc.saturating_add(elem_value_offset.try_into()?);
if (elem_loc..elem_value_loc).contains(&insertion_loc) {
emplace_scalar::<UOffsetT>(
slice,
(isize::try_from(elem_value_offset)? + offset).try_into()?,
);
updated[elem_loc] = true;
}
if elem_type == BaseType::Obj {
let elem_obj = schema.objects().get(field.type_().index().try_into()?);
update_offset(
buf,
elem_value_loc,
updated,
&elem_obj,
schema,
insertion_loc,
offset,
)?;
}
}
}
BaseType::Union => {
let union_enum = schema.enums().get(field.type_().index().try_into()?);
let union_type = object
.fields()
.lookup_by_key(field.name().to_string() + "_type", |field, key| {
field.key_compare_with_value(key)
})
.unwrap();
let union_type_loc = vtable_loc.saturating_add(union_type.offset().into());
let union_type_offset = VOffsetT::follow(buf, union_type_loc);
let union_type_value =
u8::follow(buf, table_loc.saturating_add(union_type_offset.into()));
let union_enum_value = union_enum
.values()
.lookup_by_key(union_type_value.into(), |value, key| {
value.key_compare_with_value(*key)
})
.unwrap();
let union_object = schema
.objects()
.get(union_enum_value.union_type().unwrap().index().try_into()?);
update_offset(
buf,
field_value_loc,
updated,
&union_object,
schema,
insertion_loc,
offset,
)?;
}
_ => (),
}
}
if (table_loc..vtable_loc).contains(&insertion_loc) {
let slice = &mut buf[table_loc..table_loc + SIZE_SOFFSET];
emplace_scalar::<SOffsetT>(slice, (vtable_offset - offset).try_into()?);
updated[table_loc] = true;
}
Ok(())
}
unsafe fn deref_uoffset(buf: &[u8], field_loc: usize) -> FlatbufferResult<usize> {
Ok(field_loc.saturating_add(read_uoffset(buf, field_loc).try_into()?))
}
unsafe fn read_uoffset(buf: &[u8], loc: usize) -> UOffsetT {
let slice = &buf[loc..loc + SIZE_UOFFSET];
read_scalar::<UOffsetT>(slice)
}