#[macro_export]
macro_rules! schema {
($Schema: ident {
$(
$Field: ident:
$(<$($generic_name: tt: $generic_type: tt),+>)?(
$($arg: ident: $arg_type: ty),*
) -> $value: ty$(,)?
)*
}) => {
$(
pub(crate) struct $Field$(
<$($generic_name: $generic_type),+>
)?$(
(core::marker::PhantomData<($($generic_name),+)>)
)?;
impl$(<$($generic_name: $generic_type),+>)? $Field$(<$($generic_name),+>)? {
#[doc(hidden)]
pub(crate) fn key($($arg: $arg_type),*) -> impl AsRef<[u8]> {
const SCHEMA: &[u8] = stringify!($Schema).as_bytes();
const FIELD: &[u8] = stringify!($Field).as_bytes();
const DST: [u8; 1 + SCHEMA.len() + 1 + FIELD.len()] = {
let mut dst = [0; 1 + SCHEMA.len() + 1 + FIELD.len()];
assert!(SCHEMA.len() < 255);
dst[0] = SCHEMA.len() as u8;
{
let mut b = 0;
while b < SCHEMA.len() {
dst[1 + b] = SCHEMA[b];
b += 1;
}
}
assert!(FIELD.len() < 255);
dst[1 + SCHEMA.len()] = FIELD.len() as u8;
{
let mut b = 0;
while b < FIELD.len() {
dst[(1 + SCHEMA.len() + 1) + b] = FIELD[b];
b += 1;
}
}
dst
};
let mut key = DST.to_vec();
<($($arg_type),*) as $crate::__private::borsh::BorshSerialize>::serialize(
&($($arg),*),
&mut key
).expect("`BorshSerialize` errored when writing to an infallible writer (`Vec`)");
key
}
pub(crate) fn set(
txn: &mut impl $crate::Transaction
$(, $arg: $arg_type)*,
value: &$value
) {
let key = Self::key($($arg),*);
let value = $crate::__private::borsh::to_vec(value)
.expect("`BorshSerialize` errored when writing to an infallible writer (`Vec`)");
$crate::Transaction::set(txn, key, value);
}
pub(crate) fn get(
getter: &impl $crate::Get,
$($arg: $arg_type),*
) -> Option<$value> {
$crate::Get::get(getter, Self::key($($arg),*)).map(|value| {
$crate::__private::borsh::from_slice(value.as_ref())
.expect("`BorshDeserialize` errored when reading a value it wrote")
})
}
pub(crate) fn del(
txn: &mut impl $crate::Transaction
$(, $arg: $arg_type)*
) {
$crate::Transaction::del(txn, &Self::key($($arg),*));
}
pub(crate) fn take(
txn: &mut impl $crate::Transaction
$(, $arg: $arg_type)*
) -> Option<$value> {
let key = Self::key($($arg),*);
let res = $crate::Get::get(txn, &key).map(|value| {
$crate::__private::borsh::from_slice(value.as_ref())
.expect("`BorshDeserialize` errored when reading a value it wrote")
});
if res.is_some() {
$crate::Transaction::del(txn, &key);
}
res
}
}
)*
};
}
#[macro_export]
macro_rules! channel {
($Schema: ident {
$($Field: ident:
$(<$($generic_name: tt: $generic_type: tt),+>)?(
$($arg: ident: $arg_type: ty),*
) -> $value: ty$(,)?
)*
}) => {
#[doc(hidden)]
#[allow(non_snake_case)]
mod $Schema {
use super::*;
$crate::schema! {
$Schema {
$(
$Field: $(<$($generic_name: $generic_type),+>)?(
$($arg: $arg_type,)*
index: u64
) -> $value
)*
}
}
}
$(
pub(crate) struct $Field$(
<$($generic_name: $generic_type),+>
)?$(
(core::marker::PhantomData<($($generic_name),+)>)
)?;
impl$(<$($generic_name: $generic_type),+>)? $Field$(<$($generic_name),+>)? {
pub(crate) fn send(
txn: &mut impl $crate::Transaction
$(, $arg: $arg_type)*
, value: &$value
) {
let messages_sent_key = $Schema::$Field$(::<$($generic_name),+>)?::key($($arg,)* 0);
let messages_sent = $crate::Get::get(txn, &messages_sent_key).map(|counter| {
u64::from_le_bytes(counter.as_ref().try_into().unwrap())
}).unwrap_or(0);
$crate::Transaction::set(txn, &messages_sent_key, (messages_sent + 1).to_le_bytes());
$Schema::$Field$(::<$($generic_name),+>)?::set(txn, $($arg,)* 2 + messages_sent, value);
}
pub(crate) fn peek(
getter: &impl $crate::Get
$(, $arg: $arg_type)*
) -> Option<$value> {
let messages_recvd_key = $Schema::$Field$(::<$($generic_name),+>)?::key($($arg,)* 1);
let messages_recvd = $crate::Get::get(getter, &messages_recvd_key).map(|counter| {
u64::from_le_bytes(counter.as_ref().try_into().unwrap())
}).unwrap_or(0);
$Schema::$Field$(::<$($generic_name),+>)?::get(getter, $($arg,)* 2 + messages_recvd)
}
pub(crate) fn try_recv(
txn: &mut impl $crate::Transaction
$(, $arg: $arg_type)*
) -> Option<$value> {
let messages_recvd_key = $Schema::$Field$(::<$($generic_name),+>)?::key($($arg,)* 1);
let messages_recvd = $crate::Get::get(txn, &messages_recvd_key).map(|counter| {
u64::from_le_bytes(counter.as_ref().try_into().unwrap())
}).unwrap_or(0);
let message_index = 2 + messages_recvd;
let res = $Schema::$Field$(::<$($generic_name),+>)?::get(txn, $($arg,)* message_index);
if res.is_some() {
$Schema::$Field$(::<$($generic_name),+>)?::del(txn, $($arg,)* message_index);
$crate::Transaction::set(txn, &messages_recvd_key, (messages_recvd + 1).to_le_bytes());
}
res
}
}
)*
};
}