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