blob: 350e984abe7f2dda5f11b4786e6e83ceecb6e615 [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
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
17use std::marker::PhantomData;
18use std::mem::size_of;
19use std::ops::Deref;
20
Austin Schuh272c6132020-11-14 16:37:52 -080021use crate::endian_scalar::{emplace_scalar, read_scalar, read_scalar_at};
22use crate::follow::Follow;
23use crate::push::Push;
Austin Schuhe89fa2d2019-08-14 20:24:23 -070024
25pub const FLATBUFFERS_MAX_BUFFER_SIZE: usize = (1u64 << 31) as usize;
26
27pub const FILE_IDENTIFIER_LENGTH: usize = 4;
28
29pub const VTABLE_METADATA_FIELDS: usize = 2;
30
31pub const SIZE_U8: usize = size_of::<u8>();
32pub const SIZE_I8: usize = size_of::<i8>();
33
34pub const SIZE_U16: usize = size_of::<u16>();
35pub const SIZE_I16: usize = size_of::<i16>();
36
37pub const SIZE_U32: usize = size_of::<u32>();
38pub const SIZE_I32: usize = size_of::<i32>();
39
40pub const SIZE_U64: usize = size_of::<u64>();
41pub const SIZE_I64: usize = size_of::<i64>();
42
43pub const SIZE_F32: usize = size_of::<f32>();
44pub const SIZE_F64: usize = size_of::<f64>();
45
46pub const SIZE_SOFFSET: usize = SIZE_I32;
47pub const SIZE_UOFFSET: usize = SIZE_U32;
48pub const SIZE_VOFFSET: usize = SIZE_I16;
49
50pub const SIZE_SIZEPREFIX: usize = SIZE_UOFFSET;
51
Austin Schuh272c6132020-11-14 16:37:52 -080052/// SOffsetT is a relative pointer from tables to their vtables.
Austin Schuhe89fa2d2019-08-14 20:24:23 -070053pub type SOffsetT = i32;
54
Austin Schuh272c6132020-11-14 16:37:52 -080055/// UOffsetT is used represent both for relative pointers and lengths of vectors.
Austin Schuhe89fa2d2019-08-14 20:24:23 -070056pub type UOffsetT = u32;
57
Austin Schuh272c6132020-11-14 16:37:52 -080058/// VOffsetT is a relative pointer in vtables to point from tables to field data.
59pub type VOffsetT = u16;
Austin Schuhe89fa2d2019-08-14 20:24:23 -070060
61/// TableFinishedWIPOffset marks a WIPOffset as being for a finished table.
Austin Schuh272c6132020-11-14 16:37:52 -080062#[derive(Clone, Copy)]
Austin Schuhe89fa2d2019-08-14 20:24:23 -070063pub struct TableFinishedWIPOffset {}
64
65/// TableUnfinishedWIPOffset marks a WIPOffset as being for an unfinished table.
Austin Schuh272c6132020-11-14 16:37:52 -080066#[derive(Clone, Copy)]
Austin Schuhe89fa2d2019-08-14 20:24:23 -070067pub struct TableUnfinishedWIPOffset {}
68
69/// UnionWIPOffset marks a WIPOffset as being for a union value.
Austin Schuh272c6132020-11-14 16:37:52 -080070#[derive(Clone, Copy)]
Austin Schuhe89fa2d2019-08-14 20:24:23 -070071pub struct UnionWIPOffset {}
72
73/// VTableWIPOffset marks a WIPOffset as being for a vtable.
Austin Schuh272c6132020-11-14 16:37:52 -080074#[derive(Clone, Copy)]
Austin Schuhe89fa2d2019-08-14 20:24:23 -070075pub struct VTableWIPOffset {}
76
77/// WIPOffset contains an UOffsetT with a special meaning: it is the location of
78/// data relative to the *end* of an in-progress FlatBuffer. The
79/// FlatBufferBuilder uses this to track the location of objects in an absolute
80/// way. The impl of Push converts a WIPOffset into a ForwardsUOffset.
81#[derive(Debug)]
82pub struct WIPOffset<T>(UOffsetT, PhantomData<T>);
83
Austin Schuh272c6132020-11-14 16:37:52 -080084// We cannot use derive for these two impls, as the derived impls would only
85// implement `Copy` and `Clone` for `T: Copy` and `T: Clone` respectively.
86// However `WIPOffset<T>` can always be copied, no matter that `T` you
87// have.
Austin Schuhe89fa2d2019-08-14 20:24:23 -070088impl<T> Copy for WIPOffset<T> {}
89impl<T> Clone for WIPOffset<T> {
Austin Schuh272c6132020-11-14 16:37:52 -080090 #[inline(always)]
91 fn clone(&self) -> Self {
92 *self
Austin Schuhe89fa2d2019-08-14 20:24:23 -070093 }
94}
Austin Schuh272c6132020-11-14 16:37:52 -080095
Austin Schuhe89fa2d2019-08-14 20:24:23 -070096impl<T> PartialEq for WIPOffset<T> {
97 fn eq(&self, o: &WIPOffset<T>) -> bool {
98 self.value() == o.value()
99 }
100}
101
102impl<T> Deref for WIPOffset<T> {
103 type Target = UOffsetT;
104 #[inline]
105 fn deref(&self) -> &UOffsetT {
106 &self.0
107 }
108}
109impl<'a, T: 'a> WIPOffset<T> {
110 /// Create a new WIPOffset.
111 #[inline]
112 pub fn new(o: UOffsetT) -> WIPOffset<T> {
113 WIPOffset {
114 0: o,
115 1: PhantomData,
116 }
117 }
118
119 /// Return a wrapped value that brings its meaning as a union WIPOffset
120 /// into the type system.
121 #[inline(always)]
Austin Schuh272c6132020-11-14 16:37:52 -0800122 pub fn as_union_value(self) -> WIPOffset<UnionWIPOffset> {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700123 WIPOffset::new(self.0)
124 }
125 /// Get the underlying value.
126 #[inline(always)]
Austin Schuh272c6132020-11-14 16:37:52 -0800127 pub fn value(self) -> UOffsetT {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700128 self.0
129 }
130}
131
132impl<T> Push for WIPOffset<T> {
133 type Output = ForwardsUOffset<T>;
134
135 #[inline(always)]
136 fn push(&self, dst: &mut [u8], rest: &[u8]) {
137 let n = (SIZE_UOFFSET + rest.len() - self.value() as usize) as UOffsetT;
138 emplace_scalar::<UOffsetT>(dst, n);
139 }
140}
141
142impl<T> Push for ForwardsUOffset<T> {
143 type Output = Self;
144
145 #[inline(always)]
146 fn push(&self, dst: &mut [u8], rest: &[u8]) {
147 self.value().push(dst, rest);
148 }
149}
150
151/// ForwardsUOffset is used by Follow to traverse a FlatBuffer: the pointer
152/// is incremented by the value contained in this type.
153#[derive(Debug)]
154pub struct ForwardsUOffset<T>(UOffsetT, PhantomData<T>);
Austin Schuh272c6132020-11-14 16:37:52 -0800155
156// We cannot use derive for these two impls, as the derived impls would only
157// implement `Copy` and `Clone` for `T: Copy` and `T: Clone` respectively.
158// However `ForwardsUOffset<T>` can always be copied, no matter that `T` you
159// have.
160impl<T> Copy for ForwardsUOffset<T> {}
161impl<T> Clone for ForwardsUOffset<T> {
162 #[inline(always)]
163 fn clone(&self) -> Self {
164 *self
165 }
166}
167
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700168impl<T> ForwardsUOffset<T> {
169 #[inline(always)]
Austin Schuh272c6132020-11-14 16:37:52 -0800170 pub fn value(self) -> UOffsetT {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700171 self.0
172 }
173}
174
175impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> {
176 type Inner = T::Inner;
177 #[inline(always)]
178 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
179 let slice = &buf[loc..loc + SIZE_UOFFSET];
180 let off = read_scalar::<u32>(slice) as usize;
181 T::follow(buf, loc + off)
182 }
183}
184
185/// ForwardsVOffset is used by Follow to traverse a FlatBuffer: the pointer
186/// is incremented by the value contained in this type.
187#[derive(Debug)]
188pub struct ForwardsVOffset<T>(VOffsetT, PhantomData<T>);
189impl<T> ForwardsVOffset<T> {
190 #[inline(always)]
191 pub fn value(&self) -> VOffsetT {
192 self.0
193 }
194}
195
196impl<'a, T: Follow<'a>> Follow<'a> for ForwardsVOffset<T> {
197 type Inner = T::Inner;
198 #[inline(always)]
199 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
200 let slice = &buf[loc..loc + SIZE_VOFFSET];
201 let off = read_scalar::<VOffsetT>(slice) as usize;
202 T::follow(buf, loc + off)
203 }
204}
205
206impl<T> Push for ForwardsVOffset<T> {
207 type Output = Self;
208
209 #[inline]
210 fn push(&self, dst: &mut [u8], rest: &[u8]) {
211 self.value().push(dst, rest);
212 }
213}
214
215/// ForwardsSOffset is used by Follow to traverse a FlatBuffer: the pointer
216/// is incremented by the *negative* of the value contained in this type.
217#[derive(Debug)]
218pub struct BackwardsSOffset<T>(SOffsetT, PhantomData<T>);
219impl<T> BackwardsSOffset<T> {
220 #[inline(always)]
221 pub fn value(&self) -> SOffsetT {
222 self.0
223 }
224}
225
226impl<'a, T: Follow<'a>> Follow<'a> for BackwardsSOffset<T> {
227 type Inner = T::Inner;
228 #[inline(always)]
229 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
230 let slice = &buf[loc..loc + SIZE_SOFFSET];
231 let off = read_scalar::<SOffsetT>(slice);
232 T::follow(buf, (loc as SOffsetT - off) as usize)
233 }
234}
235
236impl<T> Push for BackwardsSOffset<T> {
237 type Output = Self;
238
239 #[inline]
240 fn push(&self, dst: &mut [u8], rest: &[u8]) {
241 self.value().push(dst, rest);
242 }
243}
244
245/// SkipSizePrefix is used by Follow to traverse a FlatBuffer: the pointer is
246/// incremented by a fixed constant in order to skip over the size prefix value.
247pub struct SkipSizePrefix<T>(PhantomData<T>);
248impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipSizePrefix<T> {
249 type Inner = T::Inner;
250 #[inline(always)]
251 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
252 T::follow(buf, loc + SIZE_SIZEPREFIX)
253 }
254}
255
256/// SkipRootOffset is used by Follow to traverse a FlatBuffer: the pointer is
257/// incremented by a fixed constant in order to skip over the root offset value.
258pub struct SkipRootOffset<T>(PhantomData<T>);
259impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipRootOffset<T> {
260 type Inner = T::Inner;
261 #[inline(always)]
262 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
263 T::follow(buf, loc + SIZE_UOFFSET)
264 }
265}
266
267/// FileIdentifier is used by Follow to traverse a FlatBuffer: the pointer is
268/// dereferenced into a byte slice, whose bytes are the file identifer value.
269pub struct FileIdentifier;
270impl<'a> Follow<'a> for FileIdentifier {
271 type Inner = &'a [u8];
272 #[inline(always)]
273 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
274 &buf[loc..loc + FILE_IDENTIFIER_LENGTH]
275 }
276}
277
278/// SkipFileIdentifier is used by Follow to traverse a FlatBuffer: the pointer
279/// is incremented by a fixed constant in order to skip over the file
280/// identifier value.
281pub struct SkipFileIdentifier<T>(PhantomData<T>);
282impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipFileIdentifier<T> {
283 type Inner = T::Inner;
284 #[inline(always)]
285 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
286 T::follow(buf, loc + FILE_IDENTIFIER_LENGTH)
287 }
288}
289
Austin Schuh272c6132020-11-14 16:37:52 -0800290impl<'a> Follow<'a> for bool {
291 type Inner = bool;
292 #[inline(always)]
293 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
294 read_scalar_at::<u8>(buf, loc) != 0
295 }
296}
297
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700298/// Follow trait impls for primitive types.
299///
300/// Ideally, these would be implemented as a single impl using trait bounds on
301/// EndianScalar, but implementing Follow that way causes a conflict with
302/// other impls.
303macro_rules! impl_follow_for_endian_scalar {
304 ($ty:ident) => {
305 impl<'a> Follow<'a> for $ty {
306 type Inner = $ty;
307 #[inline(always)]
308 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
309 read_scalar_at::<$ty>(buf, loc)
310 }
311 }
312 };
313}
314
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700315impl_follow_for_endian_scalar!(u8);
316impl_follow_for_endian_scalar!(u16);
317impl_follow_for_endian_scalar!(u32);
318impl_follow_for_endian_scalar!(u64);
319impl_follow_for_endian_scalar!(i8);
320impl_follow_for_endian_scalar!(i16);
321impl_follow_for_endian_scalar!(i32);
322impl_follow_for_endian_scalar!(i64);
323impl_follow_for_endian_scalar!(f32);
324impl_follow_for_endian_scalar!(f64);