Skip to main content

thruput_sdk/sys_exn/
rcq.rs

1use crate::exn::{LibraryExn, syscall_exn};
2use crate::internal::ScratchBuf;
3use crate::re_throw::OrSyscallThrow;
4use crate::sys::SyscallNo;
5use crate::sys_result::rcq as rcq_result;
6use crate::types::StorageKey;
7
8#[cfg(feature = "alloc")]
9use alloc::boxed::Box;
10
11// Every rcq error below is attributed to `kRetrocausalQueueConsume`, even
12// when the failing syscall was `RetrocausalQueuePeekLen` issued on its
13// behalf — the result-layer routines don't report which call failed, and
14// the historical thrown exceptions already used the consume number.
15
16pub fn retrocausal_queue_insert(key: &StorageKey, queue_entry: &[u8]) {
17    rcq_result::retrocausal_queue_insert(key, queue_entry)
18        .or_syscall_throw(SyscallNo::kRetrocausalQueueInsert)
19}
20
21pub fn retrocausal_queue_consume_sized<const N: usize>(
22    key: &StorageKey,
23) -> [u8; N] {
24    rcq_result::retrocausal_queue_get_sized(key, false)
25        .or_syscall_throw(SyscallNo::kRetrocausalQueueConsume)
26}
27
28/// Consume the next queue entry as an `N`-byte array, reporting failure as
29/// `Err` instead of aborting (the `try_` law; see the
30/// [`exn`](mod@crate::exn) module docs).
31///
32/// An empty queue is a `LibraryExn::Syscall` for which
33/// [`is_storage_missing`](LibraryExn::is_storage_missing) is true; an entry
34/// of a different size is `LibraryExn::RetrocausalQueueEntryWrongSize` and is left in
35/// the queue (the size is checked by peeking before consuming).
36pub fn retrocausal_queue_try_consume_sized<const N: usize>(
37    key: &StorageKey,
38) -> Result<[u8; N], LibraryExn> {
39    retrocausal_queue_try_sized(key, false)
40}
41
42pub fn retrocausal_queue_peek_sized<const N: usize>(
43    key: &StorageKey,
44) -> [u8; N] {
45    rcq_result::retrocausal_queue_get_sized(key, true)
46        .or_syscall_throw(SyscallNo::kRetrocausalQueueConsume)
47}
48
49/// Peek at the next queue entry as an `N`-byte array; the `try_`-law
50/// counterpart of [`retrocausal_queue_peek_sized`]. Same error contract as
51/// [`retrocausal_queue_try_consume_sized`].
52pub fn retrocausal_queue_try_peek_sized<const N: usize>(
53    key: &StorageKey,
54) -> Result<[u8; N], LibraryExn> {
55    retrocausal_queue_try_sized(key, true)
56}
57
58/// Shared body of the sized `try_` forms. Checks the entry's length by
59/// peeking before reading it, so a wrong-size entry is reported without
60/// being consumed (and without tripping the read path's size assertion).
61fn retrocausal_queue_try_sized<const N: usize>(
62    key: &StorageKey,
63    peek: bool,
64) -> Result<[u8; N], LibraryExn> {
65    let found = rcq_result::retrocausal_queue_peek_len(key)
66        .or_syscall_exn(SyscallNo::kRetrocausalQueueConsume)?;
67    if found != N as u32 {
68        return Err(LibraryExn::RetrocausalQueueEntryWrongSize {
69            expected: N as u32,
70            found,
71        });
72    }
73    rcq_result::retrocausal_queue_get_sized(key, peek)
74        .or_syscall_exn(SyscallNo::kRetrocausalQueueConsume)
75}
76
77/// Read the next queue entry into `buf` (cleared first), reporting every
78/// failure as `Err`
79/// (the `try_` law): an empty queue is the
80/// [`is_storage_missing`](LibraryExn::is_storage_missing) syscall exn, an
81/// entry larger than `buf` is `StorageSerialization` (unreachable for the
82/// SDK scratch, which is larger than the protocol's entry cap), and any
83/// other syscall failure its syscall exn. With `peek == false` the
84/// entry-larger-than-`buf` error is destructive (see
85/// [`rcq_result::retrocausal_queue_read_into`]); `try_` callers that must
86/// leave a bad entry in the queue read with `peek == true` and pop via
87/// [`retrocausal_queue_try_discard`].
88pub(crate) fn retrocausal_queue_try_read_into(
89    key: &StorageKey,
90    peek: bool,
91    buf: &mut ScratchBuf,
92) -> Result<(), LibraryExn> {
93    match rcq_result::retrocausal_queue_read_into(key, peek, buf) {
94        Ok(Some(())) => Ok(()),
95        Ok(None) => Err(LibraryExn::StorageSerialization),
96        Err(e) => Err(syscall_exn(SyscallNo::kRetrocausalQueueConsume, e)),
97    }
98}
99
100/// Pop the next queue entry without copying its contents, reporting failure
101/// as `Err`. Completes a typed `try_consume` after the entry has been peeked
102/// and decoded, so the pop can no longer fail on the entry's contents.
103pub(crate) fn retrocausal_queue_try_discard(
104    key: &StorageKey,
105) -> Result<(), LibraryExn> {
106    rcq_result::retrocausal_queue_consume_discard(key)
107        .or_syscall_exn(SyscallNo::kRetrocausalQueueConsume)
108}
109
110#[cfg(feature = "alloc")]
111pub fn retrocausal_queue_consume(key: &StorageKey) -> Box<[u8]> {
112    use crate::re_throw::OrReThrow;
113    retrocausal_queue_try_consume(key).or_re_throw()
114}
115
116/// Consume the next queue entry into a boxed slice, reporting failure as
117/// `Err` instead of aborting (the `try_` law). An empty queue is a
118/// `LibraryExn::Syscall` for which
119/// [`is_storage_missing`](LibraryExn::is_storage_missing) is true.
120#[cfg(feature = "alloc")]
121pub fn retrocausal_queue_try_consume(
122    key: &StorageKey,
123) -> Result<Box<[u8]>, LibraryExn> {
124    retrocausal_queue_try_get(key, false)
125}
126
127#[cfg(feature = "alloc")]
128pub fn retrocausal_queue_peek(key: &StorageKey) -> Box<[u8]> {
129    use crate::re_throw::OrReThrow;
130    retrocausal_queue_try_peek(key).or_re_throw()
131}
132
133/// Peek at the next queue entry as a boxed slice; the `try_`-law
134/// counterpart of [`retrocausal_queue_peek`]. Same error contract as
135/// [`retrocausal_queue_try_consume`].
136#[cfg(feature = "alloc")]
137pub fn retrocausal_queue_try_peek(
138    key: &StorageKey,
139) -> Result<Box<[u8]>, LibraryExn> {
140    retrocausal_queue_try_get(key, true)
141}
142
143/// Get the next queue entry's data into a boxed slice.
144///
145/// If `peek` is true, the entry will not be consumed.
146///
147#[cfg(feature = "alloc")]
148fn retrocausal_queue_try_get(
149    key: &StorageKey,
150    peek: bool,
151) -> Result<Box<[u8]>, LibraryExn> {
152    rcq_result::retrocausal_queue_get(key, peek)
153        .or_syscall_exn(SyscallNo::kRetrocausalQueueConsume)
154}