• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 crate::endian_scalar::{emplace_scalar, read_scalar, read_scalar_at};
22 use crate::follow::Follow;
23 use crate::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 a relative pointer from tables to their vtables.
53 pub type SOffsetT = i32;
54 
55 /// UOffsetT is used represent both for relative pointers and lengths of vectors.
56 pub type UOffsetT = u32;
57 
58 /// VOffsetT is a relative pointer in vtables to point from tables to field data.
59 pub type VOffsetT = u16;
60 
61 /// TableFinishedWIPOffset marks a WIPOffset as being for a finished table.
62 #[derive(Clone, Copy)]
63 pub struct TableFinishedWIPOffset {}
64 
65 /// TableUnfinishedWIPOffset marks a WIPOffset as being for an unfinished table.
66 #[derive(Clone, Copy)]
67 pub struct TableUnfinishedWIPOffset {}
68 
69 /// UnionWIPOffset marks a WIPOffset as being for a union value.
70 #[derive(Clone, Copy)]
71 pub struct UnionWIPOffset {}
72 
73 /// VTableWIPOffset marks a WIPOffset as being for a vtable.
74 #[derive(Clone, Copy)]
75 pub 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)]
82 pub struct WIPOffset<T>(UOffsetT, PhantomData<T>);
83 
84 // 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.
88 impl<T> Copy for WIPOffset<T> {}
89 impl<T> Clone for WIPOffset<T> {
90     #[inline(always)]
clone(&self) -> Self91     fn clone(&self) -> Self {
92         *self
93     }
94 }
95 
96 impl<T> Eq for WIPOffset<T> {}
97 
98 impl<T> PartialEq for WIPOffset<T> {
eq(&self, o: &WIPOffset<T>) -> bool99     fn eq(&self, o: &WIPOffset<T>) -> bool {
100         self.value() == o.value()
101     }
102 }
103 
104 impl<T> Deref for WIPOffset<T> {
105     type Target = UOffsetT;
106     #[inline]
deref(&self) -> &UOffsetT107     fn deref(&self) -> &UOffsetT {
108         &self.0
109     }
110 }
111 impl<'a, T: 'a> WIPOffset<T> {
112     /// Create a new WIPOffset.
113     #[inline]
new(o: UOffsetT) -> WIPOffset<T>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)]
as_union_value(self) -> WIPOffset<UnionWIPOffset>124     pub fn as_union_value(self) -> WIPOffset<UnionWIPOffset> {
125         WIPOffset::new(self.0)
126     }
127     /// Get the underlying value.
128     #[inline(always)]
value(self) -> UOffsetT129     pub fn value(self) -> UOffsetT {
130         self.0
131     }
132 }
133 
134 impl<T> Push for WIPOffset<T> {
135     type Output = ForwardsUOffset<T>;
136 
137     #[inline(always)]
push(&self, dst: &mut [u8], rest: &[u8])138     fn push(&self, dst: &mut [u8], rest: &[u8]) {
139         let n = (SIZE_UOFFSET + rest.len() - self.value() as usize) as UOffsetT;
140         unsafe {
141             emplace_scalar::<UOffsetT>(dst, n);
142         }
143     }
144 }
145 
146 impl<T> Push for ForwardsUOffset<T> {
147     type Output = Self;
148 
149     #[inline(always)]
push(&self, dst: &mut [u8], rest: &[u8])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)]
158 pub struct ForwardsUOffset<T>(UOffsetT, PhantomData<T>);
159 
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.
164 impl<T> Copy for ForwardsUOffset<T> {}
165 impl<T> Clone for ForwardsUOffset<T> {
166     #[inline(always)]
clone(&self) -> Self167     fn clone(&self) -> Self {
168         *self
169     }
170 }
171 
172 impl<T> ForwardsUOffset<T> {
173     #[inline(always)]
value(self) -> UOffsetT174     pub fn value(self) -> UOffsetT {
175         self.0
176     }
177 }
178 
179 impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> {
180     type Inner = T::Inner;
181     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner182     fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
183         let slice = &buf[loc..loc + SIZE_UOFFSET];
184         let off = unsafe { read_scalar::<u32>(slice) as usize };
185         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)]
192 pub struct ForwardsVOffset<T>(VOffsetT, PhantomData<T>);
193 impl<T> ForwardsVOffset<T> {
194     #[inline(always)]
value(&self) -> VOffsetT195     pub fn value(&self) -> VOffsetT {
196         self.0
197     }
198 }
199 
200 impl<'a, T: Follow<'a>> Follow<'a> for ForwardsVOffset<T> {
201     type Inner = T::Inner;
202     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner203     fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
204         let slice = &buf[loc..loc + SIZE_VOFFSET];
205         let off = unsafe { read_scalar::<VOffsetT>(slice) as usize };
206         T::follow(buf, loc + off)
207     }
208 }
209 
210 impl<T> Push for ForwardsVOffset<T> {
211     type Output = Self;
212 
213     #[inline]
push(&self, dst: &mut [u8], rest: &[u8])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)]
222 pub struct BackwardsSOffset<T>(SOffsetT, PhantomData<T>);
223 impl<T> BackwardsSOffset<T> {
224     #[inline(always)]
value(&self) -> SOffsetT225     pub fn value(&self) -> SOffsetT {
226         self.0
227     }
228 }
229 
230 impl<'a, T: Follow<'a>> Follow<'a> for BackwardsSOffset<T> {
231     type Inner = T::Inner;
232     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner233     fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
234         let slice = &buf[loc..loc + SIZE_SOFFSET];
235         let off = unsafe { read_scalar::<SOffsetT>(slice) };
236         T::follow(buf, (loc as SOffsetT - off) as usize)
237     }
238 }
239 
240 impl<T> Push for BackwardsSOffset<T> {
241     type Output = Self;
242 
243     #[inline]
push(&self, dst: &mut [u8], rest: &[u8])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.
251 pub struct SkipSizePrefix<T>(PhantomData<T>);
252 impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipSizePrefix<T> {
253     type Inner = T::Inner;
254     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner255     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.
262 pub struct SkipRootOffset<T>(PhantomData<T>);
263 impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipRootOffset<T> {
264     type Inner = T::Inner;
265     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner266     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.
273 pub struct FileIdentifier;
274 impl<'a> Follow<'a> for FileIdentifier {
275     type Inner = &'a [u8];
276     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner277     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.
285 pub struct SkipFileIdentifier<T>(PhantomData<T>);
286 impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipFileIdentifier<T> {
287     type Inner = T::Inner;
288     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner289     fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
290         T::follow(buf, loc + FILE_IDENTIFIER_LENGTH)
291     }
292 }
293 
294 impl<'a> Follow<'a> for bool {
295     type Inner = bool;
296     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner297     fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
298         unsafe { read_scalar_at::<u8>(buf, loc) != 0 }
299     }
300 }
301 
302 /// 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.
307 macro_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 {
313                 unsafe { read_scalar_at::<$ty>(buf, loc) }
314             }
315         }
316     };
317 }
318 
319 impl_follow_for_endian_scalar!(u8);
320 impl_follow_for_endian_scalar!(u16);
321 impl_follow_for_endian_scalar!(u32);
322 impl_follow_for_endian_scalar!(u64);
323 impl_follow_for_endian_scalar!(i8);
324 impl_follow_for_endian_scalar!(i16);
325 impl_follow_for_endian_scalar!(i32);
326 impl_follow_for_endian_scalar!(i64);
327 impl_follow_for_endian_scalar!(f32);
328 impl_follow_for_endian_scalar!(f64);
329