Skip to main content

odem_rs_core/continuation/
adapter.rs

1use core::{marker::PhantomData, mem::offset_of, ptr::NonNull};
2
3use intrusive_collections::{DefaultLinkOps, LinkOps};
4
5use super::{Continuation, Link};
6
7use crate::{
8	config::Config,
9	ptr::{IntrusivelyCounted, Irc},
10};
11
12/* ******************************************************** Intrusive Adapter */
13
14/// Adapter for [continuations] to be inserted into intrusive data structures.
15///
16/// [continuations]: Continuation
17pub struct Adapter<C: ?Sized + Config, P = Irc<Continuation<'static, C>>> {
18	/// The link ops for the chosen link type.
19	link_ops: <Link as DefaultLinkOps>::Ops,
20	/// The [pointer ops] for `Irc` of [continuations].
21	///
22	/// [pointer ops]: PointerOps
23	/// [continuations]: Continuation
24	pointer_ops: PointerOps<Continuation<'static, C>, P>,
25}
26
27impl<C: ?Sized + Config, P> Adapter<C, P> {
28	/// The associated constant that represents `Link::default()`.
29	///
30	/// This exists because `Default::default()` is not a constant function.
31	pub const NEW: Self = Adapter {
32		link_ops: <Link as DefaultLinkOps>::NEW,
33		pointer_ops: PointerOps(PhantomData),
34	};
35}
36
37impl<C: ?Sized + Config, P> Default for Adapter<C, P> {
38	fn default() -> Self {
39		Self::NEW
40	}
41}
42
43impl<C: ?Sized + Config, P> Clone for Adapter<C, P> {
44	fn clone(&self) -> Self {
45		*self
46	}
47}
48
49impl<C: ?Sized + Config, P> Copy for Adapter<C, P> {}
50
51unsafe impl<C, P> intrusive_collections::Adapter for Adapter<C, P>
52where
53	C: ?Sized + Config,
54	P: From<Irc<Continuation<'static, C>>> + Into<Irc<Continuation<'static, C>>>,
55{
56	type LinkOps = <Link as DefaultLinkOps>::Ops;
57	type PointerOps = PointerOps<Continuation<'static, C>, P>;
58
59	unsafe fn get_value(
60		&self,
61		link: <Self::LinkOps as LinkOps>::LinkPtr,
62	) -> *const Continuation<'static, C> {
63		intrusive_collections::container_of!(link.as_ptr(), Continuation<'static, C>, hook)
64	}
65
66	unsafe fn get_link(
67		&self,
68		value: *const Continuation<'static, C>,
69	) -> <Self::LinkOps as LinkOps>::LinkPtr {
70		unsafe {
71			let ptr = (value as *const u8).add(offset_of!(Continuation<'static, C>, hook));
72			NonNull::new_unchecked(ptr as *mut _)
73		}
74	}
75
76	fn link_ops(&self) -> &Self::LinkOps {
77		&self.link_ops
78	}
79
80	fn link_ops_mut(&mut self) -> &mut Self::LinkOps {
81		&mut self.link_ops
82	}
83
84	fn pointer_ops(&self) -> &Self::PointerOps {
85		&self.pointer_ops
86	}
87}
88
89/// Another helper structure that helps with the conversion between raw
90/// [Continuation] pointers and owned ones.
91pub struct PointerOps<V, P>(PhantomData<(V, P)>);
92
93impl<V, P> PointerOps<V, P> {
94	/// Default instance of pointer ops.
95	pub const NEW: Self = PointerOps(PhantomData);
96}
97
98impl<V, P> Clone for PointerOps<V, P> {
99	fn clone(&self) -> Self {
100		*self
101	}
102}
103
104impl<V, P> Copy for PointerOps<V, P> {}
105
106unsafe impl<V, P> intrusive_collections::PointerOps for PointerOps<V, P>
107where
108	V: IntrusivelyCounted,
109	P: From<Irc<V>> + Into<Irc<V>>,
110{
111	type Value = V;
112	type Pointer = P;
113
114	unsafe fn from_raw(&self, value: *const V) -> P {
115		unsafe { P::from(Irc::from_raw(NonNull::new_unchecked(value as *mut V))) }
116	}
117
118	fn into_raw(&self, ptr: P) -> *const V {
119		Irc::into_raw(P::into(ptr)).as_ptr() as *const V
120	}
121}
122
123/// Helper macro to generate an implementation for a wrapper
124/// [`Adapter`](intrusive_collections::Adapter) based on the [`Adapter`] for
125/// `Continuations`.
126///
127/// This helps to fit continuations into custom event calendars.
128#[macro_export]
129#[doc(hidden)]
130macro_rules! intrusive_adapter_newtype {
131	() => {};
132
133	($name:ident) => {
134		unsafe impl<C: ?Sized + Config> ::intrusive_collections::Adapter for $name<C> {
135			type LinkOps = <$crate::continuation::Adapter<C, $crate::calendar::IdleOnDrop<C>> as ::intrusive_collections::Adapter>::LinkOps;
136			type PointerOps = <$crate::continuation::Adapter<C, $crate::calendar::IdleOnDrop<C>> as ::intrusive_collections::Adapter>::PointerOps;
137
138			#[inline]
139			unsafe fn get_value(&self, link: <Self::LinkOps as ::intrusive_collections::LinkOps>::LinkPtr) -> *const <Self::PointerOps as ::intrusive_collections::PointerOps>::Value {
140				unsafe { self.0.get_value(link) }
141			}
142
143			#[inline]
144			unsafe fn get_link(&self, value: *const <Self::PointerOps as ::intrusive_collections::PointerOps>::Value) -> <Self::LinkOps as ::intrusive_collections::LinkOps>::LinkPtr {
145				unsafe { self.0.get_link(value) }
146			}
147
148			#[inline]
149			fn link_ops(&self) -> &Self::LinkOps {
150				self.0.link_ops()
151			}
152
153			#[inline]
154			fn link_ops_mut(&mut self) -> &mut Self::LinkOps {
155				self.0.link_ops_mut()
156			}
157
158			#[inline]
159			fn pointer_ops(&self) -> &Self::PointerOps {
160				self.0.pointer_ops()
161			}
162		}
163	};
164
165	($name:ident, $($tail:ident),*) => {
166		$crate::intrusive_adapter_newtype!($name);
167		$crate::intrusive_adapter_newtype!($($tail),*);
168	};
169
170	($($name:ident,)+) => {
171		$crate::intrusive_adapter_newtype!($($name),*);
172	};
173}