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 core::ptr::write_bytes; 18 19 use crate::endian_scalar::emplace_scalar; 20 use crate::primitives::*; 21 22 /// VTableWriter compartmentalizes actions needed to create a vtable. 23 #[derive(Debug)] 24 pub struct VTableWriter<'a> { 25 buf: &'a mut [u8], 26 } 27 28 impl<'a> VTableWriter<'a> { 29 #[inline(always)] init(buf: &'a mut [u8]) -> Self30 pub fn init(buf: &'a mut [u8]) -> Self { 31 VTableWriter { buf } 32 } 33 34 /// Writes the vtable length (in bytes) into the vtable. 35 /// 36 /// Note that callers already need to have computed this to initialize 37 /// a VTableWriter. 38 /// 39 /// In debug mode, asserts that the length of the underlying data is equal 40 /// to the provided value. 41 #[inline(always)] write_vtable_byte_length(&mut self, n: VOffsetT)42 pub fn write_vtable_byte_length(&mut self, n: VOffsetT) { 43 let buf = &mut self.buf[..SIZE_VOFFSET]; 44 // Safety: 45 // Validated range above 46 unsafe { 47 emplace_scalar::<VOffsetT>(buf, n); 48 } 49 debug_assert_eq!(n as usize, self.buf.len()); 50 } 51 52 /// Writes an object length (in bytes) into the vtable. 53 #[inline(always)] write_object_inline_size(&mut self, n: VOffsetT)54 pub fn write_object_inline_size(&mut self, n: VOffsetT) { 55 let buf = &mut self.buf[SIZE_VOFFSET..2 * SIZE_VOFFSET]; 56 // Safety: 57 // Validated range above 58 unsafe { 59 emplace_scalar::<VOffsetT>(buf, n); 60 } 61 } 62 63 /// Writes an object field offset into the vtable. 64 /// 65 /// Note that this expects field offsets (which are like pointers), not 66 /// field ids (which are like array indices). 67 #[inline(always)] write_field_offset(&mut self, vtable_offset: VOffsetT, object_data_offset: VOffsetT)68 pub fn write_field_offset(&mut self, vtable_offset: VOffsetT, object_data_offset: VOffsetT) { 69 let idx = vtable_offset as usize; 70 let buf = &mut self.buf[idx..idx + SIZE_VOFFSET]; 71 // Safety: 72 // Validated range above 73 unsafe { 74 emplace_scalar::<VOffsetT>(buf, object_data_offset); 75 } 76 } 77 78 /// Clears all data in this VTableWriter. Used to cleanly undo a 79 /// vtable write. 80 #[inline(always)] clear(&mut self)81 pub fn clear(&mut self) { 82 // This is the closest thing to memset in Rust right now. 83 let len = self.buf.len(); 84 let p = self.buf.as_mut_ptr() as *mut u8; 85 86 // Safety: 87 // p is byte aligned and of length `len` 88 unsafe { 89 write_bytes(p, 0, len); 90 } 91 } 92 } 93