Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
b7a2e81
Added and implemented all primitives of a new storage. Implemented `s…
xgreenx Apr 11, 2022
2c06fcc
Simplified storage straits, moved check for atomic to separate trait.
xgreenx Apr 12, 2022
992706e
Refactored StorageLayout.
xgreenx Apr 15, 2022
17b433a
Updated key to be more readble
xgreenx Apr 15, 2022
09fb544
BE looks better than LE=)
xgreenx Apr 15, 2022
184c550
Fix comment
xgreenx Apr 15, 2022
58c21ac
Removed all storage collections
xgreenx May 6, 2022
2a1dea4
Merge branch 'master' into features/storage-rework
xgreenx May 6, 2022
5644402
Merged with master. Added tests that `StorageValue` and `StorageMappi…
xgreenx May 6, 2022
7e4b56d
Removed `SpreadLayout` and all related stuff and traits.
xgreenx May 9, 2022
4ab1b5f
Updated all examples to use the latest changes.
xgreenx May 11, 2022
76c50ee
Removed `StorageType2`. `StorageType` is used everywhere now.
xgreenx May 12, 2022
750bce2
Merge branch 'master' into features/storage-rework
xgreenx May 12, 2022
e8bf915
Make clippy happy
xgreenx May 12, 2022
6f868fb
Make clippy happy.
xgreenx May 12, 2022
b74b9fd
Update comment
xgreenx May 12, 2022
02f478f
Unified metadata and storage key generation. The metadata contains al…
xgreenx May 17, 2022
414d0c0
Merge branch 'master' into features/storage-rework
xgreenx May 17, 2022
b8e74bd
Update metadata to version 4
xgreenx May 17, 2022
da38d41
Fixed tests
xgreenx May 17, 2022
145850f
Merge branch 'master' into features/storage-rework
xgreenx May 17, 2022
f107ca1
Implement `TypeInfo` and `StorageLayout` in `storage_item` macro by d…
xgreenx May 17, 2022
078a04a
Fix tests
xgreenx May 17, 2022
f719a74
Merge branch 'master' into features/storage-rework
xgreenx May 18, 2022
6fe995c
Merge with new release
xgreenx May 18, 2022
ca8a270
Temporary use version 3 for metadata
xgreenx May 18, 2022
294ffc3
Fix ink-waterfall
xgreenx May 18, 2022
9ff2b0c
Size improvements
xgreenx May 18, 2022
52d4070
Merge branch 'master' into features/storage-rework
xgreenx May 18, 2022
44ec9e7
Merge mother
xgreenx May 18, 2022
58c969f
More inline)
xgreenx May 18, 2022
8c93461
Revert back optimization with encode. Better to do it in follow up
xgreenx May 18, 2022
099442b
More size improvements
xgreenx May 19, 2022
377a26d
Revert back panic on pull)
xgreenx May 19, 2022
97fa7b3
One more optimization. When it will be end???=)
xgreenx May 19, 2022
07d3619
Merge branch 'master' into features/storage-rework
xgreenx May 19, 2022
3db8e6d
Added comments why we don't need `extract_from_slice`
xgreenx May 19, 2022
e88d535
Removed `V4` of metadata. It will be updated in follow-up PR.
xgreenx May 19, 2022
c34e67c
We need to pass len...)
xgreenx May 19, 2022
0e136cf
Make clippy happy
xgreenx May 19, 2022
358c00d
Removed `Key`. Prepared the api for transparent hashing.
xgreenx May 20, 2022
2aeb623
Remove bench
xgreenx May 20, 2022
2d34b1d
Improve of dns example by adding one ref=DDDDDD
xgreenx May 20, 2022
88977bc
Merge branch 'master' into features/storage-rework
xgreenx May 21, 2022
45390a6
Merge branch 'master' into features/storage-rework
xgreenx May 25, 2022
9502e34
Renamed everything. Introduces `Storable`
xgreenx May 26, 2022
6441dfc
Make clippy happy
xgreenx May 27, 2022
7fa8cd0
Fixed storable tests
xgreenx Jun 3, 2022
334160c
Fixed storable tests and clippy
xgreenx Jun 3, 2022
d6bfac6
Fix spellcheck
xgreenx Jun 3, 2022
5f05846
Merge branch 'master' into features/storage-rework
xgreenx Jul 11, 2022
e1fe78e
Merge branch 'master' into features/storage-rework
xgreenx Jul 12, 2022
11c86dd
Use unstable functions(with transparent hashing) to work with storage.
xgreenx Jul 12, 2022
345ca79
Fix clippy
xgreenx Jul 12, 2022
b8e46bd
Fix readme
xgreenx Jul 12, 2022
eae9152
Apply suggestions from code review
xgreenx Jul 13, 2022
2b35bd5
Update crates/lang/ir/src/ir/storage_item/config.rs
xgreenx Jul 13, 2022
1873108
Added suggested panic on unwrap
xgreenx Jul 13, 2022
9436889
Merge branch 'master' into features/storage-rework
xgreenx Jul 20, 2022
188d46d
Update to 4.0.0
xgreenx Jul 20, 2022
e6f77d8
Merge branch 'master' into features/storage-rework
xgreenx Jul 20, 2022
9b022f3
Updated errors.
xgreenx Jul 20, 2022
07698e0
Fixed strerr text
xgreenx Jul 20, 2022
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
Prev Previous commit
Next Next commit
Removed all storage collections
Removed all lazy stuff except `StorageMapping` and `StorageValue`. Later I will rename `StorageMapping` into `Mapping`.
Removed `AtomicStatus` trait. Instead of it added `is_atomic!` macro that returns true if the object implements `AtomicGuard<true>`. It solves the problem when the struct contains generics. Now if the generic is marked as `AtomicGuard<true>` then the struct is atomic too, else it is not atomic.
Implemented `#[ink_lang::storage_item]` for structs, enums, and unions.
Started cleaning of the `SpreadLayout` and other stuff. The dispatching codegen already works without it.
  • Loading branch information
xgreenx committed May 6, 2022
commit 58c21accbc5b57b20dac2e8fba8312ffd7ac4974
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ impl CallBuilder<'_> {
))]
#[derive(
::core::fmt::Debug,
::ink_storage::traits::SpreadLayout,
::ink_storage::traits::PackedLayout,
::scale::Encode,
::scale::Decode,
::core::hash::Hash,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ impl ContractRef<'_> {
))]
#[derive(
::core::fmt::Debug,
::ink_storage::traits::SpreadLayout,
::ink_storage::traits::PackedLayout,
::scale::Encode,
::scale::Decode,
::core::hash::Hash,
Expand Down
213 changes: 181 additions & 32 deletions crates/lang/codegen/src/generator/storage_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,24 @@
use crate::GenerateCode;
use derive_more::From;
use ir::Selector;
use proc_macro2::TokenStream as TokenStream2;
use proc_macro2::{
Ident,
TokenStream as TokenStream2,
TokenStream,
};
use quote::{
format_ident,
quote,
ToTokens,
};
use syn::{
parse2,
Data,
DataEnum,
DataStruct,
DataUnion,
Field,
Fields,
GenericParam,
};

Expand All @@ -36,7 +46,11 @@ pub struct StorageItem<'a> {
impl GenerateCode for StorageItem<'_> {
/// Generates ink! storage item code.
fn generate_code(&self) -> TokenStream2 {
let generated_struct = self.generate_struct();
let generated_struct = match self.item.data().clone() {
Data::Struct(struct_item) => self.generate_struct(struct_item),
Data::Enum(enum_item) => self.generate_enum(enum_item),
Data::Union(union_item) => self.generate_union(union_item),
};
let generated_atomic_status = self.generate_atomic_status();
let generated_storage_type = self.generate_storage_type();
let generated_storage_key_holder = self.generate_storage_key_holder();
Expand All @@ -51,41 +65,98 @@ impl GenerateCode for StorageItem<'_> {
}

impl<'a> StorageItem<'a> {
fn generate_struct(&self) -> TokenStream2 {
fn generate_struct(&self, struct_item: DataStruct) -> TokenStream2 {
let item = self.item;
let ident = item.ident();
let struct_ident = item.ident();
let attrs = item.attrs();
let vis = item.vis();
let generics = item.generics();
let salt = item.salt();

let fields = item.fields().map(|field| {
let key_bytes: Vec<u8> = if let Some(field_ident) = &field.ident {
[
&ident.to_string().into_bytes()[..],
&field_ident.to_string().into_bytes()[..],
]
.concat()
let fields = struct_item.fields.iter().enumerate().map(|(i, field)| {
convert_into_storage_field(struct_ident, None, &salt, i, field)
});

quote! {
#(#attrs)*
#vis struct #struct_ident #generics {
#(#fields),*
}
}
}

fn generate_enum(&self, enum_item: DataEnum) -> TokenStream2 {
let item = self.item;
let enum_ident = item.ident();
let attrs = item.attrs();
let vis = item.vis();
let generics = item.generics();
let salt = item.salt();

let variants = enum_item.variants.into_iter().map(|variant| {
let attrs = variant.attrs;
let variant_ident = &variant.ident;
let discriminant = if let Some((eq, expr)) = variant.discriminant {
quote! { #eq #expr}
} else {
ident.to_string().into_bytes()
quote! {}
};

let key = Selector::compute(&key_bytes).into_be_u32();
let fields: Vec<_> = variant
.fields
.iter()
.enumerate()
.map(|(i, field)| {
convert_into_storage_field(
enum_ident,
Some(variant_ident),
&salt,
i,
field,
)
})
.collect();

let mut new_field = field.clone();
let ty = field.ty.clone();
new_field.ty = parse2(quote! {
<#ty as ::ink_storage::traits::StorageType<
::ink_storage::traits::ManualKey<#key, #salt>,
>>::Type
})
.unwrap();
new_field
let fields = match variant.fields {
Fields::Named(_) => quote! { { #(#fields),* } },
Fields::Unnamed(_) => quote! { ( #(#fields),* ) },
Fields::Unit => quote! {},
};

quote! {
#(#attrs)*
#variant_ident #fields #discriminant
}
});

quote! {
#(#attrs)*
#vis struct #ident #generics {
#vis enum #enum_ident #generics {
#(#variants),*
}
}
}

fn generate_union(&self, union_item: DataUnion) -> TokenStream2 {
let item = self.item;
let union_ident = item.ident();
let attrs = item.attrs();
let vis = item.vis();
let generics = item.generics();
let salt = item.salt();

let fields = union_item
.fields
.named
.iter()
.enumerate()
.map(|(i, field)| {
convert_into_storage_field(union_ident, None, &salt, i, field)
});

quote! {
#(#attrs)*
#vis union #union_ident #generics {
#(#fields),*
}
}
Expand All @@ -96,19 +167,34 @@ impl<'a> StorageItem<'a> {
let ident = item.ident();

let (impl_generics, ty_generics, where_clause) = item.generics().split_for_impl();
let inner_is_atomic: Vec<_> = item
.fields()
.map(|field| {
let ty = field.ty.clone();
quote! { <#ty as ::ink_storage::traits::AtomicStatus>::IS_ATOMIC }

let types: Vec<_> = match item.data() {
Data::Struct(st) => st.fields.iter().map(|field| field.ty.clone()).collect(),
Data::Enum(en) => {
en.variants
.iter()
.map(|variant| variant.fields.iter())
.flatten()
.map(|field| field.ty.clone())
.collect()
}
Data::Union(un) => {
un.fields
.named
.iter()
.map(|field| field.ty.clone())
.collect()
}
};

let inner_is_atomic: Vec<_> = types
.iter()
.map(|t| {
quote! { ::ink_storage::is_atomic!(#t) }
})
.collect();

quote! {
impl #impl_generics ::ink_storage::traits::AtomicStatus for #ident #ty_generics #where_clause {
const IS_ATOMIC: bool = #(#inner_is_atomic)&&*;
}

impl #impl_generics ::ink_storage::traits::AtomicGuard< { #(#inner_is_atomic)&&* } >
for #ident #ty_generics #where_clause {}
}
Expand Down Expand Up @@ -226,3 +312,66 @@ impl<'a> StorageItem<'a> {
}
}
}

/// # Note
///
/// - `variant_ident` is `None` for structures and unions.
/// - if the field is unnamed then `field_ident` is `field_{}` where `{}` is a number of the field.
///
/// Evaluates the storage key of the field in the structure, variant or union.
///
/// 1. Compute the ASCII byte representation of `struct_ident` and call it `S`.
/// 1. If `variant_ident` is `Some` then computes the ASCII byte representation and call it `V`.
/// 1. Compute the ASCII byte representation of `field_ident` and call it `F`.
/// 1. Concatenate (`S` and `F`) or (`S`, `V` and `F`) using `::` as separator and call it `C`.
/// 1. Apply the `BLAKE2` 256-bit hash `H` of `C`.
/// 1. The first 4 bytes of `H` make up the storage key.
fn compute_storage_key(
struct_ident: &syn::Ident,
variant_ident: Option<&syn::Ident>,
field_ident: &syn::Ident,
) -> u32 {
let separator = &b"::"[..];
let composed_key = if let Some(variant) = variant_ident {
[
&struct_ident.to_string().into_bytes()[..],
&variant.to_string().into_bytes()[..],
&field_ident.to_string().into_bytes()[..],
]
.join(separator)
} else {
[
&struct_ident.to_string().into_bytes()[..],
&field_ident.to_string().into_bytes()[..],
]
.join(separator)
};

Selector::compute(&composed_key).into_be_u32()
}

fn convert_into_storage_field(
struct_ident: &Ident,
variant_ident: Option<&syn::Ident>,
salt: &TokenStream,
index: usize,
field: &Field,
) -> Field {
let field_ident = if let Some(field_ident) = &field.ident {
field_ident.clone()
} else {
format_ident!("field_{}", index)
};

let key = compute_storage_key(&struct_ident, variant_ident, &field_ident);

let mut new_field = field.clone();
let ty = field.ty.clone();
new_field.ty = parse2(quote! {
<#ty as ::ink_storage::traits::StorageType<
::ink_storage::traits::ManualKey<#key, #salt>,
>>::Type
})
.unwrap();
new_field
}
74 changes: 0 additions & 74 deletions crates/lang/codegen/src/generator/trait_def/call_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,12 @@ impl GenerateCode for CallBuilder<'_> {
fn generate_code(&self) -> TokenStream2 {
let struct_definition = self.generate_struct_definition();
let storage_layout_impl = self.generate_storage_layout_impl();
let spread_layout_impl = self.generate_spread_layout_impl();
let packed_layout_impl = self.generate_packed_layout_impl();
let auxiliary_trait_impls = self.generate_auxiliary_trait_impls();
let to_from_account_id_impls = self.generate_to_from_account_id_impls();
let ink_trait_impl = self.generate_ink_trait_impl();
quote! {
#struct_definition
#storage_layout_impl
#spread_layout_impl
#packed_layout_impl
#auxiliary_trait_impls
#to_from_account_id_impls
#ink_trait_impl
Expand Down Expand Up @@ -155,76 +151,6 @@ impl CallBuilder<'_> {
)
}

/// Generates the `SpreadLayout` trait implementation for the account wrapper.
///
/// # Note
///
/// Due to the generic parameter `E` and Rust's default rules for derive generated
/// trait bounds it is not recommended to derive the `SpreadLayout` trait implementation.
fn generate_spread_layout_impl(&self) -> TokenStream2 {
let span = self.span();
let call_builder_ident = self.ident();
quote_spanned!(span=>
/// We require this manual implementation since the derive produces incorrect trait bounds.
impl<E> ::ink_storage::traits::SpreadLayout
for #call_builder_ident<E>
where
E: ::ink_env::Environment,
<E as ::ink_env::Environment>::AccountId: ::ink_storage::traits::SpreadLayout,
{
const FOOTPRINT: ::core::primitive::u64 = 1;
const REQUIRES_DEEP_CLEAN_UP: ::core::primitive::bool = false;

#[inline]
fn pull_spread(ptr: &mut ::ink_primitives::KeyPtr) -> Self {
Self {
account_id: <<E as ::ink_env::Environment>::AccountId
as ::ink_storage::traits::SpreadLayout>::pull_spread(ptr)
}
}

#[inline]
fn push_spread(&self, ptr: &mut ::ink_primitives::KeyPtr) {
<<E as ::ink_env::Environment>::AccountId
as ::ink_storage::traits::SpreadLayout>::push_spread(&self.account_id, ptr)
}

#[inline]
fn clear_spread(&self, ptr: &mut ::ink_primitives::KeyPtr) {
<<E as ::ink_env::Environment>::AccountId
as ::ink_storage::traits::SpreadLayout>::clear_spread(&self.account_id, ptr)
}
}
)
}

/// Generates the `PackedLayout` trait implementation for the account wrapper.
///
/// # Note
///
/// Due to the generic parameter `E` and Rust's default rules for derive generated
/// trait bounds it is not recommended to derive the `PackedLayout` trait implementation.
fn generate_packed_layout_impl(&self) -> TokenStream2 {
let span = self.span();
let call_builder_ident = self.ident();
quote_spanned!(span=>
/// We require this manual implementation since the derive produces incorrect trait bounds.
impl<E> ::ink_storage::traits::PackedLayout
for #call_builder_ident<E>
where
E: ::ink_env::Environment,
<E as ::ink_env::Environment>::AccountId: ::ink_storage::traits::PackedLayout,
{
#[inline]
fn pull_packed(&mut self, _at: &::ink_primitives::Key) {}
#[inline]
fn push_packed(&self, _at: &::ink_primitives::Key) {}
#[inline]
fn clear_packed(&self, _at: &::ink_primitives::Key) {}
}
)
}

/// Generates trait implementations for auxiliary traits for the account wrapper.
///
/// # Note
Expand Down
Loading