Skip to content

Commit

Permalink
Merge branch 'master' into 0xdeafbeef/push-mvvntplxysln
Browse files Browse the repository at this point in the history
  • Loading branch information
0xdeafbeef authored Nov 21, 2024
2 parents 8610ead + 92d5a8b commit db98768
Show file tree
Hide file tree
Showing 36 changed files with 2,228 additions and 409 deletions.
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "everscale-types"
description = "A set of primitive types and utilities for the Everscale blockchain."
authors = ["Ivan Kalinin <[email protected]>"]
repository = "https://github.com/broxus/everscale-types"
version = "0.1.0-rc.8"
version = "0.1.2"
edition = "2021"
rust-version = "1.77"
include = ["src/**/*.rs", "benches/**/*.rs", "LICENSE-*", "README.md"]
Expand Down Expand Up @@ -57,8 +57,9 @@ sha2 = "0.10"
smallvec = { version = "1.9", features = ["union"] }
thiserror = "1.0"
tl-proto = { version = "0.4", optional = true }
typeid = { version = "1.0", optional = true }

everscale-types-proc = { version = "=0.1.4", path = "proc" }
everscale-types-proc = { version = "=0.1.5", path = "proc" }

[dev-dependencies]
anyhow = "1.0"
Expand Down Expand Up @@ -86,6 +87,7 @@ abi = [
"dep:num-bigint",
"dep:num-traits",
"dep:serde",
"dep:typeid",
"models",
]
venom = []
Expand Down
17 changes: 7 additions & 10 deletions benches/mine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,16 @@ fn do_mine(code: &Cell, factory_addr: &StdAddr, recipient: &StdAddr, reward: u12

let mut data = RawDict::<64>::new();

unsafe {
data.set_ext(KEY_ZERO.as_slice_unchecked(), &HashBytes::ZERO, cx)
.unwrap();
data.set_ext(KEY_ZERO.as_slice_allow_pruned(), &HashBytes::ZERO, cx)
.unwrap();

let airdrop_data_child = CellBuilder::build_from_ext((recipient, reward), cx).unwrap();
let airdrop_data =
CellBuilder::build_from_ext((factory_addr, airdrop_data_child), cx).unwrap();
let airdrop_data_child = CellBuilder::build_from_ext((recipient, reward), cx).unwrap();
let airdrop_data = CellBuilder::build_from_ext((factory_addr, airdrop_data_child), cx).unwrap();

data.set_ext(KEY_TWO.as_slice_unchecked(), &airdrop_data, cx)
.unwrap();
}
data.set_ext(KEY_TWO.as_slice_allow_pruned(), &airdrop_data, cx)
.unwrap();

let nonce_key = unsafe { KEY_ONE.as_slice_unchecked() };
let nonce_key = KEY_ONE.as_slice_allow_pruned();

let mut nonce = 0;
loop {
Expand Down
4 changes: 2 additions & 2 deletions proc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "everscale-types-proc"
description = "Proc-macro helpers for everscale-types"
authors = ["Ivan Kalinin <[email protected]>"]
repository = "https://github.com/broxus/everscale-types"
version = "0.1.4"
version = "0.1.5"
edition = "2021"
include = ["src/**/*.rs", "../LICENSE-*", "../README.md"]
license = "MIT OR Apache-2.0"
Expand All @@ -14,4 +14,4 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = ["visit"] }
syn = { version = "2.0.87", features = ["visit", "full"] }
100 changes: 87 additions & 13 deletions proc/src/derive_load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,33 @@ fn build_struct(
style: ast::Style,
fields: &[ast::Field<'_>],
) -> TokenStream {
let condition = container.attrs.tlb_tag.and_then(load_tag_op);
let mut tag_version = None;
let tags = match &container.attrs.tlb_tag {
attr::ContainerTag::None => None,
attr::ContainerTag::Single(tag) => load_tag(*tag),
attr::ContainerTag::Multiple(tags) => load_tags_versioned(tags).map(|load_tags| {
let ident = quote::format_ident!("__tag_version");
let res = quote! { let #ident = #load_tags; };
tag_version = Some(ident);
res
}),
};

let members = fields.iter().map(|field| {
let ident = &field.member;
let op = load_op(lifetime_def, field.ty);
let ty = field.ty;
let mut op = load_op(lifetime_def, ty);

if let (Some(since), Some(tag_version)) = (field.attrs.since_tag, &tag_version) {
op = quote! {
if #tag_version >= #since {
#op
} else {
<#ty as Default>::default()
}
};
}

quote! {
#ident: #op
}
Expand Down Expand Up @@ -102,15 +124,75 @@ fn build_struct(
};

quote! {
#condition
#tags
#result
}
}

fn load_tag_op(tag: attr::TlbTag) -> Option<TokenStream> {
fn load_tag(tag: attr::TlbTag) -> Option<TokenStream> {
let (op, value) = load_tag_op_value(tag)?;

Some(quote! {
match #op {
::core::result::Result::Ok(#value) => {},
::core::result::Result::Ok(_) => return ::core::result::Result::Err(::everscale_types::error::Error::InvalidTag),
::core::result::Result::Err(e) => return ::core::result::Result::Err(e),
}
})
}

fn load_tags_versioned(tags: &[attr::TlbTag]) -> Option<TokenStream> {
let mut iter = tags.iter();

let first_tag = iter.next()?;
let (op, first_value) = load_tag_op_value(*first_tag)?;

let mut values = Vec::with_capacity(tags.len());
values.push(first_value);

for tag in iter {
values.push(match tag.bits {
0 => continue,
1 => {
let value = tag.value != 0;
quote!(#value)
}
2..=8 => {
let value = tag.value as u8;
quote!(#value)
}
16 => {
let value = tag.value as u16;
quote!(#value)
}
32 => {
let value = tag.value;
quote!(#value)
}
_ => {
let value = tag.value as u64;
quote!(#value)
}
});
}

let values = values.into_iter().enumerate().map(|(i, value)| {
quote! { ::core::result::Result::Ok(#value) => #i }
});

Some(quote! {
match #op {
#(#values),*,
::core::result::Result::Ok(_) => return ::core::result::Result::Err(::everscale_types::error::Error::InvalidTag),
::core::result::Result::Err(e) => return ::core::result::Result::Err(e),
}
})
}

fn load_tag_op_value(tag: attr::TlbTag) -> Option<(TokenStream, TokenStream)> {
let bits = tag.bits as u16;

let (op, value) = match bits {
Some(match bits {
0 => return None,
1 => {
let value = tag.value != 0;
Expand All @@ -136,14 +218,6 @@ fn load_tag_op(tag: attr::TlbTag) -> Option<TokenStream> {
let value = tag.value as u64;
(quote!(__slice.load_uint(#bits)), quote!(#value))
}
};

Some(quote! {
match #op {
::core::result::Result::Ok(#value) => {},
::core::result::Result::Ok(_) => return ::core::result::Result::Err(::everscale_types::error::Error::InvalidTag),
::core::result::Result::Err(e) => return ::core::result::Result::Err(e),
}
})
}

Expand Down
96 changes: 90 additions & 6 deletions proc/src/derive_store.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::BTreeSet;

use proc_macro2::TokenStream;
use quote::quote;

Expand Down Expand Up @@ -51,17 +53,40 @@ fn build_struct(
style: ast::Style,
fields: &[ast::Field<'_>],
) -> TokenStream {
let store_tag = container.attrs.tlb_tag.and_then(store_tag_op);
let mut tag_version = None;
let (compute_tag_version, store_tag) = match &container.attrs.tlb_tag {
attr::ContainerTag::None => (None, None),
attr::ContainerTag::Single(tag) => (None, store_tag(*tag)),
attr::ContainerTag::Multiple(tags) => store_tags_versioned(tags, fields, &mut tag_version),
};

let fields_len = fields.len();
let members = fields.iter().enumerate().map(|(i, field)| {
let ident = &field.member;
let field_ident = quote!(self.#ident);
let op = store_op(&field_ident, field.ty);
if i + 1 == fields_len {
op
} else {
into_ok(op)

let is_last = i + 1 == fields_len;
match (field.attrs.since_tag, &tag_version) {
(Some(since), Some(tag_version)) if is_last => {
quote! {
if #tag_version >= #since {
#op
} else {
Ok(())
}
}
}
(Some(since), Some(tag_version)) => {
let op = into_ok(op);
quote! {
if #tag_version >= #since {
#op
}
}
}
_ if is_last => op,
_ => into_ok(op),
}
});

Expand All @@ -79,14 +104,15 @@ fn build_struct(
let store_tag = store_tag.map(into_ok);
quote! {
#validate_with
#compute_tag_version
#store_tag
#(#members)*
}
}
}
}

fn store_tag_op(tag: attr::TlbTag) -> Option<TokenStream> {
fn store_tag(tag: attr::TlbTag) -> Option<TokenStream> {
let bits = tag.bits as u16;

let op = match bits {
Expand Down Expand Up @@ -117,6 +143,64 @@ fn store_tag_op(tag: attr::TlbTag) -> Option<TokenStream> {
Some(quote!(__builder.#op))
}

// Returns (tag_version, stop_tag)
fn store_tags_versioned(
tags: &[attr::TlbTag],
fields: &[ast::Field<'_>],
tag_version: &mut Option<syn::Ident>,
) -> (Option<TokenStream>, Option<TokenStream>) {
let Some(first_tag) = tags.first() else {
return (None, None);
};

let mut used_tags = BTreeSet::new();
let mut version_guards = Vec::new();
for field in fields {
if let Some(since) = field.attrs.since_tag {
used_tags.insert(since);

let tag_version =
tag_version.get_or_insert_with(|| quote::format_ident!("__tag_version"));

let ident = &field.member;
let ty = field.ty;

// TODO: Optimize codegen
version_guards.push(quote! {
if self.#ident != <#ty as Default>::default() {
#tag_version = std::cmp::max(#tag_version, #since);
}
});
}
}

let Some(tag_version) = &tag_version else {
return (None, store_tag(*first_tag));
};

used_tags.remove(&0);
let match_arms = used_tags.into_iter().filter_map(|tag_index| {
let store_op = store_tag(tags[tag_index])?;
Some(quote! { #tag_index => #store_op })
});
let Some(store_first) = store_tag(*first_tag) else {
return (None, None);
};

let store_tag = quote! {
match #tag_version {
#(#match_arms),*,
_ => #store_first,
}
};

let compute_tag_version = quote! {
let mut #tag_version = 0usize;
#(#version_guards)*
};
(Some(compute_tag_version), Some(store_tag))
}

fn store_op(field_ident: &TokenStream, ty: &syn::Type) -> TokenStream {
#[allow(clippy::unnecessary_operation)]
'fallback: {
Expand Down
Loading

0 comments on commit db98768

Please sign in to comment.