tenferro_tensor/native_session.rs
1//! Lifetime-bound native session capability tokens.
2//!
3//! A backend leaf crate (CPU, CUDA, WebGPU) exposes its concrete execution
4//! session to higher-level operation crates through a [`NativeSessionRef`]
5//! returned by [`BackendSession::native_session`](crate::BackendSession::native_session).
6//! The token is opaque: its fields are private and its only constructor is
7//! `unsafe`, so safe code can neither fabricate one nor retarget it at another
8//! value. A backend leaf recovers its own session with a safe visitor that
9//! checks the token's marker against a marker type only that leaf can name.
10//!
11//! This narrows the unsafe boundary to each leaf's constructor and visitor; it
12//! does not remove it.
13//!
14//! # Examples
15//!
16//! A session without native services returns no token, which is the default:
17//!
18//! ```rust
19//! use tenferro_tensor::{BackendSession, NativeSessionRef};
20//!
21//! fn has_native_services(session: &mut dyn BackendSession) -> bool {
22//! session.native_session().is_some()
23//! }
24//! ```
25//!
26//! The token borrows its session exclusively and cannot outlive that borrow:
27//!
28//! ```compile_fail
29//! use tenferro_tensor::{BackendSession, NativeSessionRef};
30//!
31//! fn escape(session: &mut dyn BackendSession) -> NativeSessionRef<'static> {
32//! session.native_session().unwrap()
33//! }
34//! ```
35//!
36//! It cannot be built from safe code, even with a private marker type:
37//!
38//! ```compile_fail,E0133
39//! use tenferro_tensor::NativeSessionRef;
40//!
41//! struct Marker;
42//! let mut value = 0_u8;
43//! let _token = NativeSessionRef::new::<Marker, u8>(&mut value);
44//! ```
45//!
46//! It is neither `Send` nor `Clone`, so it cannot leave its thread or be
47//! duplicated into a second exclusive borrow:
48//!
49//! ```compile_fail,E0277
50//! fn require_send<T: Send>(_: T) {}
51//! fn check(token: tenferro_tensor::NativeSessionRef<'_>) {
52//! require_send(token);
53//! }
54//! ```
55//!
56//! ```compile_fail,E0599
57//! fn duplicate(token: tenferro_tensor::NativeSessionRef<'_>) {
58//! let _second = token.clone();
59//! let _first = token;
60//! }
61//! ```
62
63use std::any::TypeId;
64use std::fmt;
65use std::marker::PhantomData;
66use std::ptr::NonNull;
67
68/// An exclusively borrowed backend-leaf execution session.
69///
70/// The token names one concrete session by a backend-leaf marker type and
71/// borrows it for `'s`. It is not `Clone`, `Copy`, `Send` or `Sync`. Only the
72/// backend leaf that owns the marker can recover the session, through its own
73/// safe visitor; custom sessions either return no token or forward the token of
74/// a standard delegate they own.
75///
76/// # Examples
77///
78/// ```rust
79/// use tenferro_tensor::{BackendSession, NativeSessionRef};
80///
81/// struct Marker;
82///
83/// fn is_marked(token: &NativeSessionRef<'_>) -> bool {
84/// token.has_marker::<Marker>()
85/// }
86///
87/// fn inspect(session: &mut dyn BackendSession) -> bool {
88/// session.native_session().is_some_and(|token| is_marked(&token))
89/// }
90/// ```
91pub struct NativeSessionRef<'s> {
92 marker: TypeId,
93 session: NonNull<()>,
94 _borrow: PhantomData<&'s mut ()>,
95 _not_send_sync: PhantomData<*mut ()>,
96}
97
98impl<'s> NativeSessionRef<'s> {
99 /// Create a token that names `session` by the backend-leaf marker `M`.
100 ///
101 /// # Safety
102 ///
103 /// `M` must be a marker type private to the calling backend leaf crate,
104 /// and every token that crate creates with `M` must point to a value of the
105 /// single concrete session type its visitor recovers for `M`. `session`
106 /// is exclusively borrowed for `'s`, which the signature enforces; the
107 /// visitor relies on the marker/type correspondence for its cast.
108 ///
109 /// # Examples
110 ///
111 /// ```rust
112 /// use tenferro_tensor::NativeSessionRef;
113 ///
114 /// struct LeafSession(u32);
115 /// struct LeafMarker;
116 ///
117 /// let mut session = LeafSession(7);
118 /// // SAFETY: `LeafMarker` is private to this example and names `LeafSession`.
119 /// let token = unsafe { NativeSessionRef::new::<LeafMarker, _>(&mut session) };
120 /// let pointer = token.into_marked_ptr::<LeafMarker>().expect("same marker");
121 /// // SAFETY: the marker proved the pointee is `LeafSession`, and the
122 /// // exclusive borrow of `session` is still held here.
123 /// assert_eq!(unsafe { pointer.cast::<LeafSession>().as_ref().0 }, 7);
124 /// ```
125 pub unsafe fn new<M: 'static, S>(session: &'s mut S) -> Self {
126 Self {
127 marker: TypeId::of::<M>(),
128 session: NonNull::from(session).cast(),
129 _borrow: PhantomData,
130 _not_send_sync: PhantomData,
131 }
132 }
133
134 /// Whether this token was created with the backend-leaf marker `M`.
135 ///
136 /// # Examples
137 ///
138 /// ```rust
139 /// use tenferro_tensor::NativeSessionRef;
140 ///
141 /// struct Marker;
142 /// struct Other;
143 /// let mut value = 0_u8;
144 /// // SAFETY: `Marker` is private to this example and names `u8`.
145 /// let token = unsafe { NativeSessionRef::new::<Marker, _>(&mut value) };
146 /// assert!(token.has_marker::<Marker>());
147 /// assert!(!token.has_marker::<Other>());
148 /// ```
149 #[must_use]
150 pub fn has_marker<M: 'static>(&self) -> bool {
151 self.marker == TypeId::of::<M>()
152 }
153
154 /// Consume the token and return its session pointer when it carries `M`.
155 ///
156 /// Returning the pointer is safe; dereferencing it is the backend leaf's
157 /// audited step. The leaf may only do so while the borrow the token was
158 /// created from is still held, which its visitor guarantees by holding the
159 /// `&mut` session for the whole visit.
160 ///
161 /// # Examples
162 ///
163 /// ```rust
164 /// use tenferro_tensor::NativeSessionRef;
165 ///
166 /// struct Marker;
167 /// struct Other;
168 /// let mut value = 3_u8;
169 /// // SAFETY: `Marker` is private to this example and names `u8`.
170 /// let token = unsafe { NativeSessionRef::new::<Marker, _>(&mut value) };
171 /// assert!(token.into_marked_ptr::<Other>().is_none());
172 /// ```
173 #[must_use]
174 pub fn into_marked_ptr<M: 'static>(self) -> Option<NonNull<()>> {
175 self.has_marker::<M>().then_some(self.session)
176 }
177}
178
179impl fmt::Debug for NativeSessionRef<'_> {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 f.debug_struct("NativeSessionRef").finish_non_exhaustive()
182 }
183}