1mod utils;
2
3use tuple_list::{Tuple, TupleList};
4
5pub use self::utils::{Concat, Construct, Count, InElement, Index};
6use crate::{array::Element, include::*};
7
8#[derive(Debug)]
9struct Inner<T: InElement> {
10 count: AtomicUsize,
11 place: T::Place,
12}
13
14impl<T: InElement> Inner<T> {
15 const LAYOUT: Layout = Layout::new::<Self>();
16
17 fn new() -> NonNull<Self> {
18 let memory = match Global.allocate(Self::LAYOUT) {
19 Ok(memory) => memory.cast::<Self>(),
20 Err(_) => handle_alloc_error(Self::LAYOUT),
21 };
22 let value = Self {
23 count: AtomicUsize::new(T::TUPLE_LIST_SIZE),
24 place: T::init(),
25 };
26 unsafe { memory.as_ptr().write(value) }
29 memory
30 }
31
32 unsafe fn drop_in_place(this: NonNull<Self>) -> <T::Take as TupleList>::Tuple {
42 let inner = unsafe { this.as_ref() };
44
45 let tuple = unsafe { T::take(&inner.place) }.into_tuple();
46
47 unsafe { Global.deallocate(this.cast(), Self::LAYOUT) };
49
50 tuple
51 }
52}
53
54pub type Whole<Head, Current, Tail> =
56 <<Head as Concat<(Current,)>>::Output as Concat<Tail>>::Output;
57
58pub type List<Head, Current, Tail> = <Whole<Head, Current, Tail> as Tuple>::TupleList;
60
61type Ptr<Head, Current, Tail> = NonNull<Inner<List<Head, Current, Tail>>>;
62
63pub type Place<Head, Current, Tail> = <List<Head, Current, Tail> as InElement>::Place;
65
66pub type TakeList<Head, Current, Tail> = <List<Head, Current, Tail> as InElement>::Take;
69
70pub type Take<Head, Current, Tail> = <TakeList<Head, Current, Tail> as TupleList>::Tuple;
73
74#[derive(Debug)]
82pub struct Sender<Head, Current, Tail>(Ptr<Head, Current, Tail>)
83where
84 Head: Concat<(Current,)>,
85 <Head as Concat<(Current,)>>::Output: Concat<Tail>,
86 Tail: Tuple,
87 <Whole<Head, Current, Tail> as Tuple>::TupleList: InElement;
88
89unsafe impl<Head, Current, Tail> Send for Sender<Head, Current, Tail>
93where
94 Head: Concat<(Current,)> + Send,
95 Current: Send,
96 <Head as Concat<(Current,)>>::Output: Concat<Tail>,
97 Tail: Tuple + Send,
98 <Whole<Head, Current, Tail> as Tuple>::TupleList: InElement,
99{
100}
101
102pub type CountOf<T> = <<T as Tuple>::TupleList as Count>::Count;
104
105impl<Head, Current, Tail> Sender<Head, Current, Tail>
106where
107 Head: Concat<(Current,)>,
108 <Head as Concat<(Current,)>>::Output: Concat<Tail>,
109 Tail: Tuple,
110 <Whole<Head, Current, Tail> as Tuple>::TupleList: InElement,
111{
112 unsafe fn new(inner: Ptr<Head, Current, Tail>) -> Self {
116 Sender(inner)
117 }
118
119 pub fn send(self, value: Current) -> Result<(), Take<Head, Current, Tail>>
122 where
123 <Head as Tuple>::TupleList: Count,
124 Place<Head, Current, Tail>: Index<CountOf<Head>, Output = Element<Current>>,
125 {
126 let pointer = self.0;
127 let inner = unsafe { pointer.as_ref() };
129 let elem: &Element<Current> = Index::<CountOf<Head>>::index(&inner.place);
130
131 unsafe { elem.place(value) };
135 let fetch_sub = inner.count.fetch_sub(1, Release);
136
137 mem::forget(self);
140
141 if fetch_sub == 1 {
142 atomic::fence(Acquire);
146 return Err(unsafe { Inner::drop_in_place(pointer) });
147 }
148 Ok(())
149 }
150}
151
152impl<Head, Current, Tail> Drop for Sender<Head, Current, Tail>
153where
154 Head: Concat<(Current,)>,
155 <Head as Concat<(Current,)>>::Output: Concat<Tail>,
156 Tail: Tuple,
157 <Whole<Head, Current, Tail> as Tuple>::TupleList: InElement,
158{
159 fn drop(&mut self) {
160 let pointer = self.0;
161 let inner = unsafe { pointer.as_ref() };
163 if inner.count.fetch_sub(1, Relaxed) == 1 {
166 atomic::fence(Acquire);
168 unsafe { Inner::drop_in_place(pointer) };
169 }
170 }
171}
172
173pub fn tuple<T>() -> <T::Sender as TupleList>::Tuple
194where
195 T: Construct,
196 <T as Tuple>::TupleList: InElement,
197{
198 let inner = Inner::<T::TupleList>::new();
199 unsafe { T::construct(inner) }.into_tuple()
200}
201
202#[cfg(test)]
203mod tests {
204 #[cfg(not(loom))]
205 use std::thread;
206
207 #[cfg(loom)]
208 use loom::thread;
209
210 use super::tuple;
211
212 #[test]
213 fn send() {
214 fn inner() {
215 let (s1, s2, s3) = tuple::<(i32, u8, char)>();
216 let j2 = thread::spawn(|| s2.send(2));
217 let j3 = thread::spawn(|| s3.send('3'));
218
219 let res = s1.send(1).and(j2.join().unwrap()).and(j3.join().unwrap());
220 assert_eq!(res, Err((Some(1), Some(2), Some('3'))));
221 }
222
223 #[cfg(not(loom))]
224 inner();
225 #[cfg(loom)]
226 loom::model(inner);
227 }
228
229 #[test]
230 fn drop_one() {
231 fn inner() {
232 let (s1, s2, s3) = tuple::<(i32, u8, char)>();
233 let j2 = thread::spawn(|| {
234 drop(s2);
235 Ok(())
236 });
237 let j3 = thread::spawn(|| s3.send('3'));
238
239 let res = s1.send(1).and(j2.join().unwrap()).and(j3.join().unwrap());
240 if let Err(r) = res {
241 assert_eq!(r, (Some(1), None, Some('3')));
242 }
243 }
244
245 #[cfg(not(loom))]
246 inner();
247 #[cfg(loom)]
248 loom::model(inner);
249 }
250}