mssf_core/mem.rs
1// ------------------------------------------------------------
2// Copyright (c) Microsoft Corporation. All rights reserved.
3// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
4// ------------------------------------------------------------
5
6/// A pool to hold boxes to extend their lifetime.
7/// This is typically useful to build raw COM structures that require
8/// raw pointers in struct fields.
9#[derive(Debug, Default)]
10pub struct BoxPool {
11 inner: Vec<Box<dyn 'static + std::any::Any>>,
12}
13
14impl BoxPool {
15 pub fn new() -> Self {
16 Self { inner: Vec::new() }
17 }
18
19 /// Push a box into the pool, and return a raw pointer to the boxed value.
20 /// The pointer is valid as long as the pool is alive.
21 #[must_use]
22 pub fn push<T: 'static>(&mut self, b: Box<T>) -> *const T {
23 let raw = b.as_ref() as *const T;
24 self.inner.push(b);
25 raw
26 }
27
28 /// Push a Vec<T> into the pool, and return its length and a raw pointer to its data.
29 /// The pointer is valid as long as the pool is alive.
30 #[must_use]
31 pub fn push_vec<T: 'static>(&mut self, v: Vec<T>) -> (usize, *const T) {
32 let len = v.len();
33 let raw = v.as_ptr();
34 // Convert Vec<T> to Box<dyn Any>.
35 let boxed_v = Box::new(v);
36 self.inner.push(boxed_v);
37 (len, raw)
38 }
39}
40
41/// Trait to get a raw pointer from a type, using a BoxPool to hold the box.
42/// This is useful to implement conversions to raw COM types that require
43/// raw pointers in struct fields.
44pub trait GetRawWithBoxPool<T> {
45 fn get_raw_with_pool(&self, pool: &mut BoxPool) -> T;
46}
47
48/// Trait to get a raw pointer from a type.
49/// Type should implement this trait if it can return a raw pointer without BoxPool.
50pub trait GetRaw<T> {
51 fn get_raw(&self) -> T;
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn test_box_pool() {
60 let mut pool = BoxPool::new();
61 let b = Box::new(42);
62 let raw = pool.push(b);
63 assert_eq!(unsafe { *raw }, 42);
64
65 let v = vec![1, 2, 3];
66 let (len, raw_v) = pool.push_vec(v);
67 assert_eq!(len, 3);
68 assert_eq!(unsafe { *raw_v }, 1);
69 }
70}