same_alloc/lib.rs
1//! The `SameVec` makes it possible to re-use allocations across multiple invocations of
2//! zero-copy parsers.
3//!
4//! This crate provides an allocated buffer that can be used by vectors of
5//! different element types, as long as they have the same layout. Most prominently
6//! this allows use of one buffer where the element type depends on a function
7//! local lifetime. The required vector type would be impossible to name outside
8//! the function.
9//!
10//! # Example
11//!
12//! ```rust
13//! fn select_median_name(unparsed: &str) -> &str {
14//! // Problem: This type depends on the lifetime parameter. Ergo, we can not normally store
15//! // _one_vector in the surrounding function, and instead need to allocate here a new one.
16//! let mut names: Vec<_> = unparsed.split(' ').collect();
17//! let idx = names.len() / 2;
18//! *names.select_nth_unstable(idx).1
19//! }
20//!
21//! fn select_median_name_with_buffer<'names>(
22//! unparsed: &'names str,
23//! buf: &mut SameVec<*const str>,
24//! ) -> &'names str {
25//! let mut names = buf.use_for(same::for_ref());
26//! names.extend(unparsed.split(' '));
27//! let idx = names.len() / 2;
28//! *names.select_nth_unstable(idx).1
29//! }
30//! ```
31//!
32#![no_std]
33extern crate alloc;
34
35pub mod same;
36
37use alloc::vec::Vec;
38pub use crate::same::SameLayout;
39
40/// A dynamically sized buffer for types with the same layout.
41pub struct SameVec<T> {
42 elements: Vec<T>,
43}
44
45/// A temporary view on a SameVec, with a different element type.
46pub struct TempVec<'lt, T> {
47 from: &'lt mut dyn DynBufferWith<T>,
48 vec: Vec<T>,
49}
50
51impl<T> SameVec<T> {
52 /// Create an empty buffer.
53 pub fn new() -> Self {
54 SameVec::default()
55 }
56
57 /// Create a buffer with a pre-defined capacity.
58 ///
59 /// This buffer will not need to reallocate until the element count required for any temporary
60 /// vector exceeds this number of elements.
61 pub fn with_capacity(cap: usize) -> Self {
62 SameVec {
63 elements: Vec::with_capacity(cap),
64 }
65 }
66
67 /// Use the allocated buffer for a compatible type of elements.
68 ///
69 /// When the temporary view is dropped the allocation is returned to the buffer. This means its
70 /// capacity might be automatically increased, or decreased, based on the used of the vector.
71 pub fn use_for<U>(&mut self, marker: SameLayout<T, U>) -> TempVec<'_, U> {
72 let from = Wrap::new(&mut self.elements, marker);
73 let elements = core::mem::take(&mut from.elements);
74 let vec = from.marker.forget_vec(elements);
75 TempVec { from, vec, }
76 }
77}
78
79impl<T> Default for SameVec<T> {
80 fn default() -> Self {
81 SameVec { elements: Vec::new() }
82 }
83}
84
85impl<T> Drop for TempVec<'_, T> {
86 fn drop(&mut self) {
87 self.from.swap_internal_with(&mut self.vec);
88 }
89}
90
91impl<T> core::ops::Deref for TempVec<'_, T> {
92 type Target = Vec<T>;
93
94 fn deref(&self) -> &Vec<T> {
95 &self.vec
96 }
97}
98
99impl<T> core::ops::DerefMut for TempVec<'_, T> {
100 fn deref_mut(&mut self) -> &mut Vec<T> {
101 &mut self.vec
102 }
103}
104
105struct Wrap<T, U> {
106 marker: SameLayout<T, U>,
107 elements: alloc::vec::Vec<T>,
108}
109
110/// Type-erase way for Vec with elements layout compatible to `T`.
111trait DynBufferWith<T> {
112 fn swap_internal_with(&mut self, _: &mut Vec<T>);
113}
114
115impl<T, U> Wrap<T, U> {
116 fn new(vec: &mut Vec<T>, _: SameLayout<T, U>) -> &mut Self {
117 unsafe { &mut *(vec as *mut _ as *mut Wrap<T, U>) }
118 }
119}
120
121impl<T, U> DynBufferWith<U> for Wrap<T, U> {
122 fn swap_internal_with(&mut self, v: &mut Vec<U>) {
123 let mut temp = core::mem::take(v);
124
125 temp.clear();
126 let mut temp = self.marker.transpose().forget_vec(temp);
127 core::mem::swap(&mut temp, &mut self.elements);
128
129 temp.clear();
130 *v = self.marker.forget_vec(temp);
131 }
132}