blob: 72764b2136541a2969ba8338c1994cc20ee8fbfb [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
James Kuszmaul8e62b022022-03-22 09:33:25 -070017use core::marker::PhantomData;
18use core::mem::size_of;
19use core::ops::Deref;
Austin Schuhe89fa2d2019-08-14 20:24:23 -070020
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
James Kuszmaul8e62b022022-03-22 09:33:25 -070096impl<T> Eq for WIPOffset<T> {}
97
Austin Schuhe89fa2d2019-08-14 20:24:23 -070098impl<T> PartialEq for WIPOffset<T> {
99 fn eq(&self, o: &WIPOffset<T>) -> bool {
100 self.value() == o.value()
101 }
102}
103
104impl<T> Deref for WIPOffset<T> {
105 type Target = UOffsetT;
106 #[inline]
107 fn deref(&self) -> &UOffsetT {
108 &self.0
109 }
110}
111impl<'a, T: 'a> WIPOffset<T> {
112 /// Create a new WIPOffset.
113 #[inline]
114 pub fn new(o: UOffsetT) -> WIPOffset<T> {
115 WIPOffset {
116 0: o,
117 1: PhantomData,
118 }
119 }
120
121 /// Return a wrapped value that brings its meaning as a union WIPOffset
122 /// into the type system.
123 #[inline(always)]
Austin Schuh272c6132020-11-14 16:37:52 -0800124 pub fn as_union_value(self) -> WIPOffset<UnionWIPOffset> {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700125 WIPOffset::new(self.0)
126 }
127 /// Get the underlying value.
128 #[inline(always)]
Austin Schuh272c6132020-11-14 16:37:52 -0800129 pub fn value(self) -> UOffsetT {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700130 self.0
131 }
132}
133
134impl<T> Push for WIPOffset<T> {
135 type Output = ForwardsUOffset<T>;
136
137 #[inline(always)]
138 fn push(&self, dst: &mut [u8], rest: &[u8]) {
139 let n = (SIZE_UOFFSET + rest.len() - self.value() as usize) as UOffsetT;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700140 unsafe {
141 emplace_scalar::<UOffsetT>(dst, n);
142 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700143 }
144}
145
146impl<T> Push for ForwardsUOffset<T> {
147 type Output = Self;
148
149 #[inline(always)]
150 fn push(&self, dst: &mut [u8], rest: &[u8]) {
151 self.value().push(dst, rest);
152 }
153}
154
155/// ForwardsUOffset is used by Follow to traverse a FlatBuffer: the pointer
156/// is incremented by the value contained in this type.
157#[derive(Debug)]
158pub struct ForwardsUOffset<T>(UOffsetT, PhantomData<T>);
Austin Schuh272c6132020-11-14 16:37:52 -0800159
160// We cannot use derive for these two impls, as the derived impls would only
161// implement `Copy` and `Clone` for `T: Copy` and `T: Clone` respectively.
162// However `ForwardsUOffset<T>` can always be copied, no matter that `T` you
163// have.
164impl<T> Copy for ForwardsUOffset<T> {}
165impl<T> Clone for ForwardsUOffset<T> {
166 #[inline(always)]
167 fn clone(&self) -> Self {
168 *self
169 }
170}
171
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700172impl<T> ForwardsUOffset<T> {
173 #[inline(always)]
Austin Schuh272c6132020-11-14 16:37:52 -0800174 pub fn value(self) -> UOffsetT {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700175 self.0
176 }
177}
178
179impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> {
180 type Inner = T::Inner;
181 #[inline(always)]
182 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
183 let slice = &buf[loc..loc + SIZE_UOFFSET];
James Kuszmaul8e62b022022-03-22 09:33:25 -0700184 let off = unsafe { read_scalar::<u32>(slice) as usize };
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700185 T::follow(buf, loc + off)
186 }
187}
188
189/// ForwardsVOffset is used by Follow to traverse a FlatBuffer: the pointer
190/// is incremented by the value contained in this type.
191#[derive(Debug)]
192pub struct ForwardsVOffset<T>(VOffsetT, PhantomData<T>);
193impl<T> ForwardsVOffset<T> {
194 #[inline(always)]
195 pub fn value(&self) -> VOffsetT {
196 self.0
197 }
198}
199
200impl<'a, T: Follow<'a>> Follow<'a> for ForwardsVOffset<T> {
201 type Inner = T::Inner;
202 #[inline(always)]
203 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
204 let slice = &buf[loc..loc + SIZE_VOFFSET];
James Kuszmaul8e62b022022-03-22 09:33:25 -0700205 let off = unsafe { read_scalar::<VOffsetT>(slice) as usize };
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700206 T::follow(buf, loc + off)
207 }
208}
209
210impl<T> Push for ForwardsVOffset<T> {
211 type Output = Self;
212
213 #[inline]
214 fn push(&self, dst: &mut [u8], rest: &[u8]) {
215 self.value().push(dst, rest);
216 }
217}
218
219/// ForwardsSOffset is used by Follow to traverse a FlatBuffer: the pointer
220/// is incremented by the *negative* of the value contained in this type.
221#[derive(Debug)]
222pub struct BackwardsSOffset<T>(SOffsetT, PhantomData<T>);
223impl<T> BackwardsSOffset<T> {
224 #[inline(always)]
225 pub fn value(&self) -> SOffsetT {
226 self.0
227 }
228}
229
230impl<'a, T: Follow<'a>> Follow<'a> for BackwardsSOffset<T> {
231 type Inner = T::Inner;
232 #[inline(always)]
233 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
234 let slice = &buf[loc..loc + SIZE_SOFFSET];
James Kuszmaul8e62b022022-03-22 09:33:25 -0700235 let off = unsafe { read_scalar::<SOffsetT>(slice) };
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700236 T::follow(buf, (loc as SOffsetT - off) as usize)
237 }
238}
239
240impl<T> Push for BackwardsSOffset<T> {
241 type Output = Self;
242
243 #[inline]
244 fn push(&self, dst: &mut [u8], rest: &[u8]) {
245 self.value().push(dst, rest);
246 }
247}
248
249/// SkipSizePrefix is used by Follow to traverse a FlatBuffer: the pointer is
250/// incremented by a fixed constant in order to skip over the size prefix value.
251pub struct SkipSizePrefix<T>(PhantomData<T>);
252impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipSizePrefix<T> {
253 type Inner = T::Inner;
254 #[inline(always)]
255 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
256 T::follow(buf, loc + SIZE_SIZEPREFIX)
257 }
258}
259
260/// SkipRootOffset is used by Follow to traverse a FlatBuffer: the pointer is
261/// incremented by a fixed constant in order to skip over the root offset value.
262pub struct SkipRootOffset<T>(PhantomData<T>);
263impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipRootOffset<T> {
264 type Inner = T::Inner;
265 #[inline(always)]
266 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
267 T::follow(buf, loc + SIZE_UOFFSET)
268 }
269}
270
271/// FileIdentifier is used by Follow to traverse a FlatBuffer: the pointer is
272/// dereferenced into a byte slice, whose bytes are the file identifer value.
273pub struct FileIdentifier;
274impl<'a> Follow<'a> for FileIdentifier {
275 type Inner = &'a [u8];
276 #[inline(always)]
277 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
278 &buf[loc..loc + FILE_IDENTIFIER_LENGTH]
279 }
280}
281
282/// SkipFileIdentifier is used by Follow to traverse a FlatBuffer: the pointer
283/// is incremented by a fixed constant in order to skip over the file
284/// identifier value.
285pub struct SkipFileIdentifier<T>(PhantomData<T>);
286impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipFileIdentifier<T> {
287 type Inner = T::Inner;
288 #[inline(always)]
289 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
290 T::follow(buf, loc + FILE_IDENTIFIER_LENGTH)
291 }
292}
293
Austin Schuh272c6132020-11-14 16:37:52 -0800294impl<'a> Follow<'a> for bool {
295 type Inner = bool;
296 #[inline(always)]
297 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700298 unsafe { read_scalar_at::<u8>(buf, loc) != 0 }
Austin Schuh272c6132020-11-14 16:37:52 -0800299 }
300}
301
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700302/// Follow trait impls for primitive types.
303///
304/// Ideally, these would be implemented as a single impl using trait bounds on
305/// EndianScalar, but implementing Follow that way causes a conflict with
306/// other impls.
307macro_rules! impl_follow_for_endian_scalar {
308 ($ty:ident) => {
309 impl<'a> Follow<'a> for $ty {
310 type Inner = $ty;
311 #[inline(always)]
312 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700313 unsafe { read_scalar_at::<$ty>(buf, loc) }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700314 }
315 }
316 };
317}
318
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700319impl_follow_for_endian_scalar!(u8);
320impl_follow_for_endian_scalar!(u16);
321impl_follow_for_endian_scalar!(u32);
322impl_follow_for_endian_scalar!(u64);
323impl_follow_for_endian_scalar!(i8);
324impl_follow_for_endian_scalar!(i16);
325impl_follow_for_endian_scalar!(i32);
326impl_follow_for_endian_scalar!(i64);
327impl_follow_for_endian_scalar!(f32);
328impl_follow_for_endian_scalar!(f64);