ab_contracts_common/output.rs
1//! Memory given to method calls as `#[output]`
2
3use crate::ContractError;
4use ab_io_type::IoType;
5use ab_io_type::maybe_data::MaybeData;
6use ab_io_type::trivial_type::{AnyBitPattern, TrivialType};
7use ab_io_type::variable_elements::VariableElements;
8use core::fmt;
9use core::marker::PhantomData;
10use core::mem::MaybeUninit;
11use core::ptr::NonNull;
12
13/// Memory that can be given to a method call as an `#[output]` of type `Target`.
14///
15/// A call can leave contents behind that are not a valid value of `Target`, for example when it
16/// fails halfway, so the contents must be parsed before they are accessed, unless every bit
17/// pattern is a valid value (see [`AnyBitPattern`]). [`Lent`] does this for memory whose contents
18/// need parsing.
19///
20/// A call gets the pointer, size and capacity from [`Self::as_raw_output()`]. Until `self` is used
21/// again, the call may write initialized bytes anywhere within the capacity, even if it fails. If
22/// it succeeds, the size it reports is set with [`Self::set_output_size()`].
23///
24/// # Safety
25/// [`Self::as_raw_output()`] returns a pointer aligned for `Target::PointerType`, and a size that
26/// is valid for `Target` and doesn't exceed the capacity it returns. The pointer is valid for
27/// writes of the capacity, but for reads only of the size, with that many bytes initialized: the
28/// bytes after them may be uninitialized and must not be read before they are written. While
29/// `self` stays exclusively borrowed after that, the memory is not accessed other than through the
30/// pointer. Whatever initialized bytes a call leaves within the size (the initial one or the last
31/// one set with [`Self::set_output_size()`]) are never accessed as `Target` without being parsed
32/// first, unless every bit pattern is a valid value of `Target::PointerType`.
33#[diagnostic::on_unimplemented(
34 message = "`{Self}` can't be given to a call as an `#[output]` of type `{Target}`",
35 label = "expected `&mut {Target}` whose contents accept every bit pattern, or \
36 `&mut Lent<{Target}>`",
37 note = "a failed call can leave invalid contents behind, use `Lent::new()` for a local value, \
38 `Lent::<MaybeData<'_, _>>::from_uninit()` or \
39 `Lent::<VariableElements<'_, _>>::from_uninit()` for a local container, or \
40 `Env::lend_output()` for an `#[output]` the method received"
41)]
42pub unsafe trait OutputArg<Target>
43where
44 Target: IoType,
45{
46 /// Pointer to the contents, size and capacity to give to a call
47 fn as_raw_output(&mut self) -> (NonNull<Target::PointerType>, u32, u32);
48
49 /// Set the size that a successful call reported.
50 ///
51 /// # Safety
52 /// `size` must be valid for `Target` (see [`IoType::try_from_ptr()`]) and not exceed the
53 /// capacity, and that many bytes must be initialized.
54 unsafe fn set_output_size(&mut self, size: u32);
55}
56
57// Without this attribute rustc reports the unsatisfied `AnyBitPattern` bound of the contents of
58// containers instead of the message of `OutputArg`
59#[diagnostic::do_not_recommend]
60// SAFETY: Pointer, size and capacity are those of a valid value, the pointer can be used for reads
61// of the size and writes of the capacity while the value isn't accessed otherwise
62// (`IoType::as_mut_ptr()`), which it isn't while `self` is exclusively borrowed. Initialized
63// contents are a valid value, since every bit pattern is.
64unsafe impl<T> OutputArg<T> for T
65where
66 T: IoType<PointerType: AnyBitPattern>,
67{
68 #[inline(always)]
69 fn as_raw_output(&mut self) -> (NonNull<T::PointerType>, u32, u32) {
70 (
71 IoType::as_mut_ptr(self),
72 IoType::size(self),
73 IoType::capacity(self),
74 )
75 }
76
77 #[inline(always)]
78 unsafe fn set_output_size(&mut self, size: u32) {
79 // SAFETY: The size is valid and doesn't exceed the capacity, with that many bytes
80 // initialized (function contract), which are a valid value, since every bit pattern is
81 unsafe { IoType::set_size(self, size) }
82 }
83}
84
85enum LentValue<'a, T> {
86 /// A plain value owned by `Lent`, which may not be a valid value after a call
87 Owned(MaybeUninit<T>),
88 /// A container view owned by `Lent` over memory borrowed for `'a`. The view itself is valid,
89 /// while its contents may not be after a call.
90 View(T),
91 /// A plain value or a container view borrowed for `'a`
92 Borrowed(NonNull<T>, PhantomData<&'a mut T>),
93}
94
95/// Memory lent to calls as an `#[output]`, whose contents are parsed before they are accessed.
96///
97/// A call can leave contents behind that are not a valid value, for example when it fails halfway,
98/// so the contents are only accessible through [`Self::get_mut()`], which parses them once after
99/// each call. Plain values can also be replaced with [`Self::set()`]. Memory whose contents accept
100/// every bit pattern can be given to calls directly, see [`OutputArg`].
101///
102/// Created with [`Self::new()`] for a local value, with `Lent::<MaybeData<'_, _>>::from_uninit()`
103/// or `Lent::<VariableElements<'_, _>>::from_uninit()` for a local container, and with
104/// [`Env::lend_output()`] for an `#[output]` the method received.
105///
106/// [`Env::lend_output()`]: crate::env::Env::lend_output
107pub struct Lent<'a, T>
108where
109 T: IoType,
110{
111 value: LentValue<'a, T>,
112 /// Pointer to the contents, size and capacity, read from the value again while it is
113 /// `checked`
114 ptr: NonNull<T::PointerType>,
115 size: u32,
116 capacity: u32,
117 /// Neither a call nor a size set changed the contents since they were last known to be valid
118 checked: bool,
119}
120
121impl<T> fmt::Debug for Lent<'_, T>
122where
123 T: IoType,
124{
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 // Contents may not be a valid value
127 f.debug_struct("Lent")
128 .field("size", &self.size)
129 .field("capacity", &self.capacity)
130 .field("checked", &self.checked)
131 .finish_non_exhaustive()
132 }
133}
134
135// SAFETY: Pointer, size and capacity are those of the value when it was last known to be valid
136// (created, parsed or set), so the pointer can be used for reads of the size and writes of the
137// capacity (`IoType::as_mut_ptr()`). Since then, only calls changed the contents, by writing
138// initialized bytes within the capacity, and the size, through `Self::set_output_size()`. The value
139// is owned by `self` or borrowed by it for `'a`, so it isn't accessed while `self` is exclusively
140// borrowed. The contents are only accessed as `T` after `Self::get_mut()` parsed them or
141// `Self::set()` wrote a valid value.
142unsafe impl<T> OutputArg<T> for Lent<'_, T>
143where
144 T: IoType,
145{
146 #[inline(always)]
147 fn as_raw_output(&mut self) -> (NonNull<T::PointerType>, u32, u32) {
148 let raw_parts = self.raw_parts();
149 self.checked = false;
150 raw_parts
151 }
152
153 #[inline(always)]
154 unsafe fn set_output_size(&mut self, size: u32) {
155 // Make sure the cached size is that of the value
156 self.raw_parts();
157 // The only valid size of a plain value is its size, so a different size means `T` is a
158 // container view, which is a valid value regardless of its contents
159 if size != self.size {
160 // SAFETY: A container view, which is valid, owned by `self` or borrowed by it, and not
161 // referenced elsewhere while `self` is exclusively borrowed
162 let value = unsafe { self.value_ptr().as_mut() };
163 // SAFETY: The size is valid and doesn't exceed the capacity, with that many bytes
164 // initialized (function contract), the contents are only accessed after
165 // `Self::get_mut()` parsed them
166 unsafe {
167 IoType::set_size(value, size);
168 }
169 self.size = size;
170 }
171 // The contents may have changed together with the size
172 self.checked = false;
173 }
174}
175
176impl<T> Lent<'static, T>
177where
178 T: TrivialType,
179{
180 /// Lend a local value
181 #[inline(always)]
182 pub fn new(value: T) -> Self {
183 Self {
184 value: LentValue::Owned(MaybeUninit::new(value)),
185 // Read from the value before it is given to a call
186 ptr: NonNull::dangling(),
187 size: T::SIZE,
188 capacity: T::SIZE,
189 checked: true,
190 }
191 }
192}
193
194impl<'a, Data> Lent<'a, MaybeData<'a, Data>>
195where
196 Data: TrivialType,
197 MaybeData<'a, Data>: IoType,
198{
199 /// Lend a local [`MaybeData`] over uninitialized memory, like [`MaybeData::from_uninit()`].
200 ///
201 /// Returns `None` if `size != 0`.
202 #[inline(always)]
203 pub fn from_uninit(uninit: &'a mut MaybeUninit<Data>, size: &'a mut u32) -> Option<Self> {
204 Some(Self::from_view(MaybeData::from_uninit(uninit, size)?))
205 }
206}
207
208impl<'a, Element, const RECOMMENDED_ALLOCATION: u32>
209 Lent<'a, VariableElements<'a, Element, RECOMMENDED_ALLOCATION>>
210where
211 Element: TrivialType,
212 VariableElements<'a, Element, RECOMMENDED_ALLOCATION>: IoType,
213{
214 /// Lend a local [`VariableElements`] over uninitialized memory, like
215 /// [`VariableElements::from_uninit()`].
216 ///
217 /// Returns `None` if `size != 0` or if the buffer is larger than `u32::MAX` bytes.
218 #[inline(always)]
219 pub fn from_uninit(uninit: &'a mut [MaybeUninit<Element>], size: &'a mut u32) -> Option<Self> {
220 Some(Self::from_view(VariableElements::from_uninit(
221 uninit, size,
222 )?))
223 }
224}
225
226impl<'a, T> Lent<'a, T>
227where
228 T: IoType,
229{
230 /// Lend a container view over memory borrowed for `'a`
231 #[inline(always)]
232 fn from_view(mut view: T) -> Self {
233 let ptr = IoType::as_mut_ptr(&mut view);
234 let size = IoType::size(&view);
235 let capacity = IoType::capacity(&view);
236 Self {
237 value: LentValue::View(view),
238 ptr,
239 size,
240 capacity,
241 checked: true,
242 }
243 }
244
245 /// Lend `value`, which is only borrowed for `'a`, rather than until the method returns like
246 /// with [`Env::lend_output()`].
247 ///
248 /// # Safety
249 /// After the returned `Lent` was given to a call, `value` may hold contents that are not a
250 /// valid value. Once the `Lent` is no longer used, the contents of `value` must not be accessed
251 /// without being parsed first, unless the last use of the `Lent` after its last call was a
252 /// successful [`Self::get_mut()`] or [`Self::set()`], or the contents of `T` accept every bit
253 /// pattern.
254 ///
255 /// [`Env::lend_output()`]: crate::env::Env::lend_output
256 #[inline(always)]
257 pub unsafe fn from_mut_unchecked(value: &'a mut T) -> Self {
258 let ptr = IoType::as_mut_ptr(value);
259 let size = IoType::size(value);
260 let capacity = IoType::capacity(value);
261 Self {
262 value: LentValue::Borrowed(NonNull::from_mut(value), PhantomData),
263 ptr,
264 size,
265 capacity,
266 checked: true,
267 }
268 }
269
270 /// Exclusive access to the contents, which are parsed once after each call.
271 ///
272 /// Repeated calls without a call in between don't parse the contents again. Returns
273 /// [`ContractError::BadOutput`] if they are not a valid value of `T`. They then stay
274 /// inaccessible until [`Self::set()`], which only exists for plain values, replaces them.
275 /// Lending them again doesn't help either: methods generated by `#[contract]` reject outputs
276 /// with invalid initial contents with [`ContractError::BadInput`].
277 ///
278 /// A plain value is returned as `&mut T`. A container is returned as a new view of the lent
279 /// memory that only lives while `self` is borrowed (see [`IoType::reborrow_mut()`]). Code that
280 /// replaces it, for example with a view of other memory, doesn't change what `self` lends to
281 /// calls.
282 #[inline(always)]
283 pub fn get_mut(&mut self) -> Result<T::Reborrowed<'_>, ContractError> {
284 if !self.checked {
285 let (mut ptr, mut size, capacity) = self.raw_parts();
286 // SAFETY: The pointer is aligned and valid for writes of the capacity and for reads of
287 // the size, which is valid for `T` and doesn't exceed the capacity, with that many
288 // bytes initialized. The value was valid with these parts, and calls since then only
289 // wrote initialized bytes within the capacity and set a valid size
290 // (`OutputArg::set_output_size()` contract). Nothing else accesses the memory while
291 // `self` is exclusively borrowed, and nothing is moved out of the returned value,
292 // which is dropped right away.
293 if unsafe { T::try_from_mut_ptr(&mut ptr, &mut size, capacity) }.is_none() {
294 return Err(ContractError::BadOutput);
295 }
296 self.checked = true;
297 }
298 // SAFETY: A valid value, since it was parsed above or neither a call nor a size set changed
299 // it since it was last known to be valid, owned by `self` or borrowed by it, and not
300 // referenced elsewhere while `self` is borrowed
301 let value = unsafe { self.value_ptr().as_mut() };
302 Ok(value.reborrow_mut())
303 }
304
305 /// Pointer to the value, which may not be valid unless `checked`
306 #[inline(always)]
307 fn value_ptr(&mut self) -> NonNull<T> {
308 match &mut self.value {
309 LentValue::Owned(value) => NonNull::from_mut(value).cast::<T>(),
310 LentValue::View(view) => NonNull::from_mut(view),
311 LentValue::Borrowed(value, _) => *value,
312 }
313 }
314
315 /// Pointer to the contents, size and capacity, read from the value unless a call or a size set
316 /// may have changed it since it was last known to be valid
317 #[inline(always)]
318 fn raw_parts(&mut self) -> (NonNull<T::PointerType>, u32, u32) {
319 if self.checked {
320 // SAFETY: A valid value, since neither a call nor a size set changed it since it was
321 // created, parsed or set, owned by `self` or borrowed by it, and not referenced
322 // elsewhere while `self` is exclusively borrowed
323 let value = unsafe { self.value_ptr().as_mut() };
324 self.ptr = IoType::as_mut_ptr(value);
325 self.size = IoType::size(value);
326 self.capacity = IoType::capacity(value);
327 } else if let LentValue::Owned(value) = &mut self.value {
328 // An owned value moves together with `Lent`, unlike the memory of other values
329 self.ptr = NonNull::from_mut(value).cast::<T::PointerType>();
330 }
331 (self.ptr, self.size, self.capacity)
332 }
333}
334
335impl<T> Lent<'_, T>
336where
337 T: TrivialType,
338{
339 /// Replace the contents with a valid value
340 #[inline(always)]
341 pub fn set(&mut self, value: T) -> &mut T {
342 let mut ptr = self.value_ptr();
343 // SAFETY: Aligned and valid for writes of `T`, owned by `self` or borrowed by it, and not
344 // referenced elsewhere while `self` is exclusively borrowed
345 unsafe {
346 ptr.write(value);
347 }
348 self.checked = true;
349 // SAFETY: A valid value was written above, not referenced elsewhere while `self` is
350 // borrowed
351 unsafe { ptr.as_mut() }
352 }
353}