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