// Copyright 2019 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //! A wrapper for structures that contain flexible arrays. use std::marker::PhantomData; use std::mem::size_of; // Returns a `Vec` with a size in bytes at least as large as `size_in_bytes`. fn vec_with_size_in_bytes(size_in_bytes: usize) -> Vec { let rounded_size = (size_in_bytes + size_of::() - 1) / size_of::(); let mut v = Vec::with_capacity(rounded_size); for _ in 0..rounded_size { v.push(T::default()) } v } /// The kernel API has many structs that resemble the following `Foo` structure: /// /// ```ignore /// #[repr(C)] /// struct Foo { /// some_data: u32, /// entries: __IncompleteArrayField<__u32>, /// } /// ``` /// /// In order to allocate such a structure, `size_of::()` would be too small because it would /// not include any space for `entries`. To make the allocation large enough while still being /// aligned for `Foo`, a `Vec` is created. Only the first element of `Vec` would actually /// be used as a `Foo`. The remaining memory in the `Vec` is for `entries`, which must be /// contiguous with `Foo`. This function is used to make the `Vec` with enough space for /// `count` entries. pub fn vec_with_array_field(count: usize) -> Vec { let element_space = count * size_of::(); let vec_size_bytes = size_of::() + element_space; vec_with_size_in_bytes(vec_size_bytes) } /// The following code provides generic helpers for creating and accessing flexible array structs. /// A complete definition of flexible array structs is found in the ISO 9899 specification /// (http://www.iso-9899.info/n1570.html). A flexible array struct is of the form: /// /// ``` /// #[repr(C)] /// struct T { /// some_data: u32, /// nent: u32 /// entries: __IncompleteArrayField, /// } /// ``` /// where: /// /// - `T` is the flexible array struct type /// - `S` is the flexible array type /// - `nent` is the flexible array length /// - `entries` is the flexible array member /// /// These structures are used by the kernel API. /// A collection of methods that are required by the FlexibleArrayWrapper type. /// /// When implemented for `T`, this trait allows the caller to set number of `S` entries and /// retrieve a slice of `S` entries. Trait methods must only be called by the FlexibleArrayWrapper /// type. pub trait FlexibleArray { /// Implementations must set flexible array length in the flexible array struct to the value /// specified by `len`. Appropriate conversions (i.e, usize to u32) are allowed so long as /// they don't overflow or underflow. fn set_len(&mut self, len: usize); /// Implementations must return the length of the flexible array member. Appropriate /// conversions (i.e, usize to u32) are allowed so long as they don't overflow or underflow. fn get_len(&self) -> usize; /// Implementations must return a slice of flexible array member of length `len`. fn get_slice(&self, len: usize) -> &[S]; /// Implementations must return a mutable slice of flexible array member of length `len`. fn get_mut_slice(&mut self, len: usize) -> &mut [S]; } pub struct FlexibleArrayWrapper { entries: Vec, phantom: PhantomData, allocated_len: usize, } /// Convenience wrapper for flexible array structs. /// /// The FlexibleArray trait must be implemented for the flexible array struct before using this /// wrapper. impl FlexibleArrayWrapper where T: FlexibleArray + Default, { /// Creates a new FlexibleArrayWrapper for the given flexible array struct type and flexible /// array type. The flexible array length is set to `array_len`. vec_with_array_field is used /// to make sure the resultant wrapper is appropriately sized. pub fn new(array_len: usize) -> FlexibleArrayWrapper { let mut entries = vec_with_array_field::(array_len); entries[0].set_len(array_len); FlexibleArrayWrapper { entries, phantom: PhantomData, allocated_len: array_len, } } /// Mapping the unsized array to a slice is unsafe because the length isn't known. Using /// the length we originally allocated with eliminates the possibility of overflow. fn get_valid_len(&self) -> usize { if self.entries[0].get_len() > self.allocated_len { self.allocated_len } else { self.entries[0].get_len() } } /// Returns a slice of the flexible array member, for inspecting. To modify, use /// mut_entries_slice instead. pub fn entries_slice(&self) -> &[S] { let valid_length = self.get_valid_len(); self.entries[0].get_slice(valid_length) } /// Returns a mutable slice of the flexible array member, for modifying. pub fn mut_entries_slice(&mut self) -> &mut [S] { let valid_length = self.get_valid_len(); self.entries[0].set_len(valid_length); self.entries[0].get_mut_slice(valid_length) } /// Get a pointer so it can be passed to the kernel. Callers must not access the flexible /// array member. Using this pointer is unsafe. pub fn as_ptr(&self) -> *const T { &self.entries[0] } /// Get a mutable pointer so it can be passed to the kernel. Callers must not access the /// flexible array member. Using this pointer is unsafe. pub fn as_mut_ptr(&mut self) -> *mut T { &mut self.entries[0] } }