Skip to content

Feature: storage v2 #2024

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions contracts/examples/adder/src/adder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ pub trait Adder {
fn sum(&self) -> SingleValueMapper<BigUint>;

#[init]
fn init(&self, initial_value: BigUint) {
fn init(&mut self, initial_value: BigUint) {
self.sum().set(initial_value);
}

#[upgrade]
fn upgrade(&self, initial_value: BigUint) {
fn upgrade(&mut self, initial_value: BigUint) {
self.init(initial_value);
}

/// Add desired amount to the storage variable.
#[endpoint]
fn add(&self, value: BigUint) {
fn add(&mut self, value: BigUint) {
self.sum().update(|sum| *sum += value);
}
}
6 changes: 5 additions & 1 deletion framework/derive/src/model/endpoint_mutability_metadata.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EndpointMutabilityMetadata {
Mutable,
Readonly,
Expand All @@ -19,4 +19,8 @@ impl EndpointMutabilityMetadata {
},
}
}

pub fn is_mutable(&self) -> bool {
matches!(self, EndpointMutabilityMetadata::Mutable)
}
}
25 changes: 25 additions & 0 deletions framework/derive/src/model/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub enum AutoImpl {
StorageClear { identifier: String },
ProxyGetter,
}

#[derive(Clone, Debug)]
pub enum MethodImpl {
/// Implementation auto-generated by the framework. There can (obviously) be only one per method.
Expand All @@ -31,6 +32,12 @@ impl MethodImpl {
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MethodMutability {
Readonly,
Mutable,
}

/// Models any method argument from a contract, module or callable proxy trait.
#[derive(Clone, Debug)]
pub struct Method {
Expand All @@ -39,6 +46,7 @@ pub struct Method {
pub name: syn::Ident,
pub generics: syn::Generics,
pub unprocessed_attributes: Vec<syn::Attribute>,
pub method_mutability: MethodMutability,
pub method_args: Vec<MethodArgument>,
pub title: Option<String>,
pub output_names: Vec<String>,
Expand Down Expand Up @@ -113,4 +121,21 @@ impl Method {
PublicRole::Private => false,
}
}

pub fn accepts_labels(&self) -> bool {
matches!(
self.public_role,
PublicRole::Init(_)
| PublicRole::Endpoint(_)
| PublicRole::CallbackPromise(_)
| PublicRole::Upgrade(_)
)
}

pub fn accepts_mut_self(&self) -> bool {
match &self.public_role {
PublicRole::Endpoint(endpoint_metadata) => endpoint_metadata.mutability.is_mutable(),
_ => true,
}
}
}
25 changes: 15 additions & 10 deletions framework/derive/src/parse/argument_parse.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,42 @@
use super::attributes::*;
use crate::model::{ArgMetadata, ArgPaymentMetadata, MethodArgument};
use crate::model::{ArgMetadata, ArgPaymentMetadata, MethodArgument, MethodMutability};

pub fn extract_method_args(m: &syn::TraitItemFn) -> Vec<MethodArgument> {
pub fn extract_method_args(m: &syn::TraitItemFn) -> (MethodMutability, Vec<MethodArgument>) {
if m.sig.inputs.is_empty() {
missing_self_panic(m);
}

let mut receiver_processed = false;
m.sig
let mut receiver_mutability = Option::<MethodMutability>::None;
let arguments = m
.sig
.inputs
.iter()
.filter_map(|arg| match arg {
syn::FnArg::Receiver(selfref) => {
if selfref.mutability.is_some() || receiver_processed {
missing_self_panic(m);
if selfref.mutability.is_some() {
receiver_mutability = Some(MethodMutability::Mutable);
} else {
receiver_mutability = Some(MethodMutability::Readonly);
}
receiver_processed = true;
None
},
syn::FnArg::Typed(pat_typed) => {
if !receiver_processed {
if receiver_mutability.is_none() {
missing_self_panic(m);
}

Some(extract_method_arg(pat_typed))
},
})
.collect()
.collect();

let method_mutability = receiver_mutability.unwrap_or_else(|| missing_self_panic(m));
(method_mutability, arguments)
}

fn missing_self_panic(m: &syn::TraitItemFn) -> ! {
panic!(
"Trait method `{}` must have `&self` as its first argument.",
"Trait method `{}` must have `&self` or `&mut self` as its first argument.",
m.sig.ident
)
}
Expand Down
24 changes: 16 additions & 8 deletions framework/derive/src/parse/method_parse.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::model::{Method, MethodImpl, MethodPayableMetadata, PublicRole, TraitProperties};
use crate::model::{
Method, MethodImpl, MethodMutability, MethodPayableMetadata, PublicRole, TraitProperties,
};

use super::{
attributes::extract_doc,
Expand All @@ -25,7 +27,7 @@ pub struct MethodAttributesPass1 {
}

pub fn process_method(m: &syn::TraitItemFn, trait_attributes: &TraitProperties) -> Method {
let method_args = extract_method_args(m);
let (method_mutability, method_args) = extract_method_args(m);

let implementation = if let Some(body) = m.default.clone() {
MethodImpl::Explicit(body)
Expand Down Expand Up @@ -55,6 +57,7 @@ pub fn process_method(m: &syn::TraitItemFn, trait_attributes: &TraitProperties)
name: m.sig.ident.clone(),
generics: m.sig.generics.clone(),
unprocessed_attributes: Vec::new(),
method_mutability,
method_args,
title: None,
output_names: Vec::new(),
Expand Down Expand Up @@ -138,12 +141,17 @@ fn process_attribute_second_pass(
}

fn validate_method(method: &Method) {
let method_name = method.name.to_string();

if !method.accepts_mut_self() {
assert!(
method.method_mutability == MethodMutability::Readonly,
"Method '{method_name}' cannot take &mut self, since it is declared as readonly",
);
}

assert!(
matches!(
method.public_role,
PublicRole::Init(_) | PublicRole::Endpoint(_) | PublicRole::CallbackPromise(_) | PublicRole::Upgrade(_)
) || method.label_names.is_empty(),
"Labels can only be placed on endpoints, constructors, and promises callbacks. Method '{}' is neither.",
&method.name.to_string()
method.accepts_labels() || method.label_names.is_empty(),
"Labels can only be placed on endpoints, constructors, and promises callbacks. Method '{method_name}' is neither",
)
}
Loading