Skip to content

Commit 1c7708c

Browse files
make LazyCell implicit
Signed-off-by: Valentyn Faychuk <valy@faychuk.com>
1 parent c1c3617 commit 1c7708c

3 files changed

Lines changed: 92 additions & 20 deletions

File tree

contract_samples/rust/examples/counter_macros.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,31 @@ use alloc::vec::Vec;
66
use alloc::string::ToString;
77
use amadeus_sdk::*;
88

9-
#[derive(Contract, Default)]
9+
#[contract_state]
1010
struct SimpleCounter {
11-
count: LazyCell<i128>,
12-
owner: LazyCell<Vec<u8>>,
11+
count: i128,
12+
owner: Vec<u8>,
1313
}
1414

1515
#[contract]
1616
impl SimpleCounter {
1717
pub fn init(&mut self) {
18-
self.owner.set(account_current());
19-
self.count.set(0);
18+
*self.owner = account_current();
19+
*self.count = 0;
2020
log("Counter initialized");
2121
}
2222

2323
pub fn increment(&mut self, amount: Vec<u8>) {
24-
let amount_val = i128::from_bytes(amount);
25-
let current = self.count.get();
26-
self.count.set(current + amount_val);
24+
*self.count += i128::from_bytes(amount);
2725
}
2826

2927
pub fn get(&self) -> Vec<u8> {
30-
self.count.get().to_string().into_bytes()
28+
(*self.count).to_string().into_bytes()
3129
}
3230

3331
pub fn reset(&mut self) {
3432
let caller = account_caller();
35-
let owner = self.owner.get();
36-
amadeus_sdk::assert!(caller == owner, "unauthorized");
37-
self.count.set(0);
33+
amadeus_sdk::assert!(*self.owner == caller, "unauthorized");
34+
*self.count = 0;
3835
}
3936
}

contract_samples/rust/sdk-macros/src/lib.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,57 @@
11
use proc_macro::TokenStream;
22
use quote::quote;
3-
use syn::{parse_macro_input, DeriveInput, Data, Fields, ItemImpl, ItemFn, ImplItem, FnArg, ReturnType, Type};
3+
use syn::{parse_macro_input, ItemImpl, ItemFn, ImplItem, FnArg, ReturnType, Type, ItemStruct, Fields};
44

5-
#[proc_macro_derive(Contract)]
6-
pub fn derive_contract(input: TokenStream) -> TokenStream {
7-
let input = parse_macro_input!(input as DeriveInput);
5+
#[proc_macro_attribute]
6+
pub fn contract_state(_attr: TokenStream, item: TokenStream) -> TokenStream {
7+
let input = parse_macro_input!(item as ItemStruct);
88
let name = &input.ident;
9-
let Data::Struct(data) = &input.data else { return TokenStream::new() };
10-
let Fields::Named(fields) = &data.fields else { return TokenStream::new() };
9+
let vis = &input.vis;
10+
let attrs = &input.attrs;
11+
12+
let Fields::Named(ref fields) = input.fields else {
13+
return TokenStream::from(quote! { #input });
14+
};
15+
16+
let transformed_fields = fields.named.iter().map(|f| {
17+
let field_name = &f.ident;
18+
let field_vis = &f.vis;
19+
let field_attrs = &f.attrs;
20+
let field_ty = &f.ty;
21+
quote! {
22+
#(#field_attrs)*
23+
#field_vis #field_name: LazyCell<#field_ty>
24+
}
25+
});
1126

1227
let init_calls = fields.named.iter().map(|f| {
1328
let field = f.ident.as_ref().unwrap();
1429
let key = field.to_string();
15-
quote! { self.#field = LazyCell::new(b!("__state__::", #key)); }
30+
quote! { self.#field = LazyCell::new(#key.as_bytes().to_vec()); }
1631
});
1732

1833
let flush_calls = fields.named.iter().map(|f| {
1934
let field = f.ident.as_ref().unwrap();
2035
quote! { self.#field.flush(); }
2136
});
2237

38+
let default_fields = fields.named.iter().map(|f| {
39+
let field_name = &f.ident;
40+
quote! { #field_name: LazyCell::default() }
41+
});
42+
2343
TokenStream::from(quote! {
44+
#(#attrs)*
45+
#vis struct #name {
46+
#(#transformed_fields),*
47+
}
48+
49+
impl Default for #name {
50+
fn default() -> Self {
51+
Self { #(#default_fields),* }
52+
}
53+
}
54+
2455
impl #name {
2556
pub fn __init_lazy_fields(&mut self) { #(#init_calls)* }
2657
pub fn __flush_lazy_fields(&self) { #(#flush_calls)* }

contract_samples/rust/sdk/src/lib.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub mod encoding;
88
pub use context::*;
99
pub use storage::*;
1010
pub use encoding::*;
11-
pub use amadeus_sdk_macros::{contract, Contract};
11+
pub use amadeus_sdk_macros::{contract, contract_state};
1212

1313
use core::panic::PanicInfo;
1414

@@ -108,6 +108,39 @@ pub struct LazyCell<T> {
108108
dirty: core::cell::Cell<bool>,
109109
}
110110

111+
impl<T> core::ops::Deref for LazyCell<T>
112+
where
113+
T: FromKvBytes + Default + Clone
114+
{
115+
type Target = T;
116+
117+
fn deref(&self) -> &T {
118+
if self.value.borrow().is_none() {
119+
let loaded = kv_get::<T>(&self.key).unwrap_or_default();
120+
*self.value.borrow_mut() = Some(loaded);
121+
}
122+
unsafe {
123+
(*self.value.as_ptr()).as_ref().unwrap()
124+
}
125+
}
126+
}
127+
128+
impl<T> core::ops::DerefMut for LazyCell<T>
129+
where
130+
T: FromKvBytes + Default + Clone
131+
{
132+
fn deref_mut(&mut self) -> &mut T {
133+
if self.value.borrow().is_none() {
134+
let loaded = kv_get::<T>(&self.key).unwrap_or_default();
135+
*self.value.borrow_mut() = Some(loaded);
136+
}
137+
self.dirty.set(true);
138+
unsafe {
139+
(*self.value.as_ptr()).as_mut().unwrap()
140+
}
141+
}
142+
}
143+
111144
impl<T> Default for LazyCell<T> {
112145
fn default() -> Self {
113146
Self::new(Vec::new())
@@ -143,4 +176,15 @@ impl<T> LazyCell<T> {
143176
*self.value.borrow_mut() = Some(val);
144177
self.dirty.set(true);
145178
}
179+
180+
pub fn update<F>(&self, f: F) where T: FromKvBytes + Default + Clone, F: FnOnce(T) -> T {
181+
let current = self.get();
182+
let new_value = f(current);
183+
self.set(new_value);
184+
}
185+
186+
pub fn add(&self, amount: T) where T: FromKvBytes + Default + Clone + core::ops::Add<Output = T> {
187+
let current = self.get();
188+
self.set(current + amount);
189+
}
146190
}

0 commit comments

Comments
 (0)