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