flatbuffers/
primitives.rs

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
17use core::marker::PhantomData;
18use core::mem::size_of;
19use core::ops::Deref;
20
21use crate::endian_scalar::{emplace_scalar, read_scalar, read_scalar_at};
22use crate::follow::Follow;
23use crate::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 a relative pointer from tables to their vtables.
53pub type SOffsetT = i32;
54
55/// UOffsetT is used represent both for relative pointers and lengths of vectors.
56pub type UOffsetT = u32;
57
58/// VOffsetT is a relative pointer in vtables to point from tables to field data.
59pub type VOffsetT = u16;
60
61/// TableFinishedWIPOffset marks a WIPOffset as being for a finished table.
62#[derive(Clone, Copy)]
63pub struct TableFinishedWIPOffset {}
64
65/// TableUnfinishedWIPOffset marks a WIPOffset as being for an unfinished table.
66#[derive(Clone, Copy)]
67pub struct TableUnfinishedWIPOffset {}
68
69/// UnionWIPOffset marks a WIPOffset as being for a union value.
70#[derive(Clone, Copy)]
71pub struct UnionWIPOffset {}
72
73/// VTableWIPOffset marks a WIPOffset as being for a vtable.
74#[derive(Clone, Copy)]
75pub 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
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.
88impl<T> Copy for WIPOffset<T> {}
89impl<T> Clone for WIPOffset<T> {
90    #[inline(always)]
91    fn clone(&self) -> Self {
92        *self
93    }
94}
95
96impl<T> Eq for WIPOffset<T> {}
97
98impl<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(o, PhantomData)
116    }
117
118    /// Return a wrapped value that brings its meaning as a union WIPOffset
119    /// into the type system.
120    #[inline(always)]
121    pub fn as_union_value(self) -> WIPOffset<UnionWIPOffset> {
122        WIPOffset::new(self.0)
123    }
124    /// Get the underlying value.
125    #[inline(always)]
126    pub fn value(self) -> UOffsetT {
127        self.0
128    }
129}
130
131impl<T> Push for WIPOffset<T> {
132    type Output = ForwardsUOffset<T>;
133
134    #[inline(always)]
135    unsafe fn push(&self, dst: &mut [u8], written_len: usize) {
136        let n = (SIZE_UOFFSET + written_len - self.value() as usize) as UOffsetT;
137        emplace_scalar::<UOffsetT>(dst, n);
138    }
139}
140
141impl<T> Push for ForwardsUOffset<T> {
142    type Output = Self;
143
144    #[inline(always)]
145    unsafe fn push(&self, dst: &mut [u8], written_len: usize) {
146        self.value().push(dst, written_len);
147    }
148}
149
150/// ForwardsUOffset is used by Follow to traverse a FlatBuffer: the pointer
151/// is incremented by the value contained in this type.
152#[derive(Debug)]
153pub struct ForwardsUOffset<T>(UOffsetT, PhantomData<T>);
154
155// We cannot use derive for these two impls, as the derived impls would only
156// implement `Copy` and `Clone` for `T: Copy` and `T: Clone` respectively.
157// However `ForwardsUOffset<T>` can always be copied, no matter that `T` you
158// have.
159impl<T> Copy for ForwardsUOffset<T> {}
160impl<T> Clone for ForwardsUOffset<T> {
161    #[inline(always)]
162    fn clone(&self) -> Self {
163        *self
164    }
165}
166
167impl<T> ForwardsUOffset<T> {
168    #[inline(always)]
169    pub fn value(self) -> UOffsetT {
170        self.0
171    }
172}
173
174impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> {
175    type Inner = T::Inner;
176    #[inline(always)]
177    unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
178        let slice = &buf[loc..loc + SIZE_UOFFSET];
179        let off = read_scalar::<u32>(slice) as usize;
180        T::follow(buf, loc + off)
181    }
182}
183
184/// ForwardsVOffset is used by Follow to traverse a FlatBuffer: the pointer
185/// is incremented by the value contained in this type.
186#[derive(Debug)]
187pub struct ForwardsVOffset<T>(VOffsetT, PhantomData<T>);
188impl<T> ForwardsVOffset<T> {
189    #[inline(always)]
190    pub fn value(&self) -> VOffsetT {
191        self.0
192    }
193}
194
195impl<'a, T: Follow<'a>> Follow<'a> for ForwardsVOffset<T> {
196    type Inner = T::Inner;
197    #[inline(always)]
198    unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
199        let slice = &buf[loc..loc + SIZE_VOFFSET];
200        let off = read_scalar::<VOffsetT>(slice) as usize;
201        T::follow(buf, loc + off)
202    }
203}
204
205impl<T> Push for ForwardsVOffset<T> {
206    type Output = Self;
207
208    #[inline]
209    unsafe fn push(&self, dst: &mut [u8], written_len: usize) {
210        self.value().push(dst, written_len);
211    }
212}
213
214/// ForwardsSOffset is used by Follow to traverse a FlatBuffer: the pointer
215/// is incremented by the *negative* of the value contained in this type.
216#[derive(Debug)]
217pub struct BackwardsSOffset<T>(SOffsetT, PhantomData<T>);
218impl<T> BackwardsSOffset<T> {
219    #[inline(always)]
220    pub fn value(&self) -> SOffsetT {
221        self.0
222    }
223}
224
225impl<'a, T: Follow<'a>> Follow<'a> for BackwardsSOffset<T> {
226    type Inner = T::Inner;
227    #[inline(always)]
228    unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
229        let slice = &buf[loc..loc + SIZE_SOFFSET];
230        let off = read_scalar::<SOffsetT>(slice);
231        T::follow(buf, (loc as SOffsetT - off) as usize)
232    }
233}
234
235impl<T> Push for BackwardsSOffset<T> {
236    type Output = Self;
237
238    #[inline]
239    unsafe fn push(&self, dst: &mut [u8], written_len: usize) {
240        self.value().push(dst, written_len);
241    }
242}
243
244/// SkipSizePrefix is used by Follow to traverse a FlatBuffer: the pointer is
245/// incremented by a fixed constant in order to skip over the size prefix value.
246pub struct SkipSizePrefix<T>(PhantomData<T>);
247impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipSizePrefix<T> {
248    type Inner = T::Inner;
249    #[inline(always)]
250    unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
251        T::follow(buf, loc + SIZE_SIZEPREFIX)
252    }
253}
254
255/// SkipRootOffset is used by Follow to traverse a FlatBuffer: the pointer is
256/// incremented by a fixed constant in order to skip over the root offset value.
257pub struct SkipRootOffset<T>(PhantomData<T>);
258impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipRootOffset<T> {
259    type Inner = T::Inner;
260    #[inline(always)]
261    unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
262        T::follow(buf, loc + SIZE_UOFFSET)
263    }
264}
265
266/// FileIdentifier is used by Follow to traverse a FlatBuffer: the pointer is
267/// dereferenced into a byte slice, whose bytes are the file identifer value.
268pub struct FileIdentifier;
269impl<'a> Follow<'a> for FileIdentifier {
270    type Inner = &'a [u8];
271    #[inline(always)]
272    unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
273        &buf[loc..loc + FILE_IDENTIFIER_LENGTH]
274    }
275}
276
277/// SkipFileIdentifier is used by Follow to traverse a FlatBuffer: the pointer
278/// is incremented by a fixed constant in order to skip over the file
279/// identifier value.
280pub struct SkipFileIdentifier<T>(PhantomData<T>);
281impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipFileIdentifier<T> {
282    type Inner = T::Inner;
283    #[inline(always)]
284    unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
285        T::follow(buf, loc + FILE_IDENTIFIER_LENGTH)
286    }
287}
288
289impl<'a> Follow<'a> for bool {
290    type Inner = bool;
291    #[inline(always)]
292    unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
293        read_scalar_at::<u8>(buf, loc) != 0
294    }
295}
296
297/// Follow trait impls for primitive types.
298///
299/// Ideally, these would be implemented as a single impl using trait bounds on
300/// EndianScalar, but implementing Follow that way causes a conflict with
301/// other impls.
302macro_rules! impl_follow_for_endian_scalar {
303    ($ty:ident) => {
304        impl<'a> Follow<'a> for $ty {
305            type Inner = $ty;
306            #[inline(always)]
307            unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
308                read_scalar_at::<$ty>(buf, loc)
309            }
310        }
311    };
312}
313
314impl_follow_for_endian_scalar!(u8);
315impl_follow_for_endian_scalar!(u16);
316impl_follow_for_endian_scalar!(u32);
317impl_follow_for_endian_scalar!(u64);
318impl_follow_for_endian_scalar!(i8);
319impl_follow_for_endian_scalar!(i16);
320impl_follow_for_endian_scalar!(i32);
321impl_follow_for_endian_scalar!(i64);
322impl_follow_for_endian_scalar!(f32);
323impl_follow_for_endian_scalar!(f64);