1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
//! 🎁 Applet module
/// Applet creation & update trait
pub trait Applet {
/// Creation of a new module
///
/// This is called once on startup of the module
fn new() -> Self;
/// Implement the update of the applet module here
fn update(&mut self) {}
}
/// Persistable applet state accessor
#[cfg(feature = "with_serde")]
pub trait AppletPersist<T>
where
T: serde::de::DeserializeOwned + serde::Serialize,
{
/// Accessor to Serde-serializable structure for serializing and deserializing state
fn persistable_state(&mut self) -> &mut T;
/// Optional callback just before state is persisted
fn pre_persist(&mut self) {}
/// Optional callback after state has een restored
fn post_restore(&mut self) {}
}
/// Implement an applet module
#[macro_export]
macro_rules! impl_applet {
($module: ty) => {
use $crate::applet::Applet as _;
static mut MODULE: Option<$module> = None;
#[no_mangle]
pub fn ark_initialize() {
$crate::init();
// SAFETY: Sound to access static as we do not use threads in Wasm and this is guaranteed to be called first in the module
unsafe {
MODULE = Some(<$module as $crate::applet::Applet>::new());
}
}
#[no_mangle]
pub fn ark_applet_update() {
// SAFETY: Sound to access static as we do not use threads in Wasm and this is guaranteed to be initialized on startup with `ark_initialize` first
unsafe {
let module = MODULE.as_mut().unwrap();
<$module as $crate::applet::Applet>::update(module);
}
}
};
}
/// Implement an applet module that can have persistent state
#[macro_export]
#[cfg(feature = "with_serde")]
macro_rules! impl_applet_persist {
($module: ty) => {
$crate::impl_applet!($module);
use $crate::applet::AppletPersist as _;
use $crate::ErrorCode;
#[no_mangle]
pub unsafe fn ark_state_persist() -> ErrorCode {
if let Some(module) = MODULE.as_mut() {
module.pre_persist();
match $crate::applet::serialize_state(module.persistable_state()) {
Ok(state) => {
ark::core::return_slice(&state);
ErrorCode::Success
}
Err(err) => {
$crate::error!("Couldn't save state, err: {:?}", &err);
ErrorCode::InternalError
}
}
} else {
ErrorCode::InternalError
}
}
#[no_mangle]
pub unsafe fn ark_state_restore(state_ptr: *const u8, state_size: u32) -> ErrorCode {
let state_slice = std::slice::from_raw_parts(state_ptr, state_size as usize);
if let Some(module) = MODULE.as_mut() {
let module_state = module.persistable_state();
match $crate::applet::deserialize_state(state_slice) {
Ok(new_state) => {
*module_state = new_state;
module.post_restore();
ErrorCode::Success
}
Err(err) => {
$crate::error!("Couldn't load state, err: {:?}", &err);
ErrorCode::InternalError
}
}
} else {
ErrorCode::InternalError
}
}
};
}
/// Serialize applet state to binary blob
///
/// This is an internal function used by the `impl_applet_persist` macro
#[doc(hidden)]
#[cfg(feature = "with_serde")]
pub fn serialize_state<T: ?Sized>(value: &T) -> Result<Vec<u8>, flexbuffers::SerializationError>
where
T: serde::Serialize,
{
let mut serializer = flexbuffers::FlexbufferSerializer::new();
value.serialize(&mut serializer)?;
let vec = serializer.take_buffer();
Ok(vec)
}
/// Deserialize applet from binary blob
///
/// This is an internal function used by the `impl_applet_persist` macro
#[doc(hidden)]
#[cfg(feature = "with_serde")]
pub fn deserialize_state<'a, T>(bytes: &'a [u8]) -> Result<T, flexbuffers::DeserializationError>
where
T: serde::Deserialize<'a>,
{
let reader = flexbuffers::Reader::get_root(bytes)?;
let v = T::deserialize(reader)?;
Ok(v)
}