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 */
1617use crate::endian_scalar::read_scalar_at;
18use crate::follow::Follow;
19use crate::primitives::*;
2021/// VTable encapsulates read-only usage of a vtable. It is only to be used
22/// by generated code.
23#[derive(Debug)]
24pub struct VTable<'a> {
25 buf: &'a [u8],
26 loc: usize,
27}
2829impl<'a> PartialEq for VTable<'a> {
30fn eq(&self, other: &VTable) -> bool {
31self.as_bytes().eq(other.as_bytes())
32 }
33}
3435impl<'a> VTable<'a> {
36/// SAFETY
37 /// `buf` must contain a valid vtable at `loc`
38 ///
39 /// This consists of a number of `VOffsetT`
40 /// - size of vtable in bytes including size element
41 /// - size of object in bytes including the vtable offset
42 /// - n fields where n is the number of fields in the table's schema when the code was compiled
43pub unsafe fn init(buf: &'a [u8], loc: usize) -> Self {
44 VTable { buf, loc }
45 }
4647pub fn num_fields(&self) -> usize {
48 (self.num_bytes() / SIZE_VOFFSET) - 2
49}
5051pub fn num_bytes(&self) -> usize {
52// Safety:
53 // Valid VTable at time of construction
54unsafe { read_scalar_at::<VOffsetT>(self.buf, self.loc) as usize }
55 }
5657pub fn object_inline_num_bytes(&self) -> usize {
58// Safety:
59 // Valid VTable at time of construction
60let n = unsafe { read_scalar_at::<VOffsetT>(self.buf, self.loc + SIZE_VOFFSET) };
61 n as usize
62 }
6364pub fn get_field(&self, idx: usize) -> VOffsetT {
65// TODO(rw): distinguish between None and 0?
66if idx > self.num_fields() {
67return 0;
68 }
6970// Safety:
71 // Valid VTable at time of construction
72unsafe {
73 read_scalar_at::<VOffsetT>(
74self.buf,
75self.loc + SIZE_VOFFSET + SIZE_VOFFSET + SIZE_VOFFSET * idx,
76 )
77 }
78 }
7980pub fn get(&self, byte_loc: VOffsetT) -> VOffsetT {
81// TODO(rw): distinguish between None and 0?
82if byte_loc as usize + 2 > self.num_bytes() {
83return 0;
84 }
85// Safety:
86 // byte_loc is within bounds of vtable, which was valid at time of construction
87unsafe { read_scalar_at::<VOffsetT>(self.buf, self.loc + byte_loc as usize) }
88 }
8990pub fn as_bytes(&self) -> &[u8] {
91let len = self.num_bytes();
92&self.buf[self.loc..self.loc + len]
93 }
94}
9596#[allow(dead_code)]
97pub fn field_index_to_field_offset(field_id: VOffsetT) -> VOffsetT {
98// Should correspond to what end_table() below builds up.
99let fixed_fields = 2; // Vtable size and Object Size.
100((field_id + fixed_fields) * (SIZE_VOFFSET as VOffsetT)) as VOffsetT
101}
102103#[allow(dead_code)]
104pub fn field_offset_to_field_index(field_o: VOffsetT) -> VOffsetT {
105debug_assert!(field_o >= 2);
106let fixed_fields = 2; // VTable size and Object Size.
107(field_o / (SIZE_VOFFSET as VOffsetT)) - fixed_fields
108}
109110impl<'a> Follow<'a> for VTable<'a> {
111type Inner = VTable<'a>;
112unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
113 VTable::init(buf, loc)
114 }
115}