• 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 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 pub struct TableFinishedWIPOffset {}
64 
65 /// TableUnfinishedWIPOffset marks a WIPOffset as being for an unfinished table.
66 pub struct TableUnfinishedWIPOffset {}
67 
68 /// UnionWIPOffset marks a WIPOffset as being for a union value.
69 pub struct UnionWIPOffset {}
70 
71 /// VTableWIPOffset marks a WIPOffset as being for a vtable.
72 pub struct VTableWIPOffset {}
73 
74 /// WIPOffset contains an UOffsetT with a special meaning: it is the location of
75 /// data relative to the *end* of an in-progress FlatBuffer. The
76 /// FlatBufferBuilder uses this to track the location of objects in an absolute
77 /// way. The impl of Push converts a WIPOffset into a ForwardsUOffset.
78 #[derive(Debug)]
79 pub struct WIPOffset<T>(UOffsetT, PhantomData<T>);
80 
81 // TODO(rw): why do we need to reimplement (with a default impl) Copy to
82 //           avoid ownership errors?
83 impl<T> Copy for WIPOffset<T> {}
84 impl<T> Clone for WIPOffset<T> {
85     #[inline]
clone(&self) -> WIPOffset<T>86     fn clone(&self) -> WIPOffset<T> {
87         WIPOffset::new(self.0.clone())
88     }
89 }
90 impl<T> PartialEq for WIPOffset<T> {
eq(&self, o: &WIPOffset<T>) -> bool91     fn eq(&self, o: &WIPOffset<T>) -> bool {
92         self.value() == o.value()
93     }
94 }
95 
96 impl<T> Deref for WIPOffset<T> {
97     type Target = UOffsetT;
98     #[inline]
deref(&self) -> &UOffsetT99     fn deref(&self) -> &UOffsetT {
100         &self.0
101     }
102 }
103 impl<'a, T: 'a> WIPOffset<T> {
104     /// Create a new WIPOffset.
105     #[inline]
new(o: UOffsetT) -> WIPOffset<T>106     pub fn new(o: UOffsetT) -> WIPOffset<T> {
107         WIPOffset {
108             0: o,
109             1: PhantomData,
110         }
111     }
112 
113     /// Return a wrapped value that brings its meaning as a union WIPOffset
114     /// into the type system.
115     #[inline(always)]
as_union_value(&self) -> WIPOffset<UnionWIPOffset>116     pub fn as_union_value(&self) -> WIPOffset<UnionWIPOffset> {
117         WIPOffset::new(self.0)
118     }
119     /// Get the underlying value.
120     #[inline(always)]
value(&self) -> UOffsetT121     pub fn value(&self) -> UOffsetT {
122         self.0
123     }
124 }
125 
126 impl<T> Push for WIPOffset<T> {
127     type Output = ForwardsUOffset<T>;
128 
129     #[inline(always)]
push(&self, dst: &mut [u8], rest: &[u8])130     fn push(&self, dst: &mut [u8], rest: &[u8]) {
131         let n = (SIZE_UOFFSET + rest.len() - self.value() as usize) as UOffsetT;
132         emplace_scalar::<UOffsetT>(dst, n);
133     }
134 }
135 
136 impl<T> Push for ForwardsUOffset<T> {
137     type Output = Self;
138 
139     #[inline(always)]
push(&self, dst: &mut [u8], rest: &[u8])140     fn push(&self, dst: &mut [u8], rest: &[u8]) {
141         self.value().push(dst, rest);
142     }
143 }
144 
145 /// ForwardsUOffset is used by Follow to traverse a FlatBuffer: the pointer
146 /// is incremented by the value contained in this type.
147 #[derive(Debug)]
148 pub struct ForwardsUOffset<T>(UOffsetT, PhantomData<T>);
149 impl<T> ForwardsUOffset<T> {
150     #[inline(always)]
value(&self) -> UOffsetT151     pub fn value(&self) -> UOffsetT {
152         self.0
153     }
154 }
155 
156 impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> {
157     type Inner = T::Inner;
158     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner159     fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
160         let slice = &buf[loc..loc + SIZE_UOFFSET];
161         let off = read_scalar::<u32>(slice) as usize;
162         T::follow(buf, loc + off)
163     }
164 }
165 
166 /// ForwardsVOffset is used by Follow to traverse a FlatBuffer: the pointer
167 /// is incremented by the value contained in this type.
168 #[derive(Debug)]
169 pub struct ForwardsVOffset<T>(VOffsetT, PhantomData<T>);
170 impl<T> ForwardsVOffset<T> {
171     #[inline(always)]
value(&self) -> VOffsetT172     pub fn value(&self) -> VOffsetT {
173         self.0
174     }
175 }
176 
177 impl<'a, T: Follow<'a>> Follow<'a> for ForwardsVOffset<T> {
178     type Inner = T::Inner;
179     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner180     fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
181         let slice = &buf[loc..loc + SIZE_VOFFSET];
182         let off = read_scalar::<VOffsetT>(slice) as usize;
183         T::follow(buf, loc + off)
184     }
185 }
186 
187 impl<T> Push for ForwardsVOffset<T> {
188     type Output = Self;
189 
190     #[inline]
push(&self, dst: &mut [u8], rest: &[u8])191     fn push(&self, dst: &mut [u8], rest: &[u8]) {
192         self.value().push(dst, rest);
193     }
194 }
195 
196 /// ForwardsSOffset is used by Follow to traverse a FlatBuffer: the pointer
197 /// is incremented by the *negative* of the value contained in this type.
198 #[derive(Debug)]
199 pub struct BackwardsSOffset<T>(SOffsetT, PhantomData<T>);
200 impl<T> BackwardsSOffset<T> {
201     #[inline(always)]
value(&self) -> SOffsetT202     pub fn value(&self) -> SOffsetT {
203         self.0
204     }
205 }
206 
207 impl<'a, T: Follow<'a>> Follow<'a> for BackwardsSOffset<T> {
208     type Inner = T::Inner;
209     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner210     fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
211         let slice = &buf[loc..loc + SIZE_SOFFSET];
212         let off = read_scalar::<SOffsetT>(slice);
213         T::follow(buf, (loc as SOffsetT - off) as usize)
214     }
215 }
216 
217 impl<T> Push for BackwardsSOffset<T> {
218     type Output = Self;
219 
220     #[inline]
push(&self, dst: &mut [u8], rest: &[u8])221     fn push(&self, dst: &mut [u8], rest: &[u8]) {
222         self.value().push(dst, rest);
223     }
224 }
225 
226 /// SkipSizePrefix is used by Follow to traverse a FlatBuffer: the pointer is
227 /// incremented by a fixed constant in order to skip over the size prefix value.
228 pub struct SkipSizePrefix<T>(PhantomData<T>);
229 impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipSizePrefix<T> {
230     type Inner = T::Inner;
231     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner232     fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
233         T::follow(buf, loc + SIZE_SIZEPREFIX)
234     }
235 }
236 
237 /// SkipRootOffset is used by Follow to traverse a FlatBuffer: the pointer is
238 /// incremented by a fixed constant in order to skip over the root offset value.
239 pub struct SkipRootOffset<T>(PhantomData<T>);
240 impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipRootOffset<T> {
241     type Inner = T::Inner;
242     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner243     fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
244         T::follow(buf, loc + SIZE_UOFFSET)
245     }
246 }
247 
248 /// FileIdentifier is used by Follow to traverse a FlatBuffer: the pointer is
249 /// dereferenced into a byte slice, whose bytes are the file identifer value.
250 pub struct FileIdentifier;
251 impl<'a> Follow<'a> for FileIdentifier {
252     type Inner = &'a [u8];
253     #[inline(always)]
follow(buf: &'a [u8], loc: usize) -> Self::Inner254     fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
255         &buf[loc..loc + FILE_IDENTIFIER_LENGTH]
256     }
257 }
258 
259 /// SkipFileIdentifier is used by Follow to traverse a FlatBuffer: the pointer
260 /// is incremented by a fixed constant in order to skip over the file
261 /// identifier value.
262 pub struct SkipFileIdentifier<T>(PhantomData<T>);
263 impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipFileIdentifier<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 + FILE_IDENTIFIER_LENGTH)
268     }
269 }
270 
271 /// Follow trait impls for primitive types.
272 ///
273 /// Ideally, these would be implemented as a single impl using trait bounds on
274 /// EndianScalar, but implementing Follow that way causes a conflict with
275 /// other impls.
276 macro_rules! impl_follow_for_endian_scalar {
277     ($ty:ident) => (
278         impl<'a> Follow<'a> for $ty {
279             type Inner = $ty;
280             #[inline(always)]
281             fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
282                 read_scalar_at::<$ty>(buf, loc)
283             }
284         }
285     )
286 }
287 
288 impl_follow_for_endian_scalar!(bool);
289 impl_follow_for_endian_scalar!(u8);
290 impl_follow_for_endian_scalar!(u16);
291 impl_follow_for_endian_scalar!(u32);
292 impl_follow_for_endian_scalar!(u64);
293 impl_follow_for_endian_scalar!(i8);
294 impl_follow_for_endian_scalar!(i16);
295 impl_follow_for_endian_scalar!(i32);
296 impl_follow_for_endian_scalar!(i64);
297 impl_follow_for_endian_scalar!(f32);
298 impl_follow_for_endian_scalar!(f64);
299