/rust/registry/src/index.crates.io-1949cf8c6b5b557f/vfio-ioctls-0.5.1/src/fam.rs
Line | Count | Source |
1 | | // Copyright © 2019 Intel Corporation |
2 | | // |
3 | | // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause |
4 | | |
5 | | // This is a private version of vmm-sys-util::FamStruct. As it works smoothly, we keep it for |
6 | | // simplicity. |
7 | | |
8 | | use std::mem::size_of; |
9 | | |
10 | | /// Returns a `Vec<T>` with a size in bytes at least as large as `size_in_bytes`. |
11 | 0 | fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> { |
12 | 0 | let rounded_size = size_in_bytes.div_ceil(size_of::<T>()); |
13 | 0 | let mut v = Vec::with_capacity(rounded_size); |
14 | 0 | for _ in 0..rounded_size { |
15 | 0 | v.push(T::default()) |
16 | | } |
17 | 0 | v |
18 | 0 | } Unexecuted instantiation: vfio_ioctls::fam::vec_with_size_in_bytes::<vfio_ioctls::vfio_device::vfio_region_info_with_cap> Unexecuted instantiation: vfio_ioctls::fam::vec_with_size_in_bytes::<vfio_bindings::vfio_bindings::vfio::vfio_irq_set> |
19 | | |
20 | | /// The VFIO API has several structs that resembles the following `Foo` structure: |
21 | | /// |
22 | | /// ``` |
23 | | /// struct ControlMessageHeader { |
24 | | /// r#type: u8, |
25 | | /// length: u8, |
26 | | /// } |
27 | | /// |
28 | | /// #[repr(C)] |
29 | | /// pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>); |
30 | | /// #[repr(C)] |
31 | | /// struct Foo { |
32 | | /// some_data: ControlMessageHeader, |
33 | | /// entries: __IncompleteArrayField<u32>, |
34 | | /// } |
35 | | /// ``` |
36 | | /// |
37 | | /// In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would not |
38 | | /// include any space for `entries`. To make the allocation large enough while still being aligned |
39 | | /// for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually be used |
40 | | /// as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be contiguous |
41 | | /// with `Foo`. This function is used to make the `Vec<Foo>` with enough space for `count` entries. |
42 | 0 | pub(crate) fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> { |
43 | 0 | let element_space = match count.checked_mul(size_of::<F>()) { |
44 | 0 | None => panic!("allocating too large buffer with vec_with_array_field"), |
45 | 0 | Some(v) => v, |
46 | | }; |
47 | 0 | let vec_size_bytes = match element_space.checked_add(size_of::<T>()) { |
48 | 0 | None => panic!("allocating too large buffer with vec_with_array_field"), |
49 | 0 | Some(v) => v, |
50 | | }; |
51 | | |
52 | 0 | vec_with_size_in_bytes(vec_size_bytes) |
53 | 0 | } Unexecuted instantiation: vfio_ioctls::fam::vec_with_array_field::<vfio_ioctls::vfio_device::vfio_region_info_with_cap, u8> Unexecuted instantiation: vfio_ioctls::fam::vec_with_array_field::<vfio_bindings::vfio_bindings::vfio::vfio_irq_set, u32> |
54 | | |
55 | | #[cfg(test)] |
56 | | mod tests { |
57 | | use super::*; |
58 | | |
59 | | #[derive(Default)] |
60 | | #[allow(dead_code)] |
61 | | struct Header { |
62 | | ty: u32, |
63 | | len: u32, |
64 | | } |
65 | | |
66 | | #[allow(dead_code)] |
67 | | struct Field { |
68 | | f1: u64, |
69 | | f2: u64, |
70 | | } |
71 | | |
72 | | #[test] |
73 | | fn test_vec_with_array_field() { |
74 | | let v1 = vec_with_array_field::<Header, Field>(1); |
75 | | assert_eq!(v1.len(), 3); |
76 | | |
77 | | let v2 = vec_with_array_field::<Header, Field>(0); |
78 | | assert_eq!(v2.len(), 1); |
79 | | |
80 | | let v3 = vec_with_array_field::<Header, Field>(5); |
81 | | assert_eq!(v3.len(), 11); |
82 | | } |
83 | | |
84 | | #[test] |
85 | | #[should_panic] |
86 | | fn test_vec_with_array_field_overflow() { |
87 | | let _ = vec_with_array_field::<Header, Field>(usize::MAX); |
88 | | } |
89 | | } |