data_model/
flexible_array.rs

1// Copyright 2019 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! A wrapper for structures that contain flexible arrays.
6//!
7//! The following code provides generic helpers for creating and accessing flexible array structs.
8//! A complete definition of flexible array structs is found in the ISO 9899 specification
9//! <http://www.iso-9899.info/n1570.html>. A flexible array struct is of the form:
10//!
11//! ```ignore
12//! #[repr(C)]
13//! struct T {
14//!    some_data: u32,
15//!    nents: u32,
16//!    entries: __IncompleteArrayField<S>,
17//! }
18//! ```
19//! where:
20//!
21//! - `T` is the flexible array struct type
22//! - `S` is the flexible array type
23//! - `nents` is the flexible array length
24//! - `entries` is the flexible array member
25//!
26//! These structures are used by the kernel API.
27
28use std::marker::PhantomData;
29use std::mem::size_of;
30
31// Returns a `Vec<T>` with a size in bytes at least as large as `size_in_bytes`.
32fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> {
33    let rounded_size = size_in_bytes.div_ceil(size_of::<T>());
34    let mut v = Vec::with_capacity(rounded_size);
35    v.resize_with(rounded_size, T::default);
36    v
37}
38
39/// The kernel API has many structs that resemble the following `Foo` structure:
40///
41/// ```ignore
42/// #[repr(C)]
43/// struct Foo {
44///    some_data: u32,
45///    entries: __IncompleteArrayField<__u32>,
46/// }
47/// ```
48///
49/// In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would
50/// not include any space for `entries`. To make the allocation large enough while still being
51/// aligned for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually
52/// be used as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be
53/// contiguous with `Foo`. This function is used to make the `Vec<Foo>` with enough space for
54/// `count` entries.
55pub fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> {
56    let element_space = count * size_of::<F>();
57    let vec_size_bytes = size_of::<T>() + element_space;
58    vec_with_size_in_bytes(vec_size_bytes)
59}
60
61/// A collection of methods that are required by the FlexibleArrayWrapper type.
62///
63/// When implemented for `T`, this trait allows the caller to set number of `S` entries and
64/// retrieve a slice of `S` entries.  Trait methods must only be called by the FlexibleArrayWrapper
65/// type.  Don't implement this trait directly, use the flexible_array! macro to avoid duplication.
66pub trait FlexibleArray<S> {
67    /// Implementations must set flexible array length in the flexible array struct to the value
68    /// specified by `len`. Appropriate conversions (i.e, usize to u32) are allowed so long as
69    /// they don't overflow or underflow.
70    fn set_len(&mut self, len: usize);
71    /// Implementations must return the length of the flexible array member.  Appropriate
72    /// conversions (i.e, usize to u32) are allowed so long as they don't overflow or underflow.
73    fn get_len(&self) -> usize;
74    /// Implementations must return a slice of flexible array member of length `len`.
75    /// # Safety
76    /// Do not use this function directly, as the FlexibleArrayWrapper will guarantee safety.
77    unsafe fn get_slice(&self, len: usize) -> &[S];
78    /// Implementations must return a mutable slice of flexible array member of length `len`.
79    /// # Safety
80    /// Do not use this function directly, as the FlexibleArrayWrapper will guarantee safety.
81    unsafe fn get_mut_slice(&mut self, len: usize) -> &mut [S];
82}
83
84/// Always use this macro for implementing the FlexibleArray<`S`> trait for a given `T`.  There
85/// exists an 1:1 mapping of macro identifiers to the definitions in the FlexibleArray<`S`>
86/// documentation, so refer to that for more information.
87#[macro_export]
88macro_rules! flexible_array_impl {
89    ($T:ident, $S:ident, $nents:ident, $entries:ident) => {
90        impl $crate::FlexibleArray<$S> for $T {
91            fn set_len(&mut self, len: usize) {
92                self.$nents = ::std::convert::TryInto::try_into(len).unwrap();
93            }
94
95            fn get_len(&self) -> usize {
96                self.$nents as usize
97            }
98
99            unsafe fn get_slice(&self, len: usize) -> &[$S] {
100                self.$entries.as_slice(len)
101            }
102
103            unsafe fn get_mut_slice(&mut self, len: usize) -> &mut [$S] {
104                self.$entries.as_mut_slice(len)
105            }
106        }
107    };
108}
109
110pub struct FlexibleArrayWrapper<T, S> {
111    entries: Vec<T>,
112    phantom: PhantomData<S>,
113    allocated_len: usize,
114}
115
116/// Convenience wrapper for flexible array structs.
117///
118/// The FlexibleArray trait must be implemented for the flexible array struct before using this
119/// wrapper.
120impl<T, S> FlexibleArrayWrapper<T, S>
121where
122    T: FlexibleArray<S> + Default,
123{
124    /// Creates a new FlexibleArrayWrapper for the given flexible array struct type and flexible
125    /// array type. The flexible array length is set to `array_len`. vec_with_array_field is used
126    /// to make sure the resultant wrapper is appropriately sized.
127    pub fn new(array_len: usize) -> FlexibleArrayWrapper<T, S> {
128        let mut entries = vec_with_array_field::<T, S>(array_len);
129        entries[0].set_len(array_len);
130
131        FlexibleArrayWrapper {
132            entries,
133            phantom: PhantomData,
134            allocated_len: array_len,
135        }
136    }
137
138    /// Mapping the unsized array to a slice is unsafe because the length isn't known.  Using
139    /// the length we originally allocated with eliminates the possibility of overflow.
140    fn get_valid_len(&self) -> usize {
141        if self.entries[0].get_len() > self.allocated_len {
142            self.allocated_len
143        } else {
144            self.entries[0].get_len()
145        }
146    }
147
148    /// Returns a slice of the flexible array member, for inspecting. To modify, use
149    /// mut_entries_slice instead.
150    pub fn entries_slice(&self) -> &[S] {
151        let valid_length = self.get_valid_len();
152        // SAFETY:
153        // Safe because the length has been validated.
154        unsafe { self.entries[0].get_slice(valid_length) }
155    }
156
157    /// Returns a mutable slice of the flexible array member, for modifying.
158    pub fn mut_entries_slice(&mut self) -> &mut [S] {
159        let valid_length = self.get_valid_len();
160        self.entries[0].set_len(valid_length);
161        // SAFETY:
162        // Safe because the length has been validated.
163        unsafe { self.entries[0].get_mut_slice(valid_length) }
164    }
165
166    /// Get a pointer so it can be passed to the kernel. Callers must not access the flexible
167    /// array member.  Using this pointer is unsafe.
168    pub fn as_ptr(&self) -> *const T {
169        &self.entries[0]
170    }
171
172    /// Get a mutable pointer so it can be passed to the kernel. Callers must not access the
173    /// flexible array member.  Using this pointer is unsafe.
174    pub fn as_mut_ptr(&mut self) -> *mut T {
175        &mut self.entries[0]
176    }
177}