mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-02 20:15:34 +00:00
* Implement Serialize for flexbuffer::Reader * bump version * Remove use of experimantal or-patterns * Remove more use of experimantal or-patterns Co-authored-by: Casper Neo <cneo@google.com>
402 lines
14 KiB
Rust
402 lines
14 KiB
Rust
// Copyright 2019 Google LLC
|
|
//
|
|
// 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
|
|
//
|
|
// https://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 crate::bitwidth::{align, BitWidth};
|
|
mod value;
|
|
use crate::FlexBufferType;
|
|
use std::cmp::max;
|
|
use value::{find_vector_type, store_value, Value};
|
|
mod map;
|
|
mod push;
|
|
mod ser;
|
|
mod vector;
|
|
use map::sort_map_by_keys;
|
|
pub use map::MapBuilder;
|
|
pub use push::Pushable;
|
|
pub use ser::{Error, FlexbufferSerializer};
|
|
pub use vector::VectorBuilder;
|
|
|
|
macro_rules! push_slice {
|
|
($push_name: ident, $scalar: ty, $Val: ident, $new_vec: ident) => {
|
|
fn $push_name<T, S>(&mut self, xs: S)
|
|
where
|
|
T: Into<$scalar> + Copy,
|
|
S: AsRef<[T]>,
|
|
{
|
|
let mut value = Value::$new_vec(xs.as_ref().len());
|
|
let mut width = xs
|
|
.as_ref()
|
|
.iter()
|
|
.map(|x| BitWidth::from((*x).into()))
|
|
.max()
|
|
.unwrap_or_default();
|
|
if !value.is_fixed_length_vector() {
|
|
let length = Value::UInt(xs.as_ref().len() as u64);
|
|
width = std::cmp::max(width, length.width_or_child_width());
|
|
align(&mut self.buffer, width);
|
|
store_value(&mut self.buffer, length, width);
|
|
} else {
|
|
align(&mut self.buffer, width);
|
|
}
|
|
let address = self.buffer.len();
|
|
for &x in xs.as_ref().iter() {
|
|
store_value(&mut self.buffer, Value::$Val(x.into()), width);
|
|
}
|
|
value.set_address_or_panic(address);
|
|
value.set_child_width_or_panic(width);
|
|
self.values.push(value);
|
|
}
|
|
};
|
|
}
|
|
macro_rules! push_indirect {
|
|
($push_name: ident, $scalar: ty, $Direct: ident, $Indirect: ident) => {
|
|
fn $push_name<T: Into<$scalar>>(&mut self, x: T) {
|
|
let x = Value::$Direct(x.into());
|
|
let child_width = x.width_or_child_width();
|
|
let address = self.buffer.len();
|
|
store_value(&mut self.buffer, x, child_width);
|
|
self.values.push(Value::Reference {
|
|
address,
|
|
child_width,
|
|
fxb_type: FlexBufferType::$Indirect,
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
bitflags! {
|
|
/// Options for sharing data within a flexbuffer.
|
|
///
|
|
/// These increase serialization time but decrease the size of the resulting buffer. By
|
|
/// default, `SHARE_KEYS`. You may wish to turn on `SHARE_STRINGS` if you know your data has
|
|
/// many duplicate strings or `SHARE_KEY_VECTORS` if your data has many maps with identical
|
|
/// keys.
|
|
///
|
|
/// ## Not Yet Implemented
|
|
/// - `SHARE_STRINGS`
|
|
/// - `SHARE_KEY_VECTORS`
|
|
pub struct BuilderOptions: u8 {
|
|
const SHARE_NONE = 0;
|
|
const SHARE_KEYS = 1;
|
|
const SHARE_STRINGS = 2;
|
|
const SHARE_KEYS_AND_STRINGS = 3;
|
|
const SHARE_KEY_VECTORS = 4;
|
|
const SHARE_ALL = 7;
|
|
}
|
|
}
|
|
impl Default for BuilderOptions {
|
|
fn default() -> Self {
|
|
Self::SHARE_KEYS
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
// Address of a Key inside of the buffer.
|
|
struct CachedKey(usize);
|
|
|
|
/// **Use this struct to build a Flexbuffer.**
|
|
///
|
|
/// Flexbuffers may only have a single root value, which may be constructed
|
|
/// with one of the following functions.
|
|
/// * `build_singleton` will push 1 value to the buffer and serialize it as the root.
|
|
/// * `start_vector` returns a `VectorBuilder`, into which many (potentially
|
|
/// heterogenous) values can be pushed. The vector itself is the root and is serialized
|
|
/// when the `VectorBuilder` is dropped (or `end` is called).
|
|
/// * `start_map` returns a `MapBuilder`, which is similar to a `VectorBuilder` except
|
|
/// every value must be pushed with an associated key. The map is serialized when the
|
|
/// `MapBuilder` is dropped (or `end` is called).
|
|
///
|
|
/// These functions reset and overwrite the Builder which means, while there are no
|
|
/// active `MapBuilder` or `VectorBuilder`, the internal buffer is empty or contains a
|
|
/// finished Flexbuffer. The internal buffer is accessed with `view`.
|
|
#[derive(Debug, Clone)]
|
|
pub struct Builder {
|
|
buffer: Vec<u8>,
|
|
values: Vec<Value>,
|
|
key_pool: Option<Vec<CachedKey>>,
|
|
}
|
|
impl Default for Builder {
|
|
fn default() -> Self {
|
|
let opts = Default::default();
|
|
Builder::new(opts)
|
|
}
|
|
}
|
|
|
|
impl<'a> Builder {
|
|
pub fn new(opts: BuilderOptions) -> Self {
|
|
let key_pool = if opts.contains(BuilderOptions::SHARE_KEYS) {
|
|
Some(vec![])
|
|
} else {
|
|
None
|
|
};
|
|
Builder {
|
|
key_pool,
|
|
values: Vec::new(),
|
|
buffer: Vec::new(),
|
|
}
|
|
}
|
|
/// Shows the internal flexbuffer. It will either be empty or populated with the most
|
|
/// recently built flexbuffer.
|
|
pub fn view(&self) -> &[u8] {
|
|
&self.buffer
|
|
}
|
|
/// Returns the internal buffer, replacing it with a new vector. The returned buffer will
|
|
/// either be empty or populated with the most recently built flexbuffer.
|
|
pub fn take_buffer(&mut self) -> Vec<u8> {
|
|
let mut b = Vec::new();
|
|
std::mem::swap(&mut self.buffer, &mut b);
|
|
b
|
|
}
|
|
/// Resets the internal state. Automatically called before building a new flexbuffer.
|
|
pub fn reset(&mut self) {
|
|
self.buffer.clear();
|
|
self.values.clear();
|
|
if let Some(pool) = self.key_pool.as_mut() {
|
|
pool.clear();
|
|
}
|
|
}
|
|
fn push_key(&mut self, key: &str) {
|
|
debug_assert!(
|
|
key.bytes().all(|b| b != b'\0'),
|
|
"Keys must not have internal nulls."
|
|
);
|
|
// Search key pool if there is one.
|
|
let found = self.key_pool.as_ref().map(|pool| {
|
|
pool.binary_search_by(|&CachedKey(addr)| {
|
|
let old_key = map::get_key(&self.buffer, addr);
|
|
old_key.cloned().cmp(key.bytes())
|
|
})
|
|
});
|
|
let address = if let Some(Ok(idx)) = found {
|
|
// Found key in key pool.
|
|
self.key_pool.as_ref().unwrap()[idx].0
|
|
} else {
|
|
// Key not in pool (or no pool).
|
|
let address = self.buffer.len();
|
|
self.buffer.extend_from_slice(key.as_bytes());
|
|
self.buffer.push(b'\0');
|
|
address
|
|
};
|
|
if let Some(Err(idx)) = found {
|
|
// Insert into key pool.
|
|
let pool = self.key_pool.as_mut().unwrap();
|
|
pool.insert(idx, CachedKey(address));
|
|
}
|
|
self.values.push(Value::Key(address));
|
|
}
|
|
fn push_uint<T: Into<u64>>(&mut self, x: T) {
|
|
self.values.push(Value::UInt(x.into()));
|
|
}
|
|
fn push_int<T: Into<i64>>(&mut self, x: T) {
|
|
self.values.push(Value::Int(x.into()));
|
|
}
|
|
fn push_float<T: Into<f64>>(&mut self, x: T) {
|
|
self.values.push(Value::Float(x.into()));
|
|
}
|
|
fn push_null(&mut self) {
|
|
self.values.push(Value::Null);
|
|
}
|
|
fn push_bool(&mut self, x: bool) {
|
|
self.values.push(Value::Bool(x));
|
|
}
|
|
fn store_blob(&mut self, xs: &[u8]) -> Value {
|
|
let length = Value::UInt(xs.len() as u64);
|
|
let width = length.width_or_child_width();
|
|
align(&mut self.buffer, width);
|
|
store_value(&mut self.buffer, length, width);
|
|
let address = self.buffer.len();
|
|
self.buffer.extend_from_slice(xs);
|
|
Value::Reference {
|
|
fxb_type: FlexBufferType::Blob,
|
|
address,
|
|
child_width: width,
|
|
}
|
|
}
|
|
fn push_str(&mut self, x: &str) {
|
|
let mut string = self.store_blob(x.as_bytes());
|
|
self.buffer.push(b'\0');
|
|
string.set_fxb_type_or_panic(FlexBufferType::String);
|
|
self.values.push(string);
|
|
}
|
|
fn push_blob(&mut self, x: &[u8]) {
|
|
let blob = self.store_blob(x);
|
|
self.values.push(blob);
|
|
}
|
|
fn push_bools(&mut self, xs: &[bool]) {
|
|
let length = Value::UInt(xs.len() as u64);
|
|
let width = length.width_or_child_width();
|
|
align(&mut self.buffer, width);
|
|
store_value(&mut self.buffer, length, width);
|
|
let address = self.buffer.len();
|
|
for &b in xs.iter() {
|
|
self.buffer.push(b as u8);
|
|
self.buffer.resize(self.buffer.len() + width as usize, 0);
|
|
}
|
|
self.values.push(Value::Reference {
|
|
fxb_type: FlexBufferType::VectorBool,
|
|
address,
|
|
child_width: width,
|
|
});
|
|
}
|
|
|
|
push_slice!(push_uints, u64, UInt, new_uint_vector);
|
|
push_slice!(push_ints, i64, Int, new_int_vector);
|
|
push_slice!(push_floats, f64, Float, new_float_vector);
|
|
push_indirect!(push_indirect_int, i64, Int, IndirectInt);
|
|
push_indirect!(push_indirect_uint, u64, UInt, IndirectUInt);
|
|
push_indirect!(push_indirect_float, f64, Float, IndirectFloat);
|
|
|
|
/// Resets the builder and starts a new flexbuffer with a vector at the root.
|
|
/// The exact Flexbuffer vector type is dynamically inferred.
|
|
pub fn start_vector(&'a mut self) -> VectorBuilder<'a> {
|
|
self.reset();
|
|
VectorBuilder {
|
|
builder: self,
|
|
start: None,
|
|
}
|
|
}
|
|
/// Resets the builder and builds a new flexbuffer with a map at the root.
|
|
pub fn start_map(&'a mut self) -> MapBuilder<'a> {
|
|
self.reset();
|
|
MapBuilder {
|
|
builder: self,
|
|
start: None,
|
|
}
|
|
}
|
|
/// Resets the builder and builds a new flexbuffer with the pushed value at the root.
|
|
pub fn build_singleton<P: Pushable>(&mut self, p: P) {
|
|
self.reset();
|
|
p.push_to_builder(self);
|
|
let root = self.values.pop().unwrap();
|
|
store_root(&mut self.buffer, root);
|
|
}
|
|
fn push<P: Pushable>(&mut self, p: P) {
|
|
p.push_to_builder(self);
|
|
}
|
|
/// Stores the values past `previous_end` as a map or vector depending on `is_map`.
|
|
/// If `previous_end` is None then this was a root map / vector and the last value
|
|
/// is stored as the root.
|
|
fn end_map_or_vector(&mut self, is_map: bool, previous_end: Option<usize>) {
|
|
let split = previous_end.unwrap_or(0);
|
|
let value = if is_map {
|
|
let key_vals = &mut self.values[split..];
|
|
sort_map_by_keys(key_vals, &self.buffer);
|
|
let key_vector = store_vector(&mut self.buffer, key_vals, StoreOption::MapKeys);
|
|
store_vector(&mut self.buffer, key_vals, StoreOption::Map(key_vector))
|
|
} else {
|
|
store_vector(&mut self.buffer, &self.values[split..], StoreOption::Vector)
|
|
};
|
|
self.values.truncate(split);
|
|
if previous_end.is_some() {
|
|
self.values.push(value);
|
|
} else {
|
|
store_root(&mut self.buffer, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Builds a Flexbuffer with the single pushed value as the root.
|
|
pub fn singleton<P: Pushable>(p: P) -> Vec<u8> {
|
|
let mut b = Builder::default();
|
|
b.build_singleton(p);
|
|
let Builder { buffer, .. } = b;
|
|
buffer
|
|
}
|
|
|
|
/// Stores the root value, root type and root width.
|
|
/// This should be called to finish the Flexbuffer.
|
|
fn store_root(buffer: &mut Vec<u8>, root: Value) {
|
|
let root_width = root.width_in_vector(buffer.len(), 0);
|
|
align(buffer, root_width);
|
|
store_value(buffer, root, root_width);
|
|
buffer.push(root.packed_type(root_width));
|
|
buffer.push(root_width.n_bytes() as u8);
|
|
}
|
|
|
|
pub enum StoreOption {
|
|
Vector,
|
|
Map(Value),
|
|
MapKeys,
|
|
}
|
|
/// Writes a Flexbuffer Vector or Map.
|
|
/// StoreOption::Map(Keys) must be a Value::Key or this will panic.
|
|
// #[inline(always)]
|
|
pub fn store_vector(buffer: &mut Vec<u8>, values: &[Value], opt: StoreOption) -> Value {
|
|
let (skip, stride) = match opt {
|
|
StoreOption::Vector => (0, 1),
|
|
StoreOption::MapKeys => (0, 2),
|
|
StoreOption::Map(_) => (1, 2),
|
|
};
|
|
let iter_values = || values.iter().skip(skip).step_by(stride);
|
|
|
|
// Figure out vector type and how long is the prefix.
|
|
let mut result = if let StoreOption::Map(_) = opt {
|
|
Value::new_map()
|
|
} else {
|
|
find_vector_type(iter_values())
|
|
};
|
|
let length_slot = if !result.is_fixed_length_vector() {
|
|
let length = iter_values().count();
|
|
Some(Value::UInt(length as u64))
|
|
} else {
|
|
None
|
|
};
|
|
// Measure required width and align to it.
|
|
let mut width = BitWidth::W8;
|
|
if let StoreOption::Map(keys) = opt {
|
|
width = max(width, keys.width_in_vector(buffer.len(), 0))
|
|
}
|
|
if let Some(l) = length_slot {
|
|
width = max(width, l.width_or_child_width());
|
|
}
|
|
let prefix_length = result.prefix_length();
|
|
for (i, &val) in iter_values().enumerate() {
|
|
width = max(width, val.width_in_vector(buffer.len(), i + prefix_length));
|
|
}
|
|
align(buffer, width);
|
|
#[allow(deprecated)]
|
|
{
|
|
debug_assert_ne!(
|
|
result.fxb_type(),
|
|
FlexBufferType::VectorString,
|
|
"VectorString is deprecated and cannot be written.\
|
|
(https://github.com/google/flatbuffers/issues/5627)"
|
|
);
|
|
}
|
|
// Write Prefix.
|
|
if let StoreOption::Map(keys) = opt {
|
|
let key_width = Value::UInt(keys.width_or_child_width().n_bytes() as u64);
|
|
store_value(buffer, keys, width);
|
|
store_value(buffer, key_width, width);
|
|
}
|
|
if let Some(len) = length_slot {
|
|
store_value(buffer, len, width);
|
|
}
|
|
// Write data.
|
|
let address = buffer.len();
|
|
for &v in iter_values() {
|
|
store_value(buffer, v, width);
|
|
}
|
|
// Write types
|
|
if result.is_typed_vector_or_map() {
|
|
for v in iter_values() {
|
|
buffer.push(v.packed_type(width));
|
|
}
|
|
}
|
|
// Return Value representing this Vector.
|
|
result.set_address_or_panic(address);
|
|
result.set_child_width_or_panic(width);
|
|
result
|
|
}
|