/rust/registry/src/index.crates.io-1949cf8c6b5b557f/flatbuffers-25.12.19/src/builder.rs
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2018 Google Inc. All rights reserved. |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #[cfg(not(feature = "std"))] |
18 | | use alloc::{vec, vec::Vec}; |
19 | | use core::cmp::max; |
20 | | use core::convert::Infallible; |
21 | | use core::fmt::{Debug, Display}; |
22 | | use core::iter::{DoubleEndedIterator, ExactSizeIterator}; |
23 | | use core::marker::PhantomData; |
24 | | use core::ops::{Add, AddAssign, Deref, DerefMut, Index, IndexMut, Sub, SubAssign}; |
25 | | use core::ptr::write_bytes; |
26 | | |
27 | | use crate::endian_scalar::emplace_scalar; |
28 | | use crate::primitives::*; |
29 | | use crate::push::{Push, PushAlignment}; |
30 | | use crate::read_scalar; |
31 | | use crate::table::Table; |
32 | | use crate::vector::Vector; |
33 | | use crate::vtable::{field_index_to_field_offset, VTable}; |
34 | | use crate::vtable_writer::VTableWriter; |
35 | | |
36 | | /// Trait to implement custom allocation strategies for [`FlatBufferBuilder`]. |
37 | | /// |
38 | | /// An implementation can be used with [`FlatBufferBuilder::new_in`], enabling a custom allocation |
39 | | /// strategy for the [`FlatBufferBuilder`]. |
40 | | /// |
41 | | /// # Safety |
42 | | /// |
43 | | /// The implementation of the allocator must match the defined behavior as described by the |
44 | | /// comments. |
45 | | pub unsafe trait Allocator: DerefMut<Target = [u8]> { |
46 | | /// A type describing allocation failures |
47 | | type Error: Display + Debug; |
48 | | /// Grows the buffer, with the old contents being moved to the end. |
49 | | /// |
50 | | /// NOTE: While not unsound, an implementation that doesn't grow the |
51 | | /// internal buffer will get stuck in an infinite loop. |
52 | | fn grow_downwards(&mut self) -> Result<(), Self::Error>; |
53 | | |
54 | | /// Returns the size of the internal buffer in bytes. |
55 | | fn len(&self) -> usize; |
56 | | } |
57 | | |
58 | | /// Default [`FlatBufferBuilder`] allocator backed by a [`Vec<u8>`]. |
59 | | #[derive(Default)] |
60 | | pub struct DefaultAllocator(Vec<u8>); |
61 | | |
62 | | impl DefaultAllocator { |
63 | | /// Builds the allocator from an existing buffer. |
64 | 0 | pub fn from_vec(buffer: Vec<u8>) -> Self { |
65 | 0 | Self(buffer) |
66 | 0 | } |
67 | | } |
68 | | |
69 | | impl Deref for DefaultAllocator { |
70 | | type Target = [u8]; |
71 | | |
72 | 0 | fn deref(&self) -> &Self::Target { |
73 | 0 | &self.0 |
74 | 0 | } |
75 | | } |
76 | | |
77 | | impl DerefMut for DefaultAllocator { |
78 | 0 | fn deref_mut(&mut self) -> &mut Self::Target { |
79 | 0 | &mut self.0 |
80 | 0 | } |
81 | | } |
82 | | |
83 | | // SAFETY: The methods are implemented as described by the documentation. |
84 | | unsafe impl Allocator for DefaultAllocator { |
85 | | type Error = Infallible; |
86 | 0 | fn grow_downwards(&mut self) -> Result<(), Self::Error> { |
87 | 0 | let old_len = self.0.len(); |
88 | 0 | let new_len = max(1, old_len * 2); |
89 | | |
90 | 0 | self.0.resize(new_len, 0); |
91 | | |
92 | 0 | if new_len == 1 { |
93 | 0 | return Ok(()); |
94 | 0 | } |
95 | | |
96 | | // calculate the midpoint, and safely copy the old end data to the new |
97 | | // end position: |
98 | 0 | let middle = new_len / 2; |
99 | 0 | { |
100 | 0 | let (left, right) = &mut self.0[..].split_at_mut(middle); |
101 | 0 | right.copy_from_slice(left); |
102 | 0 | } |
103 | | // finally, zero out the old end data. |
104 | | { |
105 | 0 | let ptr = self.0[..middle].as_mut_ptr(); |
106 | | // Safety: |
107 | | // ptr is byte aligned and of length middle |
108 | 0 | unsafe { |
109 | 0 | write_bytes(ptr, 0, middle); |
110 | 0 | } |
111 | | } |
112 | 0 | Ok(()) |
113 | 0 | } |
114 | | |
115 | 0 | fn len(&self) -> usize { |
116 | 0 | self.0.len() |
117 | 0 | } |
118 | | } |
119 | | |
120 | | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
121 | | struct FieldLoc { |
122 | | off: UOffsetT, |
123 | | id: VOffsetT, |
124 | | } |
125 | | |
126 | | /// FlatBufferBuilder builds a FlatBuffer through manipulating its internal |
127 | | /// state. It has an owned `Vec<u8>` that grows as needed (up to the hardcoded |
128 | | /// limit of 2GiB, which is set by the FlatBuffers format). |
129 | | #[derive(Clone, Debug, Eq, PartialEq)] |
130 | | pub struct FlatBufferBuilder<'fbb, A: Allocator = DefaultAllocator> { |
131 | | allocator: A, |
132 | | head: ReverseIndex, |
133 | | |
134 | | field_locs: Vec<FieldLoc>, |
135 | | written_vtable_revpos: Vec<UOffsetT>, |
136 | | |
137 | | nested: bool, |
138 | | finished: bool, |
139 | | |
140 | | min_align: usize, |
141 | | force_defaults: bool, |
142 | | strings_pool: Vec<WIPOffset<&'fbb str>>, |
143 | | |
144 | | _phantom: PhantomData<&'fbb ()>, |
145 | | } |
146 | | |
147 | | impl<'fbb> FlatBufferBuilder<'fbb, DefaultAllocator> { |
148 | | /// Create a FlatBufferBuilder that is ready for writing. |
149 | 0 | pub fn new() -> Self { |
150 | 0 | Self::with_capacity(0) |
151 | 0 | } |
152 | | #[deprecated(note = "replaced with `with_capacity`", since = "0.8.5")] |
153 | 0 | pub fn new_with_capacity(size: usize) -> Self { |
154 | 0 | Self::with_capacity(size) |
155 | 0 | } |
156 | | /// Create a FlatBufferBuilder that is ready for writing, with a |
157 | | /// ready-to-use capacity of the provided size. |
158 | | /// |
159 | | /// The maximum valid value is `FLATBUFFERS_MAX_BUFFER_SIZE`. |
160 | 0 | pub fn with_capacity(size: usize) -> Self { |
161 | 0 | Self::from_vec(vec![0; size]) |
162 | 0 | } |
163 | | /// Create a FlatBufferBuilder that is ready for writing, reusing |
164 | | /// an existing vector. |
165 | 0 | pub fn from_vec(buffer: Vec<u8>) -> Self { |
166 | | // we need to check the size here because we create the backing buffer |
167 | | // directly, bypassing the typical way of using grow_allocator: |
168 | 0 | assert!( |
169 | 0 | buffer.len() <= FLATBUFFERS_MAX_BUFFER_SIZE, |
170 | | "cannot initialize buffer bigger than 2 gigabytes" |
171 | | ); |
172 | 0 | let allocator = DefaultAllocator::from_vec(buffer); |
173 | 0 | Self::new_in(allocator) |
174 | 0 | } |
175 | | |
176 | | /// Destroy the FlatBufferBuilder, returning its internal byte vector |
177 | | /// and the index into it that represents the start of valid data. |
178 | 0 | pub fn collapse(self) -> (Vec<u8>, usize) { |
179 | 0 | let index = self.head.to_forward_index(&self.allocator); |
180 | 0 | (self.allocator.0, index) |
181 | 0 | } |
182 | | } |
183 | | |
184 | | impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> { |
185 | | /// Create a [`FlatBufferBuilder`] that is ready for writing with a custom [`Allocator`]. |
186 | 0 | pub fn new_in(allocator: A) -> Self { |
187 | 0 | let head = ReverseIndex::end(); |
188 | 0 | FlatBufferBuilder { |
189 | 0 | allocator, |
190 | 0 | head, |
191 | 0 |
|
192 | 0 | field_locs: Vec::new(), |
193 | 0 | written_vtable_revpos: Vec::new(), |
194 | 0 |
|
195 | 0 | nested: false, |
196 | 0 | finished: false, |
197 | 0 |
|
198 | 0 | min_align: 0, |
199 | 0 | force_defaults: false, |
200 | 0 | strings_pool: Vec::new(), |
201 | 0 |
|
202 | 0 | _phantom: PhantomData, |
203 | 0 | } |
204 | 0 | } |
205 | | |
206 | | /// Destroy the [`FlatBufferBuilder`], returning its [`Allocator`] and the index |
207 | | /// into it that represents the start of valid data. |
208 | 0 | pub fn collapse_in(self) -> (A, usize) { |
209 | 0 | let index = self.head.to_forward_index(&self.allocator); |
210 | 0 | (self.allocator, index) |
211 | 0 | } |
212 | | |
213 | | /// Reset the FlatBufferBuilder internal state. Use this method after a |
214 | | /// call to a `finish` function in order to re-use a FlatBufferBuilder. |
215 | | /// |
216 | | /// This function is the only way to reset the `finished` state and start |
217 | | /// again. |
218 | | /// |
219 | | /// If you are using a FlatBufferBuilder repeatedly, make sure to use this |
220 | | /// function, because it re-uses the FlatBufferBuilder's existing |
221 | | /// heap-allocated `Vec<u8>` internal buffer. This offers significant speed |
222 | | /// improvements as compared to creating a new FlatBufferBuilder for every |
223 | | /// new object. |
224 | 0 | pub fn reset(&mut self) { |
225 | | // memset only the part of the buffer that could be dirty: |
226 | 0 | self.allocator[self.head.range_to_end()].iter_mut().for_each(|x| *x = 0); |
227 | | |
228 | 0 | self.head = ReverseIndex::end(); |
229 | 0 | self.written_vtable_revpos.clear(); |
230 | | |
231 | 0 | self.nested = false; |
232 | 0 | self.finished = false; |
233 | | |
234 | 0 | self.min_align = 0; |
235 | 0 | self.strings_pool.clear(); |
236 | 0 | } |
237 | | |
238 | | /// Push a Push'able value onto the front of the in-progress data. |
239 | | /// |
240 | | /// This function uses traits to provide a unified API for writing |
241 | | /// scalars, tables, vectors, and WIPOffsets. |
242 | | #[inline] |
243 | 0 | pub fn push<P: Push>(&mut self, x: P) -> WIPOffset<P::Output> { |
244 | 0 | let sz = P::size(); |
245 | 0 | self.align(sz, P::alignment()); |
246 | 0 | self.make_space(sz); |
247 | 0 | { |
248 | 0 | let (dst, rest) = self.allocator[self.head.range_to_end()].split_at_mut(sz); |
249 | 0 | // Safety: |
250 | 0 | // Called make_space above |
251 | 0 | unsafe { x.push(dst, rest.len()) }; |
252 | 0 | } |
253 | 0 | WIPOffset::new(self.used_space() as UOffsetT) |
254 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::kind_generated::Kind>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::point_generated::Point>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_generated::Value>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::polygon_generated::Polygon>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::geometry_generated::Geometry>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::key_value_generated::KeyValue>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::line_string_generated::LineString>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::object_field_generated::ObjectField>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<&str>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::geometry_kind_type_generated::GeometryKindType>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<u8>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<flatbuffers::primitives::UnionWIPOffset>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::kind_generated::Kind>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_generated::Value>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::line_string_generated::LineString>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::record_id_key_generated::RecordIdKey>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::uint_64_value_generated::UInt64Value>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<flatbuffers::primitives::WIPOffset<&str>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::kind_type_generated::KindType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_type_generated::ValueType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_bound_generated::ValueBound> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::literal_type_generated::LiteralType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::geometry_type_generated::GeometryType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::record_id_key_type_generated::RecordIdKeyType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::record_id_key_bound_generated::RecordIdKeyBound> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<bool> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<f64> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<u8> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<u32> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<i64> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push::<u64> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::push::<_> |
255 | | |
256 | | /// Push a Push'able value onto the front of the in-progress data, and |
257 | | /// store a reference to it in the in-progress vtable. If the value matches |
258 | | /// the default, then this is a no-op. |
259 | | #[inline] |
260 | 0 | pub fn push_slot<X: Push + PartialEq>(&mut self, slotoff: VOffsetT, x: X, default: X) { |
261 | 0 | self.assert_nested("push_slot"); |
262 | 0 | if x != default || self.force_defaults { |
263 | 0 | self.push_slot_always(slotoff, x); |
264 | 0 | } |
265 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::kind_type_generated::KindType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_type_generated::ValueType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_bound_generated::ValueBound> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::literal_type_generated::LiteralType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::geometry_type_generated::GeometryType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::record_id_key_type_generated::RecordIdKeyType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::record_id_key_bound_generated::RecordIdKeyBound> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<bool> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<f64> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<u32> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<i64> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot::<u64> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::push_slot::<_> |
266 | | |
267 | | /// Push a Push'able value onto the front of the in-progress data, and |
268 | | /// store a reference to it in the in-progress vtable. |
269 | | #[inline] |
270 | 0 | pub fn push_slot_always<X: Push>(&mut self, slotoff: VOffsetT, x: X) { |
271 | 0 | self.assert_nested("push_slot_always"); |
272 | 0 | let off = self.push(x); |
273 | 0 | self.track_field(slotoff, off.value()); |
274 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::kind_generated::Kind>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::point_generated::Point>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_generated::Value>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::polygon_generated::Polygon>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::geometry_generated::Geometry>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::key_value_generated::KeyValue>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::line_string_generated::LineString>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::object_field_generated::ObjectField>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<flatbuffers::primitives::ForwardsUOffset<&str>>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::geometry_kind_type_generated::GeometryKindType>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::vector::Vector<u8>>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<flatbuffers::primitives::UnionWIPOffset>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::kind_generated::Kind>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_generated::Value>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::line_string_generated::LineString>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::record_id_key_generated::RecordIdKey>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::uint_64_value_generated::UInt64Value>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<flatbuffers::primitives::WIPOffset<&str>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::kind_type_generated::KindType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_type_generated::ValueType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_bound_generated::ValueBound> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::literal_type_generated::LiteralType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::geometry_type_generated::GeometryType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::record_id_key_type_generated::RecordIdKeyType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::record_id_key_bound_generated::RecordIdKeyBound> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<bool> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<f64> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<u32> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<i64> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_slot_always::<u64> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::push_slot_always::<_> |
275 | | |
276 | | /// Retrieve the number of vtables that have been serialized into the |
277 | | /// FlatBuffer. This is primarily used to check vtable deduplication. |
278 | | #[inline] |
279 | 0 | pub fn num_written_vtables(&self) -> usize { |
280 | 0 | self.written_vtable_revpos.len() |
281 | 0 | } |
282 | | |
283 | | /// Start a Table write. |
284 | | /// |
285 | | /// Asserts that the builder is not in a nested state. |
286 | | /// |
287 | | /// Users probably want to use `push_slot` to add values after calling this. |
288 | | #[inline] |
289 | 0 | pub fn start_table(&mut self) -> WIPOffset<TableUnfinishedWIPOffset> { |
290 | 0 | self.assert_not_nested( |
291 | | "start_table can not be called when a table or vector is under construction", |
292 | | ); |
293 | 0 | self.nested = true; |
294 | | |
295 | 0 | WIPOffset::new(self.used_space() as UOffsetT) |
296 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::start_table Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::start_table |
297 | | |
298 | | /// End a Table write. |
299 | | /// |
300 | | /// Asserts that the builder is in a nested state. |
301 | | #[inline] |
302 | 0 | pub fn end_table( |
303 | 0 | &mut self, |
304 | 0 | off: WIPOffset<TableUnfinishedWIPOffset>, |
305 | 0 | ) -> WIPOffset<TableFinishedWIPOffset> { |
306 | 0 | self.assert_nested("end_table"); |
307 | | |
308 | 0 | let o = self.write_vtable(off); |
309 | | |
310 | 0 | self.nested = false; |
311 | 0 | self.field_locs.clear(); |
312 | | |
313 | 0 | WIPOffset::new(o.value()) |
314 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::end_table Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::end_table |
315 | | |
316 | | /// Start a Vector write. |
317 | | /// |
318 | | /// Asserts that the builder is not in a nested state. |
319 | | /// |
320 | | /// Most users will prefer to call `create_vector`. |
321 | | /// Speed optimizing users who choose to create vectors manually using this |
322 | | /// function will want to use `push` to add values. |
323 | | #[inline] |
324 | 0 | pub fn start_vector<T: Push>(&mut self, num_items: usize) { |
325 | 0 | self.assert_not_nested( |
326 | | "start_vector can not be called when a table or vector is under construction", |
327 | | ); |
328 | 0 | self.nested = true; |
329 | 0 | self.align(num_items * T::size(), T::alignment().max_of(SIZE_UOFFSET)); |
330 | 0 | } |
331 | | |
332 | | /// End a Vector write. |
333 | | /// |
334 | | /// Note that the `num_elems` parameter is the number of written items, not |
335 | | /// the byte count. |
336 | | /// |
337 | | /// Asserts that the builder is in a nested state. |
338 | | #[inline] |
339 | 0 | pub fn end_vector<T: Push>(&mut self, num_elems: usize) -> WIPOffset<Vector<'fbb, T>> { |
340 | 0 | self.assert_nested("end_vector"); |
341 | 0 | self.nested = false; |
342 | 0 | let o = self.push::<UOffsetT>(num_elems as UOffsetT); |
343 | 0 | WIPOffset::new(o.value()) |
344 | 0 | } |
345 | | |
346 | | #[inline] |
347 | 0 | pub fn create_shared_string<'a: 'b, 'b>(&'a mut self, s: &'b str) -> WIPOffset<&'fbb str> { |
348 | 0 | self.assert_not_nested( |
349 | | "create_shared_string can not be called when a table or vector is under construction", |
350 | | ); |
351 | | |
352 | | // Saves a ref to allocator since rust doesnt like us refrencing it |
353 | | // in the binary_search_by code. |
354 | 0 | let buf = &self.allocator; |
355 | | |
356 | 0 | let found = self.strings_pool.binary_search_by(|offset| { |
357 | 0 | let ptr = offset.value() as usize; |
358 | | // Gets The pointer to the size of the string |
359 | 0 | let str_memory = &buf[buf.len() - ptr..]; |
360 | | // Gets the size of the written string from buffer |
361 | 0 | let size = |
362 | 0 | u32::from_le_bytes([str_memory[0], str_memory[1], str_memory[2], str_memory[3]]) |
363 | 0 | as usize; |
364 | | // Size of the string size |
365 | 0 | let string_size: usize = 4; |
366 | | // Fetches actual string bytes from index of string after string size |
367 | | // to the size of string plus string size |
368 | 0 | let iter = str_memory[string_size..size + string_size].iter(); |
369 | | // Compares bytes of fetched string and current writable string |
370 | 0 | iter.cloned().cmp(s.bytes()) |
371 | 0 | }); |
372 | | |
373 | 0 | match found { |
374 | 0 | Ok(index) => self.strings_pool[index], |
375 | 0 | Err(index) => { |
376 | 0 | let address = WIPOffset::new(self.create_byte_string(s.as_bytes()).value()); |
377 | 0 | self.strings_pool.insert(index, address); |
378 | 0 | address |
379 | | } |
380 | | } |
381 | 0 | } |
382 | | |
383 | | /// Create a utf8 string. |
384 | | /// |
385 | | /// The wire format represents this as a zero-terminated byte vector. |
386 | | #[inline] |
387 | 0 | pub fn create_string<'a: 'b, 'b>(&'a mut self, s: &'b str) -> WIPOffset<&'fbb str> { |
388 | 0 | self.assert_not_nested( |
389 | | "create_string can not be called when a table or vector is under construction", |
390 | | ); |
391 | 0 | WIPOffset::new(self.create_byte_string(s.as_bytes()).value()) |
392 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_string Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::create_string |
393 | | |
394 | | /// Create a zero-terminated byte vector. |
395 | | #[inline] |
396 | 0 | pub fn create_byte_string(&mut self, data: &[u8]) -> WIPOffset<&'fbb [u8]> { |
397 | 0 | self.assert_not_nested( |
398 | | "create_byte_string can not be called when a table or vector is under construction", |
399 | | ); |
400 | 0 | self.align(data.len() + 1, PushAlignment::new(SIZE_UOFFSET)); |
401 | 0 | self.push(0u8); |
402 | 0 | self.push_bytes_unprefixed(data); |
403 | 0 | self.push(data.len() as UOffsetT); |
404 | 0 | WIPOffset::new(self.used_space() as UOffsetT) |
405 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_byte_string Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::create_byte_string |
406 | | |
407 | | /// Create a vector of Push-able objects. |
408 | | /// |
409 | | /// Speed-sensitive users may wish to reduce memory usage by creating the |
410 | | /// vector manually: use `start_vector`, `push`, and `end_vector`. |
411 | | #[inline] |
412 | 0 | pub fn create_vector<'a: 'b, 'b, T: Push + 'b>( |
413 | 0 | &'a mut self, |
414 | 0 | items: &'b [T], |
415 | 0 | ) -> WIPOffset<Vector<'fbb, T::Output>> { |
416 | 0 | let elem_size = T::size(); |
417 | 0 | let slice_size = items.len() * elem_size; |
418 | 0 | self.align(slice_size, T::alignment().max_of(SIZE_UOFFSET)); |
419 | 0 | self.ensure_capacity(slice_size + UOffsetT::size()); |
420 | | |
421 | 0 | self.head -= slice_size; |
422 | 0 | let mut written_len = self.head.distance_to_end(); |
423 | | |
424 | 0 | let buf = &mut self.allocator[self.head.range_to(self.head + slice_size)]; |
425 | 0 | for (item, out) in items.iter().zip(buf.chunks_exact_mut(elem_size)) { |
426 | 0 | written_len -= elem_size; |
427 | 0 |
|
428 | 0 | // Safety: |
429 | 0 | // Called ensure_capacity and aligned to T above |
430 | 0 | unsafe { item.push(out, written_len) }; |
431 | 0 | } |
432 | | |
433 | 0 | WIPOffset::new(self.push::<UOffsetT>(items.len() as UOffsetT).value()) |
434 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_vector::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::kind_generated::Kind>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_vector::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::point_generated::Point>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_vector::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_generated::Value>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_vector::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::polygon_generated::Polygon>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_vector::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::geometry_generated::Geometry>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_vector::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::key_value_generated::KeyValue>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_vector::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::line_string_generated::LineString>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_vector::<flatbuffers::primitives::WIPOffset<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::object_field_generated::ObjectField>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_vector::<flatbuffers::primitives::WIPOffset<&str>> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_vector::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::geometry_kind_type_generated::GeometryKindType> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::create_vector::<u8> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::create_vector::<_> |
435 | | |
436 | | /// Create a vector of Push-able objects. |
437 | | /// |
438 | | /// Speed-sensitive users may wish to reduce memory usage by creating the |
439 | | /// vector manually: use `start_vector`, `push`, and `end_vector`. |
440 | | #[inline] |
441 | 0 | pub fn create_vector_from_iter<T: Push>( |
442 | 0 | &mut self, |
443 | 0 | items: impl ExactSizeIterator<Item = T> + DoubleEndedIterator, |
444 | 0 | ) -> WIPOffset<Vector<'fbb, T::Output>> { |
445 | 0 | let elem_size = T::size(); |
446 | 0 | self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET)); |
447 | 0 | let mut actual = 0; |
448 | 0 | for item in items.rev() { |
449 | 0 | self.push(item); |
450 | 0 | actual += 1; |
451 | 0 | } |
452 | 0 | WIPOffset::new(self.push::<UOffsetT>(actual).value()) |
453 | 0 | } |
454 | | |
455 | | /// Set whether default values are stored. |
456 | | /// |
457 | | /// In order to save space, fields that are set to their default value |
458 | | /// aren't stored in the buffer. Setting `force_defaults` to `true` |
459 | | /// disables this optimization. |
460 | | /// |
461 | | /// By default, `force_defaults` is `false`. |
462 | | #[inline] |
463 | 0 | pub fn force_defaults(&mut self, force_defaults: bool) { |
464 | 0 | self.force_defaults = force_defaults; |
465 | 0 | } |
466 | | |
467 | | /// Get the byte slice for the data that has been written, regardless of |
468 | | /// whether it has been finished. |
469 | | #[inline] |
470 | 0 | pub fn unfinished_data(&self) -> &[u8] { |
471 | 0 | &self.allocator[self.head.range_to_end()] |
472 | 0 | } |
473 | | /// Get the byte slice for the data that has been written after a call to |
474 | | /// one of the `finish` functions. |
475 | | /// # Panics |
476 | | /// Panics if the buffer is not finished. |
477 | | #[inline] |
478 | 0 | pub fn finished_data(&self) -> &[u8] { |
479 | 0 | self.assert_finished("finished_bytes cannot be called when the buffer is not yet finished"); |
480 | 0 | &self.allocator[self.head.range_to_end()] |
481 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::finished_data Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::finished_data |
482 | | /// Returns a mutable view of a finished buffer and location of where the flatbuffer starts. |
483 | | /// Note that modifying the flatbuffer data may corrupt it. |
484 | | /// # Panics |
485 | | /// Panics if the flatbuffer is not finished. |
486 | | #[inline] |
487 | 0 | pub fn mut_finished_buffer(&mut self) -> (&mut [u8], usize) { |
488 | 0 | let index = self.head.to_forward_index(&self.allocator); |
489 | 0 | (&mut self.allocator[..], index) |
490 | 0 | } |
491 | | /// Assert that a field is present in the just-finished Table. |
492 | | /// |
493 | | /// This is somewhat low-level and is mostly used by the generated code. |
494 | | #[inline] |
495 | 0 | pub fn required( |
496 | 0 | &self, |
497 | 0 | tab_revloc: WIPOffset<TableFinishedWIPOffset>, |
498 | 0 | slot_byte_loc: VOffsetT, |
499 | 0 | assert_msg_name: &'static str, |
500 | 0 | ) { |
501 | 0 | let idx = self.used_space() - tab_revloc.value() as usize; |
502 | | |
503 | | // Safety: |
504 | | // The value of TableFinishedWIPOffset is the offset from the end of the allocator |
505 | | // to an SOffsetT pointing to a valid VTable |
506 | | // |
507 | | // `self.allocator.len() = self.used_space() + self.head` |
508 | | // `self.allocator.len() - tab_revloc = self.used_space() - tab_revloc + self.head` |
509 | | // `self.allocator.len() - tab_revloc = idx + self.head` |
510 | 0 | let tab = unsafe { Table::new(&self.allocator[self.head.range_to_end()], idx) }; |
511 | 0 | let o = tab.vtable().get(slot_byte_loc) as usize; |
512 | 0 | assert!(o != 0, "missing required field {}", assert_msg_name); |
513 | 0 | } |
514 | | |
515 | | /// Finalize the FlatBuffer by: aligning it, pushing an optional file |
516 | | /// identifier on to it, pushing a size prefix on to it, and marking the |
517 | | /// internal state of the FlatBufferBuilder as `finished`. Afterwards, |
518 | | /// users can call `finished_data` to get the resulting data. |
519 | | #[inline] |
520 | 0 | pub fn finish_size_prefixed<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) { |
521 | 0 | self.finish_with_opts(root, file_identifier, true); |
522 | 0 | } |
523 | | |
524 | | /// Finalize the FlatBuffer by: aligning it, pushing an optional file |
525 | | /// identifier on to it, and marking the internal state of the |
526 | | /// FlatBufferBuilder as `finished`. Afterwards, users can call |
527 | | /// `finished_data` to get the resulting data. |
528 | | #[inline] |
529 | 0 | pub fn finish<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) { |
530 | 0 | self.finish_with_opts(root, file_identifier, false); |
531 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::finish::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::kind_generated::Kind> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::finish::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_generated::Value> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::finish::<_> |
532 | | |
533 | | /// Finalize the FlatBuffer by: aligning it and marking the internal state |
534 | | /// of the FlatBufferBuilder as `finished`. Afterwards, users can call |
535 | | /// `finished_data` to get the resulting data. |
536 | | #[inline] |
537 | 0 | pub fn finish_minimal<T>(&mut self, root: WIPOffset<T>) { |
538 | 0 | self.finish_with_opts(root, None, false); |
539 | 0 | } |
540 | | |
541 | | #[inline] |
542 | 0 | fn used_space(&self) -> usize { |
543 | 0 | self.head.distance_to_end() |
544 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::used_space Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::used_space |
545 | | |
546 | | #[inline] |
547 | 0 | fn track_field(&mut self, slot_off: VOffsetT, off: UOffsetT) { |
548 | 0 | let fl = FieldLoc { id: slot_off, off }; |
549 | 0 | self.field_locs.push(fl); |
550 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::track_field Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::track_field |
551 | | |
552 | | /// Write the VTable, if it is new. |
553 | 0 | fn write_vtable( |
554 | 0 | &mut self, |
555 | 0 | table_tail_revloc: WIPOffset<TableUnfinishedWIPOffset>, |
556 | 0 | ) -> WIPOffset<VTableWIPOffset> { |
557 | 0 | self.assert_nested("write_vtable"); |
558 | | |
559 | | // Write the vtable offset, which is the start of any Table. |
560 | | // We fill its value later. |
561 | 0 | let object_revloc_to_vtable: WIPOffset<VTableWIPOffset> = |
562 | 0 | WIPOffset::new(self.push::<UOffsetT>(0xF0F0_F0F0).value()); |
563 | | |
564 | | // Layout of the data this function will create when a new vtable is |
565 | | // needed. |
566 | | // -------------------------------------------------------------------- |
567 | | // vtable starts here |
568 | | // | x, x -- vtable len (bytes) [u16] |
569 | | // | x, x -- object inline len (bytes) [u16] |
570 | | // | x, x -- zero, or num bytes from start of object to field #0 [u16] |
571 | | // | ... |
572 | | // | x, x -- zero, or num bytes from start of object to field #n-1 [u16] |
573 | | // vtable ends here |
574 | | // table starts here |
575 | | // | x, x, x, x -- offset (negative direction) to the vtable [i32] |
576 | | // | aka "vtableoffset" |
577 | | // | -- table inline data begins here, we don't touch it -- |
578 | | // table ends here -- aka "table_start" |
579 | | // -------------------------------------------------------------------- |
580 | | // |
581 | | // Layout of the data this function will create when we re-use an |
582 | | // existing vtable. |
583 | | // |
584 | | // We always serialize this particular vtable, then compare it to the |
585 | | // other vtables we know about to see if there is a duplicate. If there |
586 | | // is, then we erase the serialized vtable we just made. |
587 | | // We serialize it first so that we are able to do byte-by-byte |
588 | | // comparisons with already-serialized vtables. This 1) saves |
589 | | // bookkeeping space (we only keep revlocs to existing vtables), 2) |
590 | | // allows us to convert to little-endian once, then do |
591 | | // fast memcmp comparisons, and 3) by ensuring we are comparing real |
592 | | // serialized vtables, we can be more assured that we are doing the |
593 | | // comparisons correctly. |
594 | | // |
595 | | // -------------------------------------------------------------------- |
596 | | // table starts here |
597 | | // | x, x, x, x -- offset (negative direction) to an existing vtable [i32] |
598 | | // | aka "vtableoffset" |
599 | | // | -- table inline data begins here, we don't touch it -- |
600 | | // table starts here: aka "table_start" |
601 | | // -------------------------------------------------------------------- |
602 | | |
603 | | // fill the WIP vtable with zeros: |
604 | 0 | let vtable_byte_len = get_vtable_byte_len(&self.field_locs); |
605 | 0 | self.make_space(vtable_byte_len); |
606 | | |
607 | | // compute the length of the table (not vtable!) in bytes: |
608 | 0 | let table_object_size = object_revloc_to_vtable.value() - table_tail_revloc.value(); |
609 | 0 | debug_assert!(table_object_size < 0x10000); // vTable use 16bit offsets. |
610 | | |
611 | | // Write the VTable (we may delete it afterwards, if it is a duplicate): |
612 | 0 | let vt_start_pos = self.head; |
613 | 0 | let vt_end_pos = self.head + vtable_byte_len; |
614 | | { |
615 | | // write the vtable header: |
616 | 0 | let vtfw = |
617 | 0 | &mut VTableWriter::init(&mut self.allocator[vt_start_pos.range_to(vt_end_pos)]); |
618 | 0 | vtfw.write_vtable_byte_length(vtable_byte_len as VOffsetT); |
619 | 0 | vtfw.write_object_inline_size(table_object_size as VOffsetT); |
620 | | |
621 | | // serialize every FieldLoc to the vtable: |
622 | 0 | for &fl in self.field_locs.iter() { |
623 | 0 | let pos: VOffsetT = (object_revloc_to_vtable.value() - fl.off) as VOffsetT; |
624 | 0 | vtfw.write_field_offset(fl.id, pos); |
625 | 0 | } |
626 | | } |
627 | 0 | let new_vt_bytes = &self.allocator[vt_start_pos.range_to(vt_end_pos)]; |
628 | 0 | let found = self.written_vtable_revpos.binary_search_by(|old_vtable_revpos: &UOffsetT| { |
629 | 0 | let old_vtable_pos = self.allocator.len() - *old_vtable_revpos as usize; |
630 | | // Safety: |
631 | | // Already written vtables are valid by construction |
632 | 0 | let old_vtable = unsafe { VTable::init(&self.allocator, old_vtable_pos) }; |
633 | 0 | new_vt_bytes.cmp(old_vtable.as_bytes()) |
634 | 0 | }); Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::write_vtable::{closure#0}Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::write_vtable::{closure#0} |
635 | 0 | let final_vtable_revpos = match found { |
636 | 0 | Ok(i) => { |
637 | | // The new vtable is a duplicate so clear it. |
638 | 0 | VTableWriter::init(&mut self.allocator[vt_start_pos.range_to(vt_end_pos)]).clear(); |
639 | 0 | self.head += vtable_byte_len; |
640 | 0 | self.written_vtable_revpos[i] |
641 | | } |
642 | 0 | Err(i) => { |
643 | | // This is a new vtable. Add it to the cache. |
644 | 0 | let new_vt_revpos = self.used_space() as UOffsetT; |
645 | 0 | self.written_vtable_revpos.insert(i, new_vt_revpos); |
646 | 0 | new_vt_revpos |
647 | | } |
648 | | }; |
649 | | // Write signed offset from table to its vtable. |
650 | 0 | let table_pos = self.allocator.len() - object_revloc_to_vtable.value() as usize; |
651 | 0 | if cfg!(debug_assertions) { |
652 | | // Safety: |
653 | | // Verified slice length |
654 | 0 | let tmp_soffset_to_vt = unsafe { |
655 | 0 | read_scalar::<UOffsetT>(&self.allocator[table_pos..table_pos + SIZE_UOFFSET]) |
656 | | }; |
657 | 0 | assert_eq!(tmp_soffset_to_vt, 0xF0F0_F0F0); |
658 | 0 | } |
659 | | |
660 | 0 | let buf = &mut self.allocator[table_pos..table_pos + SIZE_SOFFSET]; |
661 | | // Safety: |
662 | | // Verified length of buf above |
663 | 0 | unsafe { |
664 | 0 | emplace_scalar::<SOffsetT>( |
665 | 0 | buf, |
666 | 0 | final_vtable_revpos as SOffsetT - object_revloc_to_vtable.value() as SOffsetT, |
667 | 0 | ); |
668 | 0 | } |
669 | | |
670 | 0 | self.field_locs.clear(); |
671 | | |
672 | 0 | object_revloc_to_vtable |
673 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::write_vtable Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::write_vtable |
674 | | |
675 | | // Only call this when you know it is safe to double the size of the buffer. |
676 | | #[inline] |
677 | 0 | fn grow_allocator(&mut self) { |
678 | 0 | let starting_active_size = self.used_space(); |
679 | 0 | self.allocator.grow_downwards().expect("Flatbuffer allocation failure"); |
680 | | |
681 | 0 | let ending_active_size = self.used_space(); |
682 | 0 | debug_assert_eq!(starting_active_size, ending_active_size); |
683 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::grow_allocator Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::grow_allocator |
684 | | |
685 | | // with or without a size prefix changes how we load the data, so finish* |
686 | | // functions are split along those lines. |
687 | 0 | fn finish_with_opts<T>( |
688 | 0 | &mut self, |
689 | 0 | root: WIPOffset<T>, |
690 | 0 | file_identifier: Option<&str>, |
691 | 0 | size_prefixed: bool, |
692 | 0 | ) { |
693 | 0 | self.assert_not_finished("buffer cannot be finished when it is already finished"); |
694 | 0 | self.assert_not_nested( |
695 | | "buffer cannot be finished when a table or vector is under construction", |
696 | | ); |
697 | 0 | self.written_vtable_revpos.clear(); |
698 | | |
699 | 0 | let to_align = { |
700 | | // for the root offset: |
701 | 0 | let a = SIZE_UOFFSET; |
702 | | // for the size prefix: |
703 | 0 | let b = if size_prefixed { SIZE_UOFFSET } else { 0 }; |
704 | | // for the file identifier (a string that is not zero-terminated): |
705 | 0 | let c = if file_identifier.is_some() { FILE_IDENTIFIER_LENGTH } else { 0 }; |
706 | 0 | a + b + c |
707 | | }; |
708 | | |
709 | 0 | { |
710 | 0 | let ma = PushAlignment::new(self.min_align); |
711 | 0 | self.align(to_align, ma); |
712 | 0 | } |
713 | | |
714 | 0 | if let Some(ident) = file_identifier { |
715 | 0 | debug_assert_eq!(ident.len(), FILE_IDENTIFIER_LENGTH); |
716 | 0 | self.push_bytes_unprefixed(ident.as_bytes()); |
717 | 0 | } |
718 | | |
719 | 0 | self.push(root); |
720 | | |
721 | 0 | if size_prefixed { |
722 | 0 | let sz = self.used_space() as UOffsetT; |
723 | 0 | self.push::<UOffsetT>(sz); |
724 | 0 | } |
725 | 0 | self.finished = true; |
726 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::finish_with_opts::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::kind_generated::Kind> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::finish_with_opts::<surrealdb_protocol::fb::generated::surrealdb::protocol::v_1::value_generated::Value> Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::finish_with_opts::<_> |
727 | | |
728 | | #[inline] |
729 | 0 | fn align(&mut self, len: usize, alignment: PushAlignment) { |
730 | 0 | self.track_min_align(alignment.value()); |
731 | 0 | let s = self.used_space() as usize; |
732 | 0 | self.make_space(padding_bytes(s + len, alignment.value())); |
733 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::align Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::align |
734 | | |
735 | | #[inline] |
736 | 0 | fn track_min_align(&mut self, alignment: usize) { |
737 | 0 | self.min_align = max(self.min_align, alignment); |
738 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::track_min_align Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::track_min_align |
739 | | |
740 | | #[inline] |
741 | 0 | fn push_bytes_unprefixed(&mut self, x: &[u8]) -> UOffsetT { |
742 | 0 | let n = self.make_space(x.len()); |
743 | 0 | self.allocator[n.range_to(n + x.len())].copy_from_slice(x); |
744 | | |
745 | 0 | n.to_forward_index(&self.allocator) as UOffsetT |
746 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::push_bytes_unprefixed Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::push_bytes_unprefixed |
747 | | |
748 | | #[inline] |
749 | 0 | fn make_space(&mut self, want: usize) -> ReverseIndex { |
750 | 0 | self.ensure_capacity(want); |
751 | 0 | self.head -= want; |
752 | 0 | self.head |
753 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::make_space Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::make_space |
754 | | |
755 | | #[inline] |
756 | 0 | fn ensure_capacity(&mut self, want: usize) -> usize { |
757 | 0 | if self.unused_ready_space() >= want { |
758 | 0 | return want; |
759 | 0 | } |
760 | 0 | assert!(want <= FLATBUFFERS_MAX_BUFFER_SIZE, "cannot grow buffer beyond 2 gigabytes"); |
761 | | |
762 | 0 | while self.unused_ready_space() < want { |
763 | 0 | self.grow_allocator(); |
764 | 0 | } |
765 | 0 | want |
766 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::ensure_capacity Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::ensure_capacity |
767 | | #[inline] |
768 | 0 | fn unused_ready_space(&self) -> usize { |
769 | 0 | self.allocator.len() - self.head.distance_to_end() |
770 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::unused_ready_space Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::unused_ready_space |
771 | | #[inline] |
772 | 0 | fn assert_nested(&self, fn_name: &'static str) { |
773 | | // we don't assert that self.field_locs.len() >0 because the vtable |
774 | | // could be empty (e.g. for empty tables, or for all-default values). |
775 | 0 | debug_assert!( |
776 | 0 | self.nested, |
777 | | "incorrect FlatBufferBuilder usage: {} must be called while in a nested state", |
778 | | fn_name |
779 | | ); |
780 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::assert_nested Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::assert_nested |
781 | | #[inline] |
782 | 0 | fn assert_not_nested(&self, msg: &'static str) { |
783 | 0 | debug_assert!(!self.nested, "{}", msg); |
784 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::assert_not_nested Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::assert_not_nested |
785 | | #[inline] |
786 | 0 | fn assert_finished(&self, msg: &'static str) { |
787 | 0 | debug_assert!(self.finished, "{}", msg); |
788 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::assert_finished Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::assert_finished |
789 | | #[inline] |
790 | 0 | fn assert_not_finished(&self, msg: &'static str) { |
791 | 0 | debug_assert!(!self.finished, "{}", msg); |
792 | 0 | } Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder>::assert_not_finished Unexecuted instantiation: <flatbuffers::builder::FlatBufferBuilder<_>>::assert_not_finished |
793 | | } |
794 | | |
795 | | /// Compute the length of the vtable needed to represent the provided FieldLocs. |
796 | | /// If there are no FieldLocs, then provide the minimum number of bytes |
797 | | /// required: enough to write the VTable header. |
798 | | #[inline] |
799 | 0 | fn get_vtable_byte_len(field_locs: &[FieldLoc]) -> usize { |
800 | 0 | let max_voffset = field_locs.iter().map(|fl| fl.id).max(); |
801 | 0 | match max_voffset { |
802 | 0 | None => field_index_to_field_offset(0) as usize, |
803 | 0 | Some(mv) => mv as usize + SIZE_VOFFSET, |
804 | | } |
805 | 0 | } Unexecuted instantiation: flatbuffers::builder::get_vtable_byte_len Unexecuted instantiation: flatbuffers::builder::get_vtable_byte_len |
806 | | |
807 | | #[inline] |
808 | 0 | fn padding_bytes(buf_size: usize, scalar_size: usize) -> usize { |
809 | | // ((!buf_size) + 1) & (scalar_size - 1) |
810 | 0 | (!buf_size).wrapping_add(1) & (scalar_size.wrapping_sub(1)) |
811 | 0 | } Unexecuted instantiation: flatbuffers::builder::padding_bytes Unexecuted instantiation: flatbuffers::builder::padding_bytes |
812 | | |
813 | | impl<'fbb> Default for FlatBufferBuilder<'fbb> { |
814 | 0 | fn default() -> Self { |
815 | 0 | Self::with_capacity(0) |
816 | 0 | } |
817 | | } |
818 | | |
819 | | /// An index that indexes from the reverse of a slice. |
820 | | /// |
821 | | /// Note that while the internal representation is an index |
822 | | /// from the end of a buffer, operations like `Add` and `Sub` |
823 | | /// behave like a regular index: |
824 | | /// |
825 | | /// # Examples |
826 | | /// |
827 | | /// ```ignore |
828 | | /// let buf = [0, 1, 2, 3, 4, 5]; |
829 | | /// let idx = ReverseIndex::end() - 2; |
830 | | /// assert_eq!(&buf[idx.range_to_end()], &[4, 5]); |
831 | | /// assert_eq!(idx.to_forward_index(&buf), 4); |
832 | | /// ``` |
833 | | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
834 | | struct ReverseIndex(usize); |
835 | | |
836 | | impl ReverseIndex { |
837 | | /// Returns an index set to the end. |
838 | | /// |
839 | | /// Note: Indexing this will result in an out of bounds error. |
840 | 0 | pub fn end() -> Self { |
841 | 0 | Self(0) |
842 | 0 | } |
843 | | |
844 | | /// Returns a struct equivalent to the range `self..` |
845 | 0 | pub fn range_to_end(self) -> ReverseIndexRange { |
846 | 0 | ReverseIndexRange(self, ReverseIndex::end()) |
847 | 0 | } |
848 | | |
849 | | /// Returns a struct equivalent to the range `self..end` |
850 | 0 | pub fn range_to(self, end: ReverseIndex) -> ReverseIndexRange { |
851 | 0 | ReverseIndexRange(self, end) |
852 | 0 | } |
853 | | |
854 | | /// Transforms this reverse index into a regular index for the given buffer. |
855 | 0 | pub fn to_forward_index<T>(self, buf: &[T]) -> usize { |
856 | 0 | buf.len() - self.0 |
857 | 0 | } |
858 | | |
859 | | /// Returns the number of elements until the end of the range. |
860 | 0 | pub fn distance_to_end(&self) -> usize { |
861 | 0 | self.0 |
862 | 0 | } |
863 | | } |
864 | | |
865 | | impl Sub<usize> for ReverseIndex { |
866 | | type Output = Self; |
867 | | |
868 | 0 | fn sub(self, rhs: usize) -> Self::Output { |
869 | 0 | Self(self.0 + rhs) |
870 | 0 | } |
871 | | } |
872 | | |
873 | | impl SubAssign<usize> for ReverseIndex { |
874 | 0 | fn sub_assign(&mut self, rhs: usize) { |
875 | 0 | *self = *self - rhs; |
876 | 0 | } |
877 | | } |
878 | | |
879 | | impl Add<usize> for ReverseIndex { |
880 | | type Output = Self; |
881 | | |
882 | 0 | fn add(self, rhs: usize) -> Self::Output { |
883 | 0 | Self(self.0 - rhs) |
884 | 0 | } |
885 | | } |
886 | | |
887 | | impl AddAssign<usize> for ReverseIndex { |
888 | 0 | fn add_assign(&mut self, rhs: usize) { |
889 | 0 | *self = *self + rhs; |
890 | 0 | } |
891 | | } |
892 | | impl<T> Index<ReverseIndex> for [T] { |
893 | | type Output = T; |
894 | | |
895 | 0 | fn index(&self, index: ReverseIndex) -> &Self::Output { |
896 | 0 | let index = index.to_forward_index(self); |
897 | 0 | &self[index] |
898 | 0 | } |
899 | | } |
900 | | |
901 | | impl<T> IndexMut<ReverseIndex> for [T] { |
902 | 0 | fn index_mut(&mut self, index: ReverseIndex) -> &mut Self::Output { |
903 | 0 | let index = index.to_forward_index(self); |
904 | 0 | &mut self[index] |
905 | 0 | } |
906 | | } |
907 | | |
908 | | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
909 | | struct ReverseIndexRange(ReverseIndex, ReverseIndex); |
910 | | |
911 | | impl<T> Index<ReverseIndexRange> for [T] { |
912 | | type Output = [T]; |
913 | | |
914 | 0 | fn index(&self, index: ReverseIndexRange) -> &Self::Output { |
915 | 0 | let start = index.0.to_forward_index(self); |
916 | 0 | let end = index.1.to_forward_index(self); |
917 | 0 | &self[start..end] |
918 | 0 | } Unexecuted instantiation: <[u8] as core::ops::index::Index<flatbuffers::builder::ReverseIndexRange>>::index Unexecuted instantiation: <[_] as core::ops::index::Index<flatbuffers::builder::ReverseIndexRange>>::index |
919 | | } |
920 | | |
921 | | impl<T> IndexMut<ReverseIndexRange> for [T] { |
922 | 0 | fn index_mut(&mut self, index: ReverseIndexRange) -> &mut Self::Output { |
923 | 0 | let start = index.0.to_forward_index(self); |
924 | 0 | let end = index.1.to_forward_index(self); |
925 | 0 | &mut self[start..end] |
926 | 0 | } Unexecuted instantiation: <[u8] as core::ops::index::IndexMut<flatbuffers::builder::ReverseIndexRange>>::index_mut Unexecuted instantiation: <[_] as core::ops::index::IndexMut<flatbuffers::builder::ReverseIndexRange>>::index_mut |
927 | | } |
928 | | |
929 | | #[cfg(test)] |
930 | | mod tests { |
931 | | use super::*; |
932 | | |
933 | | #[test] |
934 | | fn reverse_index_test() { |
935 | | let buf = [0, 1, 2, 3, 4, 5]; |
936 | | let idx = ReverseIndex::end() - 2; |
937 | | assert_eq!(&buf[idx.range_to_end()], &[4, 5]); |
938 | | assert_eq!(&buf[idx.range_to(idx + 1)], &[4]); |
939 | | assert_eq!(idx.to_forward_index(&buf), 4); |
940 | | } |
941 | | } |