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