blob: 66653ebe4e06634f9b844b7d19d43743b43774d2 [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::slice::from_raw_parts;
20use std::str::from_utf8_unchecked;
21
22#[cfg(target_endian = "little")]
23use endian_scalar::EndianScalar;
24use endian_scalar::{read_scalar, read_scalar_at};
25use follow::Follow;
26use primitives::*;
27
28#[derive(Debug)]
29pub struct Vector<'a, T: 'a>(&'a [u8], usize, PhantomData<T>);
30
31impl<'a, T: 'a> Vector<'a, T> {
32 #[inline(always)]
33 pub fn new(buf: &'a [u8], loc: usize) -> Self {
34 Vector {
35 0: buf,
36 1: loc,
37 2: PhantomData,
38 }
39 }
40
41 #[inline(always)]
42 pub fn len(&self) -> usize {
43 read_scalar::<UOffsetT>(&self.0[self.1 as usize..]) as usize
44 }
45}
46
47impl<'a, T: Follow<'a> + 'a> Vector<'a, T> {
48 #[inline(always)]
49 pub fn get(&self, idx: usize) -> T::Inner {
50 debug_assert!(idx < read_scalar::<u32>(&self.0[self.1 as usize..]) as usize);
51 let sz = size_of::<T>();
52 debug_assert!(sz > 0);
53 T::follow(self.0, self.1 as usize + SIZE_UOFFSET + sz * idx)
54 }
55}
56
57pub trait SafeSliceAccess {}
58impl<'a, T: SafeSliceAccess + 'a> Vector<'a, T> {
59 pub fn safe_slice(self) -> &'a [T] {
60 let buf = self.0;
61 let loc = self.1;
62 let sz = size_of::<T>();
63 debug_assert!(sz > 0);
64 let len = read_scalar_at::<UOffsetT>(&buf, loc) as usize;
65 let data_buf = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len * sz];
66 let ptr = data_buf.as_ptr() as *const T;
67 let s: &'a [T] = unsafe { from_raw_parts(ptr, len) };
68 s
69 }
70}
71
72impl SafeSliceAccess for u8 {}
73impl SafeSliceAccess for i8 {}
74impl SafeSliceAccess for bool {}
75
76#[cfg(target_endian = "little")]
77mod le_safe_slice_impls {
78 impl super::SafeSliceAccess for u16 {}
79 impl super::SafeSliceAccess for u32 {}
80 impl super::SafeSliceAccess for u64 {}
81
82 impl super::SafeSliceAccess for i16 {}
83 impl super::SafeSliceAccess for i32 {}
84 impl super::SafeSliceAccess for i64 {}
85
86 impl super::SafeSliceAccess for f32 {}
87 impl super::SafeSliceAccess for f64 {}
88}
89
90#[cfg(target_endian = "little")]
91pub use self::le_safe_slice_impls::*;
92
93pub fn follow_cast_ref<'a, T: Sized + 'a>(buf: &'a [u8], loc: usize) -> &'a T {
94 let sz = size_of::<T>();
95 let buf = &buf[loc..loc + sz];
96 let ptr = buf.as_ptr() as *const T;
97 unsafe { &*ptr }
98}
99
100impl<'a> Follow<'a> for &'a str {
101 type Inner = &'a str;
102 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
103 let len = read_scalar_at::<UOffsetT>(&buf, loc) as usize;
104 let slice = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len];
105 let s = unsafe { from_utf8_unchecked(slice) };
106 s
107 }
108}
109
110#[cfg(target_endian = "little")]
111fn follow_slice_helper<T>(buf: &[u8], loc: usize) -> &[T] {
112 let sz = size_of::<T>();
113 debug_assert!(sz > 0);
114 let len = read_scalar_at::<UOffsetT>(&buf, loc) as usize;
115 let data_buf = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len * sz];
116 let ptr = data_buf.as_ptr() as *const T;
117 let s: &[T] = unsafe { from_raw_parts(ptr, len) };
118 s
119}
120
121/// Implement direct slice access if the host is little-endian.
122#[cfg(target_endian = "little")]
123impl<'a, T: EndianScalar> Follow<'a> for &'a [T] {
124 type Inner = &'a [T];
125 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
126 follow_slice_helper::<T>(buf, loc)
127 }
128}
129
130/// Implement Follow for all possible Vectors that have Follow-able elements.
131impl<'a, T: Follow<'a> + 'a> Follow<'a> for Vector<'a, T> {
132 type Inner = Vector<'a, T>;
133 fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
134 Vector::new(buf, loc)
135 }
136}