rocket/form/buffer.rs
1use std::ops::{Index, RangeFrom, RangeTo};
2use std::cell::UnsafeCell;
3
4use parking_lot::{RawMutex, lock_api::RawMutex as _};
5
6mod private {
7 /// Sealed trait for types that can be shared in a `SharedStack`.
8 ///
9 /// The type of values passed to
10 /// [`local_cache`](crate::request::local_cache) must implement this trait.
11 /// Since this trait is sealed, the types implementing this trait are known
12 /// and finite: `String` and `Vec<T> for all T: Sync + Send + 'static`.
13 ///
14 /// # Safety
15 ///
16 /// Types implementing this trait must have a stable address when deref'd.
17 pub unsafe trait Shareable: std::ops::Deref + Sync + Send + 'static {
18 /// The current size of the owned shareable.
19 fn size(&self) -> usize;
20 }
21
22 unsafe impl Shareable for String {
23 fn size(&self) -> usize { self.len() }
24 }
25
26 unsafe impl<T: Send + Sync + 'static> Shareable for Vec<T> {
27 fn size(&self) -> usize { self.len() }
28 }
29}
30
31pub use private::Shareable;
32
33/// A stack of strings (chars of bytes) that can be shared between threads while
34/// remaining internally mutable and while allowing references into the stack to
35/// persist across mutations.
36pub struct SharedStack<T: Shareable> {
37 stack: UnsafeCell<Vec<T>>,
38 mutex: RawMutex,
39}
40
41impl<T: Shareable> SharedStack<T>
42 where T::Target: Index<RangeFrom<usize>, Output = T::Target>
43 + Index<RangeTo<usize>, Output = T::Target>
44{
45 /// Creates a new stack.
46 pub fn new() -> Self {
47 SharedStack {
48 stack: UnsafeCell::new(vec![]),
49 mutex: RawMutex::INIT,
50 }
51 }
52
53 /// Pushes the string `S` onto the stack. Returns a reference of the string
54 /// in the stack.
55 pub(crate) fn push<S: Into<T>>(&self, string: S) -> &T::Target {
56 // SAFETY:
57 // * Aliasing: We retrieve a mutable reference to the last slot (via
58 // `push()`) and then return said reference as immutable; these
59 // occur in serial, so they don't alias. This method accesses a
60 // unique slot each call: the last slot, subsequently replaced by
61 // `push()` each next call. No other method accesses the internal
62 // buffer directly. Thus, the outstanding reference to the last slot
63 // is never accessed again mutably, preserving aliasing guarantees.
64 // * Liveness: The returned reference is to a `String`; we must ensure
65 // that the `String` is never dropped while `self` lives. This is
66 // guaranteed by returning a reference with the same lifetime as
67 // `self`, so `self` can't be dropped while the string is live, and
68 // by never removing elements from the internal `Vec` thus not
69 // dropping `String` itself: `push()` is the only mutating operation
70 // called on `Vec`, which preserves all previous elements; the
71 // stability of `String` itself means that the returned address
72 // remains valid even after internal realloc of `Vec`.
73 // * Thread-Safety: Parallel calls to `push_one` without exclusion
74 // would result in a race to `vec.push()`; `RawMutex` ensures that
75 // this doesn't occur.
76 unsafe {
77 self.mutex.lock();
78 let vec: &mut Vec<T> = &mut *self.stack.get();
79 vec.push(string.into());
80 let last = vec.last().expect("push() => non-empty");
81 self.mutex.unlock();
82 last
83 }
84 }
85
86 /// Just like `push` but `string` must already be the owned `T`.
87 pub fn push_owned(&self, string: T) -> &T::Target {
88 self.push(string)
89 }
90
91 /// Pushes the string `S` onto the stack which is assumed to internally
92 /// contain two strings with the first string being of length `n`. Returns
93 /// references to the two strings on the stack.
94 ///
95 /// # Panics
96 ///
97 /// Panics if `string.len() < len`.
98 pub(crate) fn push_split<S: Into<T>>(&self, string: S, n: usize) -> (&T::Target, &T::Target) {
99 let buffered = self.push(string);
100 let a = &buffered[..n];
101 let b = &buffered[n..];
102 (a, b)
103 }
104
105 /// Pushes the strings `a` and `b` onto the stack without allocating for
106 /// both strings. Returns references to the two strings on the stack.
107 pub(crate) fn push_two<V>(&self, a: V, b: V) -> (&T::Target, &T::Target)
108 where T: From<V> + Extend<V>,
109 {
110 let mut value = T::from(a);
111 let split_len = value.size();
112 value.extend(Some(b));
113 self.push_split(value, split_len)
114 }
115}
116
117unsafe impl<T: Shareable> Sync for SharedStack<T> {}