blob: cfd4140486c314cd2bb3de969f787ac8080c55a2 [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
21use endian_scalar::{emplace_scalar, read_scalar, read_scalar_at};
22use follow::Follow;
23use push::Push;
24
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
52/// SOffsetT is an i32 that is used by tables to reference their vtables.
53pub type SOffsetT = i32;
54
55/// UOffsetT is a u32 that is used by pervasively to represent both pointers
56/// and lengths of vectors.
57pub type UOffsetT = u32;
58
59/// VOffsetT is a i32 that is used by vtables to store field data.
60pub type VOffsetT = i16;
61
62/// TableFinishedWIPOffset marks a WIPOffset as being for a finished table.
63pub struct TableFinishedWIPOffset {}
64
65/// TableUnfinishedWIPOffset marks a WIPOffset as being for an unfinished table.
66pub struct TableUnfinishedWIPOffset {}
67
68/// UnionWIPOffset marks a WIPOffset as being for a union value.
69pub struct UnionWIPOffset {}
70
71/// VTableWIPOffset marks a WIPOffset as being for a vtable.
72pub 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)]
79pub 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?
83impl<T> Copy for WIPOffset<T> {}
84impl<T> Clone for WIPOffset<T> {
85 #[inline]
86 fn clone(&self) -> WIPOffset<T> {
87 WIPOffset::new(self.0.clone())
88 }
89}
90impl<T> PartialEq for WIPOffset<T> {
91 fn eq(&self, o: &WIPOffset<T>) -> bool {
92 self.value() == o.value()
93 }
94}
95
96impl<T> Deref for WIPOffset<T> {
97 type Target = UOffsetT;
98 #[inline]
99 fn deref(&self) -> &UOffsetT {
100 &self.0
101 }
102}
103impl<'a, T: 'a> WIPOffset<T> {
104 /// Create a new WIPOffset.
105 #[inline]
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)]
116 pub fn as_union_value(&self) -> WIPOffset<UnionWIPOffset> {
117 WIPOffset::new(self.0)
118 }
119 /// Get the underlying value.
120 #[inline(always)]
121 pub fn value(&self) -> UOffsetT {
122 self.0
123 }
124}
125
126impl<T> Push for WIPOffset<T> {
127 type Output = ForwardsUOffset<T>;
128
129 #[inline(always)]
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
136impl<T> Push for ForwardsUOffset<T> {
137 type Output = Self;
138
139 #[inline(always)]
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)]
148pub struct ForwardsUOffset<T>(UOffsetT, PhantomData<T>);
149impl<T> ForwardsUOffset<T> {
150 #[inline(always)]
151 pub fn value(&self) -> UOffsetT {
152 self.0
153 }
154}
155
156impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> {
157 type Inner = T::Inner;
158 #[inline(always)]
159 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)]
169pub struct ForwardsVOffset<T>(VOffsetT, PhantomData<T>);
170impl<T> ForwardsVOffset<T> {
171 #[inline(always)]
172 pub fn value(&self) -> VOffsetT {
173 self.0
174 }
175}
176
177impl<'a, T: Follow<'a>> Follow<'a> for ForwardsVOffset<T> {
178 type Inner = T::Inner;
179 #[inline(always)]
180 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
187impl<T> Push for ForwardsVOffset<T> {
188 type Output = Self;
189
190 #[inline]
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)]
199pub struct BackwardsSOffset<T>(SOffsetT, PhantomData<T>);
200impl<T> BackwardsSOffset<T> {
201 #[inline(always)]
202 pub fn value(&self) -> SOffsetT {
203 self.0
204 }
205}
206
207impl<'a, T: Follow<'a>> Follow<'a> for BackwardsSOffset<T> {
208 type Inner = T::Inner;
209 #[inline(always)]
210 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
217impl<T> Push for BackwardsSOffset<T> {
218 type Output = Self;
219
220 #[inline]
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.
228pub struct SkipSizePrefix<T>(PhantomData<T>);
229impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipSizePrefix<T> {
230 type Inner = T::Inner;
231 #[inline(always)]
232 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.
239pub struct SkipRootOffset<T>(PhantomData<T>);
240impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipRootOffset<T> {
241 type Inner = T::Inner;
242 #[inline(always)]
243 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.
250pub struct FileIdentifier;
251impl<'a> Follow<'a> for FileIdentifier {
252 type Inner = &'a [u8];
253 #[inline(always)]
254 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.
262pub struct SkipFileIdentifier<T>(PhantomData<T>);
263impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipFileIdentifier<T> {
264 type Inner = T::Inner;
265 #[inline(always)]
266 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.
276macro_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
288impl_follow_for_endian_scalar!(bool);
289impl_follow_for_endian_scalar!(u8);
290impl_follow_for_endian_scalar!(u16);
291impl_follow_for_endian_scalar!(u32);
292impl_follow_for_endian_scalar!(u64);
293impl_follow_for_endian_scalar!(i8);
294impl_follow_for_endian_scalar!(i16);
295impl_follow_for_endian_scalar!(i32);
296impl_follow_for_endian_scalar!(i64);
297impl_follow_for_endian_scalar!(f32);
298impl_follow_for_endian_scalar!(f64);