Bumpt flatbuffers to v24.3.25 version
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
[package]
|
||||
name = "flatbuffers"
|
||||
version = "0.6.0"
|
||||
authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
|
||||
license = "Apache-2.0"
|
||||
description = "Official FlatBuffers Rust runtime library."
|
||||
homepage = "https://google.github.io/flatbuffers/"
|
||||
repository = "https://github.com/google/flatbuffers"
|
||||
keywords = ["flatbuffers", "serialization", "zero-copy"]
|
||||
categories = ["encoding", "data-structures", "memory-management"]
|
||||
|
||||
[dependencies]
|
||||
smallvec = "0.6"
|
||||
@@ -1,701 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
extern crate smallvec;
|
||||
|
||||
use std::cmp::max;
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr::write_bytes;
|
||||
use std::slice::from_raw_parts;
|
||||
|
||||
use endian_scalar::{emplace_scalar, read_scalar_at};
|
||||
use primitives::*;
|
||||
use push::{Push, PushAlignment};
|
||||
use table::Table;
|
||||
use vector::{SafeSliceAccess, Vector};
|
||||
use vtable::{field_index_to_field_offset, VTable};
|
||||
use vtable_writer::VTableWriter;
|
||||
|
||||
pub const N_SMALLVEC_STRING_VECTOR_CAPACITY: usize = 16;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
struct FieldLoc {
|
||||
off: UOffsetT,
|
||||
id: VOffsetT,
|
||||
}
|
||||
|
||||
/// FlatBufferBuilder builds a FlatBuffer through manipulating its internal
|
||||
/// state. It has an owned `Vec<u8>` that grows as needed (up to the hardcoded
|
||||
/// limit of 2GiB, which is set by the FlatBuffers format).
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct FlatBufferBuilder<'fbb> {
|
||||
owned_buf: Vec<u8>,
|
||||
head: usize,
|
||||
|
||||
field_locs: Vec<FieldLoc>,
|
||||
written_vtable_revpos: Vec<UOffsetT>,
|
||||
|
||||
nested: bool,
|
||||
finished: bool,
|
||||
|
||||
min_align: usize,
|
||||
|
||||
_phantom: PhantomData<&'fbb ()>,
|
||||
}
|
||||
|
||||
impl<'fbb> FlatBufferBuilder<'fbb> {
|
||||
/// Create a FlatBufferBuilder that is ready for writing.
|
||||
pub fn new() -> Self {
|
||||
Self::new_with_capacity(0)
|
||||
}
|
||||
|
||||
/// Create a FlatBufferBuilder that is ready for writing, with a
|
||||
/// ready-to-use capacity of the provided size.
|
||||
///
|
||||
/// The maximum valid value is `FLATBUFFERS_MAX_BUFFER_SIZE`.
|
||||
pub fn new_with_capacity(size: usize) -> Self {
|
||||
// we need to check the size here because we create the backing buffer
|
||||
// directly, bypassing the typical way of using grow_owned_buf:
|
||||
assert!(
|
||||
size <= FLATBUFFERS_MAX_BUFFER_SIZE,
|
||||
"cannot initialize buffer bigger than 2 gigabytes"
|
||||
);
|
||||
|
||||
FlatBufferBuilder {
|
||||
owned_buf: vec![0u8; size],
|
||||
head: size,
|
||||
|
||||
field_locs: Vec::new(),
|
||||
written_vtable_revpos: Vec::new(),
|
||||
|
||||
nested: false,
|
||||
finished: false,
|
||||
|
||||
min_align: 0,
|
||||
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset the FlatBufferBuilder internal state. Use this method after a
|
||||
/// call to a `finish` function in order to re-use a FlatBufferBuilder.
|
||||
///
|
||||
/// This function is the only way to reset the `finished` state and start
|
||||
/// again.
|
||||
///
|
||||
/// If you are using a FlatBufferBuilder repeatedly, make sure to use this
|
||||
/// function, because it re-uses the FlatBufferBuilder's existing
|
||||
/// heap-allocated `Vec<u8>` internal buffer. This offers significant speed
|
||||
/// improvements as compared to creating a new FlatBufferBuilder for every
|
||||
/// new object.
|
||||
pub fn reset(&mut self) {
|
||||
// memset only the part of the buffer that could be dirty:
|
||||
{
|
||||
let to_clear = self.owned_buf.len() - self.head;
|
||||
let ptr = (&mut self.owned_buf[self.head..]).as_mut_ptr();
|
||||
unsafe {
|
||||
write_bytes(ptr, 0, to_clear);
|
||||
}
|
||||
}
|
||||
|
||||
self.head = self.owned_buf.len();
|
||||
self.written_vtable_revpos.clear();
|
||||
|
||||
self.nested = false;
|
||||
self.finished = false;
|
||||
|
||||
self.min_align = 0;
|
||||
}
|
||||
|
||||
/// Destroy the FlatBufferBuilder, returning its internal byte vector
|
||||
/// and the index into it that represents the start of valid data.
|
||||
pub fn collapse(self) -> (Vec<u8>, usize) {
|
||||
(self.owned_buf, self.head)
|
||||
}
|
||||
|
||||
/// Push a Push'able value onto the front of the in-progress data.
|
||||
///
|
||||
/// This function uses traits to provide a unified API for writing
|
||||
/// scalars, tables, vectors, and WIPOffsets.
|
||||
#[inline]
|
||||
pub fn push<P: Push>(&mut self, x: P) -> WIPOffset<P::Output> {
|
||||
let sz = P::size();
|
||||
self.align(sz, P::alignment());
|
||||
self.make_space(sz);
|
||||
{
|
||||
let (dst, rest) = (&mut self.owned_buf[self.head..]).split_at_mut(sz);
|
||||
x.push(dst, rest);
|
||||
}
|
||||
WIPOffset::new(self.used_space() as UOffsetT)
|
||||
}
|
||||
|
||||
/// Push a Push'able value onto the front of the in-progress data, and
|
||||
/// store a reference to it in the in-progress vtable. If the value matches
|
||||
/// the default, then this is a no-op.
|
||||
#[inline]
|
||||
pub fn push_slot<X: Push + PartialEq>(&mut self, slotoff: VOffsetT, x: X, default: X) {
|
||||
self.assert_nested("push_slot");
|
||||
if x == default {
|
||||
return;
|
||||
}
|
||||
self.push_slot_always(slotoff, x);
|
||||
}
|
||||
|
||||
/// Push a Push'able value onto the front of the in-progress data, and
|
||||
/// store a reference to it in the in-progress vtable.
|
||||
#[inline]
|
||||
pub fn push_slot_always<X: Push>(&mut self, slotoff: VOffsetT, x: X) {
|
||||
self.assert_nested("push_slot_always");
|
||||
let off = self.push(x);
|
||||
self.track_field(slotoff, off.value());
|
||||
}
|
||||
|
||||
/// Retrieve the number of vtables that have been serialized into the
|
||||
/// FlatBuffer. This is primarily used to check vtable deduplication.
|
||||
#[inline]
|
||||
pub fn num_written_vtables(&self) -> usize {
|
||||
self.written_vtable_revpos.len()
|
||||
}
|
||||
|
||||
/// Start a Table write.
|
||||
///
|
||||
/// Asserts that the builder is not in a nested state.
|
||||
///
|
||||
/// Users probably want to use `push_slot` to add values after calling this.
|
||||
#[inline]
|
||||
pub fn start_table(&mut self) -> WIPOffset<TableUnfinishedWIPOffset> {
|
||||
self.assert_not_nested(
|
||||
"start_table can not be called when a table or vector is under construction",
|
||||
);
|
||||
self.nested = true;
|
||||
|
||||
WIPOffset::new(self.used_space() as UOffsetT)
|
||||
}
|
||||
|
||||
/// End a Table write.
|
||||
///
|
||||
/// Asserts that the builder is in a nested state.
|
||||
#[inline]
|
||||
pub fn end_table(
|
||||
&mut self,
|
||||
off: WIPOffset<TableUnfinishedWIPOffset>,
|
||||
) -> WIPOffset<TableFinishedWIPOffset> {
|
||||
self.assert_nested("end_table");
|
||||
|
||||
let o = self.write_vtable(off);
|
||||
|
||||
self.nested = false;
|
||||
self.field_locs.clear();
|
||||
|
||||
WIPOffset::new(o.value())
|
||||
}
|
||||
|
||||
/// Start a Vector write.
|
||||
///
|
||||
/// Asserts that the builder is not in a nested state.
|
||||
///
|
||||
/// Most users will prefer to call `create_vector`.
|
||||
/// Speed optimizing users who choose to create vectors manually using this
|
||||
/// function will want to use `push` to add values.
|
||||
#[inline]
|
||||
pub fn start_vector<T: Push>(&mut self, num_items: usize) {
|
||||
self.assert_not_nested(
|
||||
"start_vector can not be called when a table or vector is under construction",
|
||||
);
|
||||
self.nested = true;
|
||||
self.align(num_items * T::size(), T::alignment().max_of(SIZE_UOFFSET));
|
||||
}
|
||||
|
||||
/// End a Vector write.
|
||||
///
|
||||
/// Note that the `num_elems` parameter is the number of written items, not
|
||||
/// the byte count.
|
||||
///
|
||||
/// Asserts that the builder is in a nested state.
|
||||
#[inline]
|
||||
pub fn end_vector<T: Push>(&mut self, num_elems: usize) -> WIPOffset<Vector<'fbb, T>> {
|
||||
self.assert_nested("end_vector");
|
||||
self.nested = false;
|
||||
let o = self.push::<UOffsetT>(num_elems as UOffsetT);
|
||||
WIPOffset::new(o.value())
|
||||
}
|
||||
|
||||
/// Create a utf8 string.
|
||||
///
|
||||
/// The wire format represents this as a zero-terminated byte vector.
|
||||
#[inline]
|
||||
pub fn create_string<'a: 'b, 'b>(&'a mut self, s: &'b str) -> WIPOffset<&'fbb str> {
|
||||
self.assert_not_nested(
|
||||
"create_string can not be called when a table or vector is under construction",
|
||||
);
|
||||
WIPOffset::new(self.create_byte_string(s.as_bytes()).value())
|
||||
}
|
||||
|
||||
/// Create a zero-terminated byte vector.
|
||||
#[inline]
|
||||
pub fn create_byte_string(&mut self, data: &[u8]) -> WIPOffset<&'fbb [u8]> {
|
||||
self.assert_not_nested(
|
||||
"create_byte_string can not be called when a table or vector is under construction",
|
||||
);
|
||||
self.align(data.len() + 1, PushAlignment::new(SIZE_UOFFSET));
|
||||
self.push(0u8);
|
||||
self.push_bytes_unprefixed(data);
|
||||
self.push(data.len() as UOffsetT);
|
||||
WIPOffset::new(self.used_space() as UOffsetT)
|
||||
}
|
||||
|
||||
/// Create a vector by memcpy'ing. This is much faster than calling
|
||||
/// `create_vector`, but the underlying type must be represented as
|
||||
/// little-endian on the host machine. This property is encoded in the
|
||||
/// type system through the SafeSliceAccess trait. The following types are
|
||||
/// always safe, on any platform: bool, u8, i8, and any
|
||||
/// FlatBuffers-generated struct.
|
||||
#[inline]
|
||||
pub fn create_vector_direct<'a: 'b, 'b, T: SafeSliceAccess + Push + Sized + 'b>(
|
||||
&'a mut self,
|
||||
items: &'b [T],
|
||||
) -> WIPOffset<Vector<'fbb, T>> {
|
||||
self.assert_not_nested(
|
||||
"create_vector_direct can not be called when a table or vector is under construction",
|
||||
);
|
||||
let elem_size = T::size();
|
||||
self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET));
|
||||
|
||||
let bytes = {
|
||||
let ptr = items.as_ptr() as *const T as *const u8;
|
||||
unsafe { from_raw_parts(ptr, items.len() * elem_size) }
|
||||
};
|
||||
self.push_bytes_unprefixed(bytes);
|
||||
self.push(items.len() as UOffsetT);
|
||||
|
||||
WIPOffset::new(self.used_space() as UOffsetT)
|
||||
}
|
||||
|
||||
/// Create a vector of strings.
|
||||
///
|
||||
/// Speed-sensitive users may wish to reduce memory usage by creating the
|
||||
/// vector manually: use `start_vector`, `push`, and `end_vector`.
|
||||
#[inline]
|
||||
pub fn create_vector_of_strings<'a, 'b>(
|
||||
&'a mut self,
|
||||
xs: &'b [&'b str],
|
||||
) -> WIPOffset<Vector<'fbb, ForwardsUOffset<&'fbb str>>> {
|
||||
self.assert_not_nested("create_vector_of_strings can not be called when a table or vector is under construction");
|
||||
// internally, smallvec can be a stack-allocated or heap-allocated vector:
|
||||
// if xs.len() > N_SMALLVEC_STRING_VECTOR_CAPACITY then it will overflow to the heap.
|
||||
let mut offsets: smallvec::SmallVec<[WIPOffset<&str>; N_SMALLVEC_STRING_VECTOR_CAPACITY]> =
|
||||
smallvec::SmallVec::with_capacity(xs.len());
|
||||
unsafe {
|
||||
offsets.set_len(xs.len());
|
||||
}
|
||||
|
||||
// note that this happens in reverse, because the buffer is built back-to-front:
|
||||
for (i, &s) in xs.iter().enumerate().rev() {
|
||||
let o = self.create_string(s);
|
||||
offsets[i] = o;
|
||||
}
|
||||
self.create_vector(&offsets[..])
|
||||
}
|
||||
|
||||
/// Create a vector of Push-able objects.
|
||||
///
|
||||
/// Speed-sensitive users may wish to reduce memory usage by creating the
|
||||
/// vector manually: use `start_vector`, `push`, and `end_vector`.
|
||||
#[inline]
|
||||
pub fn create_vector<'a: 'b, 'b, T: Push + Copy + 'b>(
|
||||
&'a mut self,
|
||||
items: &'b [T],
|
||||
) -> WIPOffset<Vector<'fbb, T::Output>> {
|
||||
let elem_size = T::size();
|
||||
self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET));
|
||||
for i in (0..items.len()).rev() {
|
||||
self.push(items[i]);
|
||||
}
|
||||
WIPOffset::new(self.push::<UOffsetT>(items.len() as UOffsetT).value())
|
||||
}
|
||||
|
||||
/// Get the byte slice for the data that has been written, regardless of
|
||||
/// whether it has been finished.
|
||||
#[inline]
|
||||
pub fn unfinished_data(&self) -> &[u8] {
|
||||
&self.owned_buf[self.head..]
|
||||
}
|
||||
/// Get the byte slice for the data that has been written after a call to
|
||||
/// one of the `finish` functions.
|
||||
#[inline]
|
||||
pub fn finished_data(&self) -> &[u8] {
|
||||
self.assert_finished("finished_bytes cannot be called when the buffer is not yet finished");
|
||||
&self.owned_buf[self.head..]
|
||||
}
|
||||
/// Assert that a field is present in the just-finished Table.
|
||||
///
|
||||
/// This is somewhat low-level and is mostly used by the generated code.
|
||||
#[inline]
|
||||
pub fn required(
|
||||
&self,
|
||||
tab_revloc: WIPOffset<TableFinishedWIPOffset>,
|
||||
slot_byte_loc: VOffsetT,
|
||||
assert_msg_name: &'static str,
|
||||
) {
|
||||
let idx = self.used_space() - tab_revloc.value() as usize;
|
||||
let tab = Table::new(&self.owned_buf[self.head..], idx);
|
||||
let o = tab.vtable().get(slot_byte_loc) as usize;
|
||||
assert!(o != 0, "missing required field {}", assert_msg_name);
|
||||
}
|
||||
|
||||
/// Finalize the FlatBuffer by: aligning it, pushing an optional file
|
||||
/// identifier on to it, pushing a size prefix on to it, and marking the
|
||||
/// internal state of the FlatBufferBuilder as `finished`. Afterwards,
|
||||
/// users can call `finished_data` to get the resulting data.
|
||||
#[inline]
|
||||
pub fn finish_size_prefixed<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) {
|
||||
self.finish_with_opts(root, file_identifier, true);
|
||||
}
|
||||
|
||||
/// Finalize the FlatBuffer by: aligning it, pushing an optional file
|
||||
/// identifier on to it, and marking the internal state of the
|
||||
/// FlatBufferBuilder as `finished`. Afterwards, users can call
|
||||
/// `finished_data` to get the resulting data.
|
||||
#[inline]
|
||||
pub fn finish<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) {
|
||||
self.finish_with_opts(root, file_identifier, false);
|
||||
}
|
||||
|
||||
/// Finalize the FlatBuffer by: aligning it and marking the internal state
|
||||
/// of the FlatBufferBuilder as `finished`. Afterwards, users can call
|
||||
/// `finished_data` to get the resulting data.
|
||||
#[inline]
|
||||
pub fn finish_minimal<T>(&mut self, root: WIPOffset<T>) {
|
||||
self.finish_with_opts(root, None, false);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn used_space(&self) -> usize {
|
||||
self.owned_buf.len() - self.head as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn track_field(&mut self, slot_off: VOffsetT, off: UOffsetT) {
|
||||
let fl = FieldLoc {
|
||||
id: slot_off,
|
||||
off: off,
|
||||
};
|
||||
self.field_locs.push(fl);
|
||||
}
|
||||
|
||||
/// Write the VTable, if it is new.
|
||||
fn write_vtable(
|
||||
&mut self,
|
||||
table_tail_revloc: WIPOffset<TableUnfinishedWIPOffset>,
|
||||
) -> WIPOffset<VTableWIPOffset> {
|
||||
self.assert_nested("write_vtable");
|
||||
|
||||
// Write the vtable offset, which is the start of any Table.
|
||||
// We fill its value later.
|
||||
let object_revloc_to_vtable: WIPOffset<VTableWIPOffset> =
|
||||
WIPOffset::new(self.push::<UOffsetT>(0xF0F0F0F0 as UOffsetT).value());
|
||||
|
||||
// Layout of the data this function will create when a new vtable is
|
||||
// needed.
|
||||
// --------------------------------------------------------------------
|
||||
// vtable starts here
|
||||
// | x, x -- vtable len (bytes) [u16]
|
||||
// | x, x -- object inline len (bytes) [u16]
|
||||
// | x, x -- zero, or num bytes from start of object to field #0 [u16]
|
||||
// | ...
|
||||
// | x, x -- zero, or num bytes from start of object to field #n-1 [u16]
|
||||
// vtable ends here
|
||||
// table starts here
|
||||
// | x, x, x, x -- offset (negative direction) to the vtable [i32]
|
||||
// | aka "vtableoffset"
|
||||
// | -- table inline data begins here, we don't touch it --
|
||||
// table ends here -- aka "table_start"
|
||||
// --------------------------------------------------------------------
|
||||
//
|
||||
// Layout of the data this function will create when we re-use an
|
||||
// existing vtable.
|
||||
//
|
||||
// We always serialize this particular vtable, then compare it to the
|
||||
// other vtables we know about to see if there is a duplicate. If there
|
||||
// is, then we erase the serialized vtable we just made.
|
||||
// We serialize it first so that we are able to do byte-by-byte
|
||||
// comparisons with already-serialized vtables. This 1) saves
|
||||
// bookkeeping space (we only keep revlocs to existing vtables), 2)
|
||||
// allows us to convert to little-endian once, then do
|
||||
// fast memcmp comparisons, and 3) by ensuring we are comparing real
|
||||
// serialized vtables, we can be more assured that we are doing the
|
||||
// comparisons correctly.
|
||||
//
|
||||
// --------------------------------------------------------------------
|
||||
// table starts here
|
||||
// | x, x, x, x -- offset (negative direction) to an existing vtable [i32]
|
||||
// | aka "vtableoffset"
|
||||
// | -- table inline data begins here, we don't touch it --
|
||||
// table starts here: aka "table_start"
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// fill the WIP vtable with zeros:
|
||||
let vtable_byte_len = get_vtable_byte_len(&self.field_locs);
|
||||
self.make_space(vtable_byte_len);
|
||||
|
||||
// compute the length of the table (not vtable!) in bytes:
|
||||
let table_object_size = object_revloc_to_vtable.value() - table_tail_revloc.value();
|
||||
debug_assert!(table_object_size < 0x10000); // vTable use 16bit offsets.
|
||||
|
||||
// Write the VTable (we may delete it afterwards, if it is a duplicate):
|
||||
let vt_start_pos = self.head;
|
||||
let vt_end_pos = self.head + vtable_byte_len;
|
||||
{
|
||||
// write the vtable header:
|
||||
let vtfw = &mut VTableWriter::init(&mut self.owned_buf[vt_start_pos..vt_end_pos]);
|
||||
vtfw.write_vtable_byte_length(vtable_byte_len as VOffsetT);
|
||||
vtfw.write_object_inline_size(table_object_size as VOffsetT);
|
||||
|
||||
// serialize every FieldLoc to the vtable:
|
||||
for &fl in self.field_locs.iter() {
|
||||
let pos: VOffsetT = (object_revloc_to_vtable.value() - fl.off) as VOffsetT;
|
||||
debug_assert_eq!(
|
||||
vtfw.get_field_offset(fl.id),
|
||||
0,
|
||||
"tried to write a vtable field multiple times"
|
||||
);
|
||||
vtfw.write_field_offset(fl.id, pos);
|
||||
}
|
||||
}
|
||||
let dup_vt_use = {
|
||||
let this_vt = VTable::init(&self.owned_buf[..], self.head);
|
||||
self.find_duplicate_stored_vtable_revloc(this_vt)
|
||||
};
|
||||
|
||||
let vt_use = match dup_vt_use {
|
||||
Some(n) => {
|
||||
VTableWriter::init(&mut self.owned_buf[vt_start_pos..vt_end_pos]).clear();
|
||||
self.head += vtable_byte_len;
|
||||
n
|
||||
}
|
||||
None => {
|
||||
let new_vt_use = self.used_space() as UOffsetT;
|
||||
self.written_vtable_revpos.push(new_vt_use);
|
||||
new_vt_use
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
let n = self.head + self.used_space() - object_revloc_to_vtable.value() as usize;
|
||||
let saw = read_scalar_at::<UOffsetT>(&self.owned_buf, n);
|
||||
debug_assert_eq!(saw, 0xF0F0F0F0);
|
||||
emplace_scalar::<SOffsetT>(
|
||||
&mut self.owned_buf[n..n + SIZE_SOFFSET],
|
||||
vt_use as SOffsetT - object_revloc_to_vtable.value() as SOffsetT,
|
||||
);
|
||||
}
|
||||
|
||||
self.field_locs.clear();
|
||||
|
||||
object_revloc_to_vtable
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn find_duplicate_stored_vtable_revloc(&self, needle: VTable) -> Option<UOffsetT> {
|
||||
for &revloc in self.written_vtable_revpos.iter().rev() {
|
||||
let o = VTable::init(
|
||||
&self.owned_buf[..],
|
||||
self.head + self.used_space() - revloc as usize,
|
||||
);
|
||||
if needle == o {
|
||||
return Some(revloc);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// Only call this when you know it is safe to double the size of the buffer.
|
||||
#[inline]
|
||||
fn grow_owned_buf(&mut self) {
|
||||
let old_len = self.owned_buf.len();
|
||||
let new_len = max(1, old_len * 2);
|
||||
|
||||
let starting_active_size = self.used_space();
|
||||
|
||||
let diff = new_len - old_len;
|
||||
self.owned_buf.resize(new_len, 0);
|
||||
self.head += diff;
|
||||
|
||||
let ending_active_size = self.used_space();
|
||||
debug_assert_eq!(starting_active_size, ending_active_size);
|
||||
|
||||
if new_len == 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate the midpoint, and safely copy the old end data to the new
|
||||
// end position:
|
||||
let middle = new_len / 2;
|
||||
{
|
||||
let (left, right) = &mut self.owned_buf[..].split_at_mut(middle);
|
||||
right.copy_from_slice(left);
|
||||
}
|
||||
// finally, zero out the old end data.
|
||||
{
|
||||
let ptr = (&mut self.owned_buf[..middle]).as_mut_ptr();
|
||||
unsafe {
|
||||
write_bytes(ptr, 0, middle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// with or without a size prefix changes how we load the data, so finish*
|
||||
// functions are split along those lines.
|
||||
fn finish_with_opts<T>(
|
||||
&mut self,
|
||||
root: WIPOffset<T>,
|
||||
file_identifier: Option<&str>,
|
||||
size_prefixed: bool,
|
||||
) {
|
||||
self.assert_not_finished("buffer cannot be finished when it is already finished");
|
||||
self.assert_not_nested(
|
||||
"buffer cannot be finished when a table or vector is under construction",
|
||||
);
|
||||
self.written_vtable_revpos.clear();
|
||||
|
||||
let to_align = {
|
||||
// for the root offset:
|
||||
let a = SIZE_UOFFSET;
|
||||
// for the size prefix:
|
||||
let b = if size_prefixed { SIZE_UOFFSET } else { 0 };
|
||||
// for the file identifier (a string that is not zero-terminated):
|
||||
let c = if file_identifier.is_some() {
|
||||
FILE_IDENTIFIER_LENGTH
|
||||
} else {
|
||||
0
|
||||
};
|
||||
a + b + c
|
||||
};
|
||||
|
||||
{
|
||||
let ma = PushAlignment::new(self.min_align);
|
||||
self.align(to_align, ma);
|
||||
}
|
||||
|
||||
if let Some(ident) = file_identifier {
|
||||
debug_assert_eq!(ident.len(), FILE_IDENTIFIER_LENGTH);
|
||||
self.push_bytes_unprefixed(ident.as_bytes());
|
||||
}
|
||||
|
||||
self.push(root);
|
||||
|
||||
if size_prefixed {
|
||||
let sz = self.used_space() as UOffsetT;
|
||||
self.push::<UOffsetT>(sz);
|
||||
}
|
||||
self.finished = true;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn align(&mut self, len: usize, alignment: PushAlignment) {
|
||||
self.track_min_align(alignment.value());
|
||||
let s = self.used_space() as usize;
|
||||
self.make_space(padding_bytes(s + len, alignment.value()));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn track_min_align(&mut self, alignment: usize) {
|
||||
self.min_align = max(self.min_align, alignment);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn push_bytes_unprefixed(&mut self, x: &[u8]) -> UOffsetT {
|
||||
let n = self.make_space(x.len());
|
||||
&mut self.owned_buf[n..n + x.len()].copy_from_slice(x);
|
||||
|
||||
n as UOffsetT
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn make_space(&mut self, want: usize) -> usize {
|
||||
self.ensure_capacity(want);
|
||||
self.head -= want;
|
||||
self.head
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ensure_capacity(&mut self, want: usize) -> usize {
|
||||
if self.unused_ready_space() >= want {
|
||||
return want;
|
||||
}
|
||||
assert!(
|
||||
want <= FLATBUFFERS_MAX_BUFFER_SIZE,
|
||||
"cannot grow buffer beyond 2 gigabytes"
|
||||
);
|
||||
|
||||
while self.unused_ready_space() < want {
|
||||
self.grow_owned_buf();
|
||||
}
|
||||
want
|
||||
}
|
||||
#[inline]
|
||||
fn unused_ready_space(&self) -> usize {
|
||||
self.head
|
||||
}
|
||||
#[inline]
|
||||
fn assert_nested(&self, fn_name: &'static str) {
|
||||
// we don't assert that self.field_locs.len() >0 because the vtable
|
||||
// could be empty (e.g. for empty tables, or for all-default values).
|
||||
debug_assert!(
|
||||
self.nested,
|
||||
format!(
|
||||
"incorrect FlatBufferBuilder usage: {} must be called while in a nested state",
|
||||
fn_name
|
||||
)
|
||||
);
|
||||
}
|
||||
#[inline]
|
||||
fn assert_not_nested(&self, msg: &'static str) {
|
||||
debug_assert!(!self.nested, msg);
|
||||
}
|
||||
#[inline]
|
||||
fn assert_finished(&self, msg: &'static str) {
|
||||
debug_assert!(self.finished, msg);
|
||||
}
|
||||
#[inline]
|
||||
fn assert_not_finished(&self, msg: &'static str) {
|
||||
debug_assert!(!self.finished, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the length of the vtable needed to represent the provided FieldLocs.
|
||||
/// If there are no FieldLocs, then provide the minimum number of bytes
|
||||
/// required: enough to write the VTable header.
|
||||
#[inline]
|
||||
fn get_vtable_byte_len(field_locs: &[FieldLoc]) -> usize {
|
||||
let max_voffset = field_locs.iter().map(|fl| fl.id).max();
|
||||
match max_voffset {
|
||||
None => field_index_to_field_offset(0) as usize,
|
||||
Some(mv) => mv as usize + SIZE_VOFFSET,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn padding_bytes(buf_size: usize, scalar_size: usize) -> usize {
|
||||
// ((!buf_size) + 1) & (scalar_size - 1)
|
||||
(!buf_size).wrapping_add(1) & (scalar_size.wrapping_sub(1))
|
||||
}
|
||||
|
||||
impl<'fbb> Default for FlatBufferBuilder<'fbb> {
|
||||
fn default() -> Self {
|
||||
Self::new_with_capacity(0)
|
||||
}
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::mem::size_of;
|
||||
|
||||
/// Trait for values that must be stored in little-endian byte order, but
|
||||
/// might be represented in memory as big-endian. Every type that implements
|
||||
/// EndianScalar is a valid FlatBuffers scalar value.
|
||||
///
|
||||
/// The Rust stdlib does not provide a trait to represent scalars, so this trait
|
||||
/// serves that purpose, too.
|
||||
///
|
||||
/// Note that we do not use the num-traits crate for this, because it provides
|
||||
/// "too much". For example, num-traits provides i128 support, but that is an
|
||||
/// invalid FlatBuffers type.
|
||||
pub trait EndianScalar: Sized + PartialEq + Copy + Clone {
|
||||
fn to_little_endian(self) -> Self;
|
||||
fn from_little_endian(self) -> Self;
|
||||
}
|
||||
|
||||
/// Macro for implementing a no-op endian conversion. This is used for types
|
||||
/// that are one byte wide.
|
||||
macro_rules! impl_endian_scalar_noop {
|
||||
($ty:ident) => {
|
||||
impl EndianScalar for $ty {
|
||||
#[inline]
|
||||
fn to_little_endian(self) -> Self {
|
||||
self
|
||||
}
|
||||
#[inline]
|
||||
fn from_little_endian(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Macro for implementing an endian conversion using the stdlib `to_le` and
|
||||
/// `from_le` functions. This is used for integer types. It is not used for
|
||||
/// floats, because the `to_le` and `from_le` are not implemented for them in
|
||||
/// the stdlib.
|
||||
macro_rules! impl_endian_scalar_stdlib_le_conversion {
|
||||
($ty:ident) => {
|
||||
impl EndianScalar for $ty {
|
||||
#[inline]
|
||||
fn to_little_endian(self) -> Self {
|
||||
Self::to_le(self)
|
||||
}
|
||||
#[inline]
|
||||
fn from_little_endian(self) -> Self {
|
||||
Self::from_le(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_endian_scalar_noop!(bool);
|
||||
impl_endian_scalar_noop!(u8);
|
||||
impl_endian_scalar_noop!(i8);
|
||||
|
||||
impl_endian_scalar_stdlib_le_conversion!(u16);
|
||||
impl_endian_scalar_stdlib_le_conversion!(u32);
|
||||
impl_endian_scalar_stdlib_le_conversion!(u64);
|
||||
impl_endian_scalar_stdlib_le_conversion!(i16);
|
||||
impl_endian_scalar_stdlib_le_conversion!(i32);
|
||||
impl_endian_scalar_stdlib_le_conversion!(i64);
|
||||
|
||||
impl EndianScalar for f32 {
|
||||
/// Convert f32 from host endian-ness to little-endian.
|
||||
#[inline]
|
||||
fn to_little_endian(self) -> Self {
|
||||
#[cfg(target_endian = "little")]
|
||||
{
|
||||
self
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f32(self)
|
||||
}
|
||||
}
|
||||
/// Convert f32 from little-endian to host endian-ness.
|
||||
#[inline]
|
||||
fn from_little_endian(self) -> Self {
|
||||
#[cfg(target_endian = "little")]
|
||||
{
|
||||
self
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f32(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EndianScalar for f64 {
|
||||
/// Convert f64 from host endian-ness to little-endian.
|
||||
#[inline]
|
||||
fn to_little_endian(self) -> Self {
|
||||
#[cfg(target_endian = "little")]
|
||||
{
|
||||
self
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f64(self)
|
||||
}
|
||||
}
|
||||
/// Convert f64 from little-endian to host endian-ness.
|
||||
#[inline]
|
||||
fn from_little_endian(self) -> Self {
|
||||
#[cfg(target_endian = "little")]
|
||||
{
|
||||
self
|
||||
}
|
||||
#[cfg(not(target_endian = "little"))]
|
||||
{
|
||||
byte_swap_f64(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Swaps the bytes of an f32.
|
||||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
pub fn byte_swap_f32(x: f32) -> f32 {
|
||||
f32::from_bits(x.to_bits().swap_bytes())
|
||||
}
|
||||
|
||||
/// Swaps the bytes of an f64.
|
||||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
pub fn byte_swap_f64(x: f64) -> f64 {
|
||||
f64::from_bits(x.to_bits().swap_bytes())
|
||||
}
|
||||
|
||||
/// Place an EndianScalar into the provided mutable byte slice. Performs
|
||||
/// endian conversion, if necessary.
|
||||
#[inline]
|
||||
pub fn emplace_scalar<T: EndianScalar>(s: &mut [u8], x: T) {
|
||||
let sz = size_of::<T>();
|
||||
let mut_ptr = (&mut s[..sz]).as_mut_ptr() as *mut T;
|
||||
let val = x.to_little_endian();
|
||||
unsafe {
|
||||
*mut_ptr = val;
|
||||
}
|
||||
}
|
||||
|
||||
/// Read an EndianScalar from the provided byte slice at the specified location.
|
||||
/// Performs endian conversion, if necessary.
|
||||
#[inline]
|
||||
pub fn read_scalar_at<T: EndianScalar>(s: &[u8], loc: usize) -> T {
|
||||
let buf = &s[loc..loc + size_of::<T>()];
|
||||
read_scalar(buf)
|
||||
}
|
||||
|
||||
/// Read an EndianScalar from the provided byte slice. Performs endian
|
||||
/// conversion, if necessary.
|
||||
#[inline]
|
||||
pub fn read_scalar<T: EndianScalar>(s: &[u8]) -> T {
|
||||
let sz = size_of::<T>();
|
||||
|
||||
let p = (&s[..sz]).as_ptr() as *const T;
|
||||
let x = unsafe { *p };
|
||||
|
||||
x.from_little_endian()
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// Follow is a trait that allows us to access FlatBuffers in a declarative,
|
||||
/// type safe, and fast way. They compile down to almost no code (after
|
||||
/// optimizations). Conceptually, Follow lifts the offset-based access
|
||||
/// patterns of FlatBuffers data into the type system. This trait is used
|
||||
/// pervasively at read time, to access tables, vtables, vectors, strings, and
|
||||
/// all other data. At this time, Follow is not utilized much on the write
|
||||
/// path.
|
||||
///
|
||||
/// Writing a new Follow implementation primarily involves deciding whether
|
||||
/// you want to return data (of the type Self::Inner) or do you want to
|
||||
/// continue traversing the FlatBuffer.
|
||||
pub trait Follow<'a> {
|
||||
type Inner;
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner;
|
||||
}
|
||||
|
||||
/// Execute a follow as a top-level function.
|
||||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
pub fn lifted_follow<'a, T: Follow<'a>>(buf: &'a [u8], loc: usize) -> T::Inner {
|
||||
T::follow(buf, loc)
|
||||
}
|
||||
|
||||
/// FollowStart wraps a Follow impl in a struct type. This can make certain
|
||||
/// programming patterns more ergonomic.
|
||||
#[derive(Debug)]
|
||||
pub struct FollowStart<T>(PhantomData<T>);
|
||||
impl<'a, T: Follow<'a> + 'a> FollowStart<T> {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self { 0: PhantomData }
|
||||
}
|
||||
#[inline]
|
||||
pub fn self_follow(&'a self, buf: &'a [u8], loc: usize) -> T::Inner {
|
||||
T::follow(buf, loc)
|
||||
}
|
||||
}
|
||||
impl<'a, T: Follow<'a>> Follow<'a> for FollowStart<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
T::follow(buf, loc)
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//! # FlatBuffers
|
||||
//!
|
||||
//! A library for memory-efficient serialization of data.
|
||||
//!
|
||||
//! This crate provides runtime support for the FlatBuffers format in the Rust programming language.
|
||||
//! To use this crate, first generate code with the `flatc` compiler, as described here: https://google.github.io/flatbuffers/
|
||||
//! Then, include that code into your project.
|
||||
//! Finally, add this crate to your `Cargo.toml`.
|
||||
//!
|
||||
//! At this time, Rust support is experimental, and APIs may change between minor versions.
|
||||
//!
|
||||
//! At this time, to generate Rust code, you will need the latest `master` version of `flatc`, available from here: https://github.com/google/flatbuffers
|
||||
//! (On OSX, you can install FlatBuffers from `HEAD` with the Homebrew package manager.)
|
||||
|
||||
mod builder;
|
||||
mod endian_scalar;
|
||||
mod follow;
|
||||
mod primitives;
|
||||
mod push;
|
||||
mod table;
|
||||
mod vector;
|
||||
mod vtable;
|
||||
mod vtable_writer;
|
||||
|
||||
pub use builder::FlatBufferBuilder;
|
||||
pub use endian_scalar::{
|
||||
byte_swap_f32, byte_swap_f64, emplace_scalar, read_scalar, read_scalar_at, EndianScalar,
|
||||
};
|
||||
pub use follow::{Follow, FollowStart};
|
||||
pub use primitives::*;
|
||||
pub use push::Push;
|
||||
pub use table::{buffer_has_identifier, get_root, get_size_prefixed_root, Table};
|
||||
pub use vector::{follow_cast_ref, SafeSliceAccess, Vector};
|
||||
pub use vtable::field_index_to_field_offset;
|
||||
|
||||
// TODO(rw): Unify `create_vector` and `create_vector_direct` by using
|
||||
// `Into<Vector<...>>`.
|
||||
// TODO(rw): Split fill ops in builder into fill_small, fill_big like in C++.
|
||||
@@ -1,298 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::size_of;
|
||||
use std::ops::Deref;
|
||||
|
||||
use endian_scalar::{emplace_scalar, read_scalar, read_scalar_at};
|
||||
use follow::Follow;
|
||||
use push::Push;
|
||||
|
||||
pub const FLATBUFFERS_MAX_BUFFER_SIZE: usize = (1u64 << 31) as usize;
|
||||
|
||||
pub const FILE_IDENTIFIER_LENGTH: usize = 4;
|
||||
|
||||
pub const VTABLE_METADATA_FIELDS: usize = 2;
|
||||
|
||||
pub const SIZE_U8: usize = size_of::<u8>();
|
||||
pub const SIZE_I8: usize = size_of::<i8>();
|
||||
|
||||
pub const SIZE_U16: usize = size_of::<u16>();
|
||||
pub const SIZE_I16: usize = size_of::<i16>();
|
||||
|
||||
pub const SIZE_U32: usize = size_of::<u32>();
|
||||
pub const SIZE_I32: usize = size_of::<i32>();
|
||||
|
||||
pub const SIZE_U64: usize = size_of::<u64>();
|
||||
pub const SIZE_I64: usize = size_of::<i64>();
|
||||
|
||||
pub const SIZE_F32: usize = size_of::<f32>();
|
||||
pub const SIZE_F64: usize = size_of::<f64>();
|
||||
|
||||
pub const SIZE_SOFFSET: usize = SIZE_I32;
|
||||
pub const SIZE_UOFFSET: usize = SIZE_U32;
|
||||
pub const SIZE_VOFFSET: usize = SIZE_I16;
|
||||
|
||||
pub const SIZE_SIZEPREFIX: usize = SIZE_UOFFSET;
|
||||
|
||||
/// SOffsetT is an i32 that is used by tables to reference their vtables.
|
||||
pub type SOffsetT = i32;
|
||||
|
||||
/// UOffsetT is a u32 that is used by pervasively to represent both pointers
|
||||
/// and lengths of vectors.
|
||||
pub type UOffsetT = u32;
|
||||
|
||||
/// VOffsetT is a i32 that is used by vtables to store field data.
|
||||
pub type VOffsetT = i16;
|
||||
|
||||
/// TableFinishedWIPOffset marks a WIPOffset as being for a finished table.
|
||||
pub struct TableFinishedWIPOffset {}
|
||||
|
||||
/// TableUnfinishedWIPOffset marks a WIPOffset as being for an unfinished table.
|
||||
pub struct TableUnfinishedWIPOffset {}
|
||||
|
||||
/// UnionWIPOffset marks a WIPOffset as being for a union value.
|
||||
pub struct UnionWIPOffset {}
|
||||
|
||||
/// VTableWIPOffset marks a WIPOffset as being for a vtable.
|
||||
pub struct VTableWIPOffset {}
|
||||
|
||||
/// WIPOffset contains an UOffsetT with a special meaning: it is the location of
|
||||
/// data relative to the *end* of an in-progress FlatBuffer. The
|
||||
/// FlatBufferBuilder uses this to track the location of objects in an absolute
|
||||
/// way. The impl of Push converts a WIPOffset into a ForwardsUOffset.
|
||||
#[derive(Debug)]
|
||||
pub struct WIPOffset<T>(UOffsetT, PhantomData<T>);
|
||||
|
||||
// TODO(rw): why do we need to reimplement (with a default impl) Copy to
|
||||
// avoid ownership errors?
|
||||
impl<T> Copy for WIPOffset<T> {}
|
||||
impl<T> Clone for WIPOffset<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> WIPOffset<T> {
|
||||
WIPOffset::new(self.0.clone())
|
||||
}
|
||||
}
|
||||
impl<T> PartialEq for WIPOffset<T> {
|
||||
fn eq(&self, o: &WIPOffset<T>) -> bool {
|
||||
self.value() == o.value()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for WIPOffset<T> {
|
||||
type Target = UOffsetT;
|
||||
#[inline]
|
||||
fn deref(&self) -> &UOffsetT {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl<'a, T: 'a> WIPOffset<T> {
|
||||
/// Create a new WIPOffset.
|
||||
#[inline]
|
||||
pub fn new(o: UOffsetT) -> WIPOffset<T> {
|
||||
WIPOffset {
|
||||
0: o,
|
||||
1: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a wrapped value that brings its meaning as a union WIPOffset
|
||||
/// into the type system.
|
||||
#[inline(always)]
|
||||
pub fn as_union_value(&self) -> WIPOffset<UnionWIPOffset> {
|
||||
WIPOffset::new(self.0)
|
||||
}
|
||||
/// Get the underlying value.
|
||||
#[inline(always)]
|
||||
pub fn value(&self) -> UOffsetT {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Push for WIPOffset<T> {
|
||||
type Output = ForwardsUOffset<T>;
|
||||
|
||||
#[inline(always)]
|
||||
fn push(&self, dst: &mut [u8], rest: &[u8]) {
|
||||
let n = (SIZE_UOFFSET + rest.len() - self.value() as usize) as UOffsetT;
|
||||
emplace_scalar::<UOffsetT>(dst, n);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Push for ForwardsUOffset<T> {
|
||||
type Output = Self;
|
||||
|
||||
#[inline(always)]
|
||||
fn push(&self, dst: &mut [u8], rest: &[u8]) {
|
||||
self.value().push(dst, rest);
|
||||
}
|
||||
}
|
||||
|
||||
/// ForwardsUOffset is used by Follow to traverse a FlatBuffer: the pointer
|
||||
/// is incremented by the value contained in this type.
|
||||
#[derive(Debug)]
|
||||
pub struct ForwardsUOffset<T>(UOffsetT, PhantomData<T>);
|
||||
impl<T> ForwardsUOffset<T> {
|
||||
#[inline(always)]
|
||||
pub fn value(&self) -> UOffsetT {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
let slice = &buf[loc..loc + SIZE_UOFFSET];
|
||||
let off = read_scalar::<u32>(slice) as usize;
|
||||
T::follow(buf, loc + off)
|
||||
}
|
||||
}
|
||||
|
||||
/// ForwardsVOffset is used by Follow to traverse a FlatBuffer: the pointer
|
||||
/// is incremented by the value contained in this type.
|
||||
#[derive(Debug)]
|
||||
pub struct ForwardsVOffset<T>(VOffsetT, PhantomData<T>);
|
||||
impl<T> ForwardsVOffset<T> {
|
||||
#[inline(always)]
|
||||
pub fn value(&self) -> VOffsetT {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Follow<'a>> Follow<'a> for ForwardsVOffset<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
let slice = &buf[loc..loc + SIZE_VOFFSET];
|
||||
let off = read_scalar::<VOffsetT>(slice) as usize;
|
||||
T::follow(buf, loc + off)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Push for ForwardsVOffset<T> {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn push(&self, dst: &mut [u8], rest: &[u8]) {
|
||||
self.value().push(dst, rest);
|
||||
}
|
||||
}
|
||||
|
||||
/// ForwardsSOffset is used by Follow to traverse a FlatBuffer: the pointer
|
||||
/// is incremented by the *negative* of the value contained in this type.
|
||||
#[derive(Debug)]
|
||||
pub struct BackwardsSOffset<T>(SOffsetT, PhantomData<T>);
|
||||
impl<T> BackwardsSOffset<T> {
|
||||
#[inline(always)]
|
||||
pub fn value(&self) -> SOffsetT {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Follow<'a>> Follow<'a> for BackwardsSOffset<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
let slice = &buf[loc..loc + SIZE_SOFFSET];
|
||||
let off = read_scalar::<SOffsetT>(slice);
|
||||
T::follow(buf, (loc as SOffsetT - off) as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Push for BackwardsSOffset<T> {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn push(&self, dst: &mut [u8], rest: &[u8]) {
|
||||
self.value().push(dst, rest);
|
||||
}
|
||||
}
|
||||
|
||||
/// SkipSizePrefix is used by Follow to traverse a FlatBuffer: the pointer is
|
||||
/// incremented by a fixed constant in order to skip over the size prefix value.
|
||||
pub struct SkipSizePrefix<T>(PhantomData<T>);
|
||||
impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipSizePrefix<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
T::follow(buf, loc + SIZE_SIZEPREFIX)
|
||||
}
|
||||
}
|
||||
|
||||
/// SkipRootOffset is used by Follow to traverse a FlatBuffer: the pointer is
|
||||
/// incremented by a fixed constant in order to skip over the root offset value.
|
||||
pub struct SkipRootOffset<T>(PhantomData<T>);
|
||||
impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipRootOffset<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
T::follow(buf, loc + SIZE_UOFFSET)
|
||||
}
|
||||
}
|
||||
|
||||
/// FileIdentifier is used by Follow to traverse a FlatBuffer: the pointer is
|
||||
/// dereferenced into a byte slice, whose bytes are the file identifer value.
|
||||
pub struct FileIdentifier;
|
||||
impl<'a> Follow<'a> for FileIdentifier {
|
||||
type Inner = &'a [u8];
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
&buf[loc..loc + FILE_IDENTIFIER_LENGTH]
|
||||
}
|
||||
}
|
||||
|
||||
/// SkipFileIdentifier is used by Follow to traverse a FlatBuffer: the pointer
|
||||
/// is incremented by a fixed constant in order to skip over the file
|
||||
/// identifier value.
|
||||
pub struct SkipFileIdentifier<T>(PhantomData<T>);
|
||||
impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipFileIdentifier<T> {
|
||||
type Inner = T::Inner;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
T::follow(buf, loc + FILE_IDENTIFIER_LENGTH)
|
||||
}
|
||||
}
|
||||
|
||||
/// Follow trait impls for primitive types.
|
||||
///
|
||||
/// Ideally, these would be implemented as a single impl using trait bounds on
|
||||
/// EndianScalar, but implementing Follow that way causes a conflict with
|
||||
/// other impls.
|
||||
macro_rules! impl_follow_for_endian_scalar {
|
||||
($ty:ident) => {
|
||||
impl<'a> Follow<'a> for $ty {
|
||||
type Inner = $ty;
|
||||
#[inline(always)]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
read_scalar_at::<$ty>(buf, loc)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_follow_for_endian_scalar!(bool);
|
||||
impl_follow_for_endian_scalar!(u8);
|
||||
impl_follow_for_endian_scalar!(u16);
|
||||
impl_follow_for_endian_scalar!(u32);
|
||||
impl_follow_for_endian_scalar!(u64);
|
||||
impl_follow_for_endian_scalar!(i8);
|
||||
impl_follow_for_endian_scalar!(i16);
|
||||
impl_follow_for_endian_scalar!(i32);
|
||||
impl_follow_for_endian_scalar!(i64);
|
||||
impl_follow_for_endian_scalar!(f32);
|
||||
impl_follow_for_endian_scalar!(f64);
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::cmp::max;
|
||||
use std::mem::{align_of, size_of};
|
||||
|
||||
use endian_scalar::emplace_scalar;
|
||||
|
||||
/// Trait to abstract over functionality needed to write values (either owned
|
||||
/// or referenced). Used in FlatBufferBuilder and implemented for generated
|
||||
/// types.
|
||||
pub trait Push: Sized {
|
||||
type Output;
|
||||
fn push(&self, dst: &mut [u8], _rest: &[u8]);
|
||||
#[inline]
|
||||
fn size() -> usize {
|
||||
size_of::<Self::Output>()
|
||||
}
|
||||
#[inline]
|
||||
fn alignment() -> PushAlignment {
|
||||
PushAlignment::new(align_of::<Self::Output>())
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensure Push alignment calculations are typesafe (because this helps reduce
|
||||
/// implementation issues when using FlatBufferBuilder::align).
|
||||
pub struct PushAlignment(usize);
|
||||
impl PushAlignment {
|
||||
#[inline]
|
||||
pub fn new(x: usize) -> Self {
|
||||
PushAlignment { 0: x }
|
||||
}
|
||||
#[inline]
|
||||
pub fn value(&self) -> usize {
|
||||
self.0
|
||||
}
|
||||
#[inline]
|
||||
pub fn max_of(&self, o: usize) -> Self {
|
||||
PushAlignment::new(max(self.0, o))
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro to implement Push for EndianScalar types.
|
||||
macro_rules! impl_push_for_endian_scalar {
|
||||
($ty:ident) => {
|
||||
impl Push for $ty {
|
||||
type Output = $ty;
|
||||
|
||||
#[inline]
|
||||
fn push(&self, dst: &mut [u8], _rest: &[u8]) {
|
||||
emplace_scalar::<$ty>(dst, *self);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_push_for_endian_scalar!(bool);
|
||||
impl_push_for_endian_scalar!(u8);
|
||||
impl_push_for_endian_scalar!(i8);
|
||||
impl_push_for_endian_scalar!(u16);
|
||||
impl_push_for_endian_scalar!(i16);
|
||||
impl_push_for_endian_scalar!(u32);
|
||||
impl_push_for_endian_scalar!(i32);
|
||||
impl_push_for_endian_scalar!(u64);
|
||||
impl_push_for_endian_scalar!(i64);
|
||||
impl_push_for_endian_scalar!(f32);
|
||||
impl_push_for_endian_scalar!(f64);
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use follow::Follow;
|
||||
use primitives::*;
|
||||
use vtable::VTable;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Table<'a> {
|
||||
pub buf: &'a [u8],
|
||||
pub loc: usize,
|
||||
}
|
||||
|
||||
impl<'a> Table<'a> {
|
||||
#[inline]
|
||||
pub fn new(buf: &'a [u8], loc: usize) -> Self {
|
||||
Table { buf: buf, loc: loc }
|
||||
}
|
||||
#[inline]
|
||||
pub fn vtable(&self) -> VTable<'a> {
|
||||
<BackwardsSOffset<VTable<'a>>>::follow(self.buf, self.loc)
|
||||
}
|
||||
#[inline]
|
||||
pub fn get<T: Follow<'a> + 'a>(
|
||||
&self,
|
||||
slot_byte_loc: VOffsetT,
|
||||
default: Option<T::Inner>,
|
||||
) -> Option<T::Inner> {
|
||||
let o = self.vtable().get(slot_byte_loc) as usize;
|
||||
if o == 0 {
|
||||
return default;
|
||||
}
|
||||
Some(<T>::follow(self.buf, self.loc + o))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Follow<'a> for Table<'a> {
|
||||
type Inner = Table<'a>;
|
||||
#[inline]
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
Table { buf: buf, loc: loc }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_root<'a, T: Follow<'a> + 'a>(data: &'a [u8]) -> T::Inner {
|
||||
<ForwardsUOffset<T>>::follow(data, 0)
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_size_prefixed_root<'a, T: Follow<'a> + 'a>(data: &'a [u8]) -> T::Inner {
|
||||
<SkipSizePrefix<ForwardsUOffset<T>>>::follow(data, 0)
|
||||
}
|
||||
#[inline]
|
||||
pub fn buffer_has_identifier(data: &[u8], ident: &str, size_prefixed: bool) -> bool {
|
||||
assert_eq!(ident.len(), FILE_IDENTIFIER_LENGTH);
|
||||
|
||||
let got = if size_prefixed {
|
||||
<SkipSizePrefix<SkipRootOffset<FileIdentifier>>>::follow(data, 0)
|
||||
} else {
|
||||
<SkipRootOffset<FileIdentifier>>::follow(data, 0)
|
||||
};
|
||||
|
||||
ident.as_bytes() == got
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::size_of;
|
||||
use std::slice::from_raw_parts;
|
||||
use std::str::from_utf8_unchecked;
|
||||
|
||||
#[cfg(target_endian = "little")]
|
||||
use endian_scalar::EndianScalar;
|
||||
use endian_scalar::{read_scalar, read_scalar_at};
|
||||
use follow::Follow;
|
||||
use primitives::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Vector<'a, T: 'a>(&'a [u8], usize, PhantomData<T>);
|
||||
|
||||
impl<'a, T: 'a> Vector<'a, T> {
|
||||
#[inline(always)]
|
||||
pub fn new(buf: &'a [u8], loc: usize) -> Self {
|
||||
Vector {
|
||||
0: buf,
|
||||
1: loc,
|
||||
2: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn len(&self) -> usize {
|
||||
read_scalar::<UOffsetT>(&self.0[self.1 as usize..]) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Follow<'a> + 'a> Vector<'a, T> {
|
||||
#[inline(always)]
|
||||
pub fn get(&self, idx: usize) -> T::Inner {
|
||||
debug_assert!(idx < read_scalar::<u32>(&self.0[self.1 as usize..]) as usize);
|
||||
let sz = size_of::<T>();
|
||||
debug_assert!(sz > 0);
|
||||
T::follow(self.0, self.1 as usize + SIZE_UOFFSET + sz * idx)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SafeSliceAccess {}
|
||||
impl<'a, T: SafeSliceAccess + 'a> Vector<'a, T> {
|
||||
pub fn safe_slice(self) -> &'a [T] {
|
||||
let buf = self.0;
|
||||
let loc = self.1;
|
||||
let sz = size_of::<T>();
|
||||
debug_assert!(sz > 0);
|
||||
let len = read_scalar_at::<UOffsetT>(&buf, loc) as usize;
|
||||
let data_buf = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len * sz];
|
||||
let ptr = data_buf.as_ptr() as *const T;
|
||||
let s: &'a [T] = unsafe { from_raw_parts(ptr, len) };
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
impl SafeSliceAccess for u8 {}
|
||||
impl SafeSliceAccess for i8 {}
|
||||
impl SafeSliceAccess for bool {}
|
||||
|
||||
#[cfg(target_endian = "little")]
|
||||
mod le_safe_slice_impls {
|
||||
impl super::SafeSliceAccess for u16 {}
|
||||
impl super::SafeSliceAccess for u32 {}
|
||||
impl super::SafeSliceAccess for u64 {}
|
||||
|
||||
impl super::SafeSliceAccess for i16 {}
|
||||
impl super::SafeSliceAccess for i32 {}
|
||||
impl super::SafeSliceAccess for i64 {}
|
||||
|
||||
impl super::SafeSliceAccess for f32 {}
|
||||
impl super::SafeSliceAccess for f64 {}
|
||||
}
|
||||
|
||||
#[cfg(target_endian = "little")]
|
||||
pub use self::le_safe_slice_impls::*;
|
||||
|
||||
pub fn follow_cast_ref<'a, T: Sized + 'a>(buf: &'a [u8], loc: usize) -> &'a T {
|
||||
let sz = size_of::<T>();
|
||||
let buf = &buf[loc..loc + sz];
|
||||
let ptr = buf.as_ptr() as *const T;
|
||||
unsafe { &*ptr }
|
||||
}
|
||||
|
||||
impl<'a> Follow<'a> for &'a str {
|
||||
type Inner = &'a str;
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
let len = read_scalar_at::<UOffsetT>(&buf, loc) as usize;
|
||||
let slice = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len];
|
||||
let s = unsafe { from_utf8_unchecked(slice) };
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_endian = "little")]
|
||||
fn follow_slice_helper<T>(buf: &[u8], loc: usize) -> &[T] {
|
||||
let sz = size_of::<T>();
|
||||
debug_assert!(sz > 0);
|
||||
let len = read_scalar_at::<UOffsetT>(&buf, loc) as usize;
|
||||
let data_buf = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len * sz];
|
||||
let ptr = data_buf.as_ptr() as *const T;
|
||||
let s: &[T] = unsafe { from_raw_parts(ptr, len) };
|
||||
s
|
||||
}
|
||||
|
||||
/// Implement direct slice access if the host is little-endian.
|
||||
#[cfg(target_endian = "little")]
|
||||
impl<'a, T: EndianScalar> Follow<'a> for &'a [T] {
|
||||
type Inner = &'a [T];
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
follow_slice_helper::<T>(buf, loc)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement Follow for all possible Vectors that have Follow-able elements.
|
||||
impl<'a, T: Follow<'a> + 'a> Follow<'a> for Vector<'a, T> {
|
||||
type Inner = Vector<'a, T>;
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
Vector::new(buf, loc)
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use endian_scalar::read_scalar_at;
|
||||
use follow::Follow;
|
||||
use primitives::*;
|
||||
|
||||
/// VTable encapsulates read-only usage of a vtable. It is only to be used
|
||||
/// by generated code.
|
||||
#[derive(Debug)]
|
||||
pub struct VTable<'a> {
|
||||
buf: &'a [u8],
|
||||
loc: usize,
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for VTable<'a> {
|
||||
fn eq(&self, other: &VTable) -> bool {
|
||||
self.as_bytes().eq(other.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VTable<'a> {
|
||||
pub fn init(buf: &'a [u8], loc: usize) -> Self {
|
||||
VTable { buf: buf, loc: loc }
|
||||
}
|
||||
pub fn num_fields(&self) -> usize {
|
||||
(self.num_bytes() / SIZE_VOFFSET) - 2
|
||||
}
|
||||
pub fn num_bytes(&self) -> usize {
|
||||
read_scalar_at::<VOffsetT>(self.buf, self.loc) as usize
|
||||
}
|
||||
pub fn object_inline_num_bytes(&self) -> usize {
|
||||
let n = read_scalar_at::<VOffsetT>(self.buf, self.loc + SIZE_VOFFSET);
|
||||
n as usize
|
||||
}
|
||||
pub fn get_field(&self, idx: usize) -> VOffsetT {
|
||||
// TODO(rw): distinguish between None and 0?
|
||||
if idx > self.num_fields() {
|
||||
return 0;
|
||||
}
|
||||
read_scalar_at::<VOffsetT>(
|
||||
self.buf,
|
||||
self.loc + SIZE_VOFFSET + SIZE_VOFFSET + SIZE_VOFFSET * idx,
|
||||
)
|
||||
}
|
||||
pub fn get(&self, byte_loc: VOffsetT) -> VOffsetT {
|
||||
// TODO(rw): distinguish between None and 0?
|
||||
if byte_loc as usize >= self.num_bytes() {
|
||||
return 0;
|
||||
}
|
||||
read_scalar_at::<VOffsetT>(self.buf, self.loc + byte_loc as usize)
|
||||
}
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
let len = self.num_bytes();
|
||||
&self.buf[self.loc..self.loc + len]
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn field_index_to_field_offset(field_id: VOffsetT) -> VOffsetT {
|
||||
// Should correspond to what end_table() below builds up.
|
||||
let fixed_fields = 2; // Vtable size and Object Size.
|
||||
((field_id + fixed_fields) * (SIZE_VOFFSET as VOffsetT)) as VOffsetT
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn field_offset_to_field_index(field_o: VOffsetT) -> VOffsetT {
|
||||
debug_assert!(field_o >= 2);
|
||||
let fixed_fields = 2; // VTable size and Object Size.
|
||||
(field_o / (SIZE_VOFFSET as VOffsetT)) - fixed_fields
|
||||
}
|
||||
|
||||
impl<'a> Follow<'a> for VTable<'a> {
|
||||
type Inner = VTable<'a>;
|
||||
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||
VTable::init(buf, loc)
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::ptr::write_bytes;
|
||||
|
||||
use endian_scalar::{emplace_scalar, read_scalar_at};
|
||||
use primitives::*;
|
||||
|
||||
/// VTableWriter compartmentalizes actions needed to create a vtable.
|
||||
#[derive(Debug)]
|
||||
pub struct VTableWriter<'a> {
|
||||
buf: &'a mut [u8],
|
||||
}
|
||||
|
||||
impl<'a> VTableWriter<'a> {
|
||||
#[inline(always)]
|
||||
pub fn init(buf: &'a mut [u8]) -> Self {
|
||||
VTableWriter { buf: buf }
|
||||
}
|
||||
|
||||
/// Writes the vtable length (in bytes) into the vtable.
|
||||
///
|
||||
/// Note that callers already need to have computed this to initialize
|
||||
/// a VTableWriter.
|
||||
///
|
||||
/// In debug mode, asserts that the length of the underlying data is equal
|
||||
/// to the provided value.
|
||||
#[inline(always)]
|
||||
pub fn write_vtable_byte_length(&mut self, n: VOffsetT) {
|
||||
emplace_scalar::<VOffsetT>(&mut self.buf[..SIZE_VOFFSET], n);
|
||||
debug_assert_eq!(n as usize, self.buf.len());
|
||||
}
|
||||
|
||||
/// Writes an object length (in bytes) into the vtable.
|
||||
#[inline(always)]
|
||||
pub fn write_object_inline_size(&mut self, n: VOffsetT) {
|
||||
emplace_scalar::<VOffsetT>(&mut self.buf[SIZE_VOFFSET..2 * SIZE_VOFFSET], n);
|
||||
}
|
||||
|
||||
/// Gets an object field offset from the vtable. Only used for debugging.
|
||||
///
|
||||
/// Note that this expects field offsets (which are like pointers), not
|
||||
/// field ids (which are like array indices).
|
||||
#[inline(always)]
|
||||
pub fn get_field_offset(&self, vtable_offset: VOffsetT) -> VOffsetT {
|
||||
let idx = vtable_offset as usize;
|
||||
read_scalar_at::<VOffsetT>(&self.buf, idx)
|
||||
}
|
||||
|
||||
/// Writes an object field offset into the vtable.
|
||||
///
|
||||
/// Note that this expects field offsets (which are like pointers), not
|
||||
/// field ids (which are like array indices).
|
||||
#[inline(always)]
|
||||
pub fn write_field_offset(&mut self, vtable_offset: VOffsetT, object_data_offset: VOffsetT) {
|
||||
let idx = vtable_offset as usize;
|
||||
emplace_scalar::<VOffsetT>(&mut self.buf[idx..idx + SIZE_VOFFSET], object_data_offset);
|
||||
}
|
||||
|
||||
/// Clears all data in this VTableWriter. Used to cleanly undo a
|
||||
/// vtable write.
|
||||
#[inline(always)]
|
||||
pub fn clear(&mut self) {
|
||||
// This is the closest thing to memset in Rust right now.
|
||||
let len = self.buf.len();
|
||||
let p = self.buf.as_mut_ptr() as *mut u8;
|
||||
unsafe {
|
||||
write_bytes(p, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user