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