Hi, we’ve got a lot of different types that use Storable, so I ended up making my own derive macro. It only uses unbounded, and that’s not a huge problem because it’s easy to modify the macro to take parameters. We’ve got about 400 types of struct that need it.
///
/// Storable
/// just so the code's in one place, we can redo this in the future
/// always uses UNBOUNDED
///
#[proc_macro_derive(Storable)]
pub fn storable(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let expanded = quote! {
impl ::lib_ic::storage::storable::Storable for #name {
fn to_bytes(&self) -> ::std::borrow::Cow<[u8]> {
::std::borrow::Cow::Owned(::lib_cbor::serialize(self).unwrap())
}
fn from_bytes(bytes: ::std::borrow::Cow<[u8]>) -> Self {
::lib_cbor::deserialize(&bytes).unwrap()
}
const BOUND: ::lib_ic::storage::storable::Bound = ::lib_ic::storage::storable::Bound::Unbounded;
}
};
TokenStream::from(expanded)
}
and the candid version:
///
/// DataValue
///
#[derive(CandidType, Clone, Debug, Serialize, Deserialize)]
pub struct DataValue {
pub data: Vec<u8>,
pub metadata: Metadata,
}
impl Storable for DataValue {
fn to_bytes(&self) -> Cow<[u8]> {
Cow::Owned(Encode!(self).unwrap())
}
fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
Decode!(bytes.as_ref(), Self).unwrap()
}
const BOUND: Bound = Bound::Unbounded;
}
Is using the candid macros the most optimal way to do this, or Serialize?
Is there a reason that something like this doesn’t exist, at least for basic structures?