[contracts] define_env! re-write as a proc macro#11888
[contracts] define_env! re-write as a proc macro#11888paritytech-processbot[bot] merged 26 commits intomasterfrom
define_env! re-write as a proc macro#11888Conversation
athei
left a comment
There was a problem hiding this comment.
I like it. Just one thing that came to mind: I proposed using Result<ReturnCode, TrapReason> but that can be confusing because we actually call .into() on it in the macro. So I think we should be using: Result<ReturnCode, impl Into<TrapReason>> so that it is clear that any type that can be converted it is okay.
Hm, I don't see any places where such a conversion happens. E.g. this host function definition #[version(1)]
fn seal_set_storage(
ctx: Runtime<E: Ext>,
key_ptr: u32,
value_ptr: u32,
value_len: u32,
) -> Result<u32, TrapReason> {
ctx.set_storage(KeyType::Fix, key_ptr, value_ptr, value_len)
}expands the following piece of code: f("seal1".as_bytes(), "seal_set_storage".as_bytes(), {
fn seal_set_storage<E: Ext>(
ctx: &mut crate::wasm::Runtime<E>,
args: &[sp_sandbox::Value],
) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError>
where
<E::T as frame_system::Config>::AccountId: sp_core::crypto::UncheckedFrom<<E::T as frame_system::Config>::Hash>
+ AsRef<[u8]>,
{
#[allow(unused)]
let mut args = args.iter();
let mut body = || {
let key_ptr : < u32 as crate :: wasm :: env_def :: ConvertibleToWasm > :: NativeType = args . next () . and_then (| v | < u32 as crate :: wasm :: env_def :: ConvertibleToWasm > :: from_typed_value (v . clone ())) . expect ("precondition: all imports should be checked against the signatures of corresponding
functions defined by `#[define_env]` proc macro by the user of the macro;
thus this can never be `None`;
qed;") ;
let value_ptr : < u32 as crate :: wasm :: env_def :: ConvertibleToWasm > :: NativeType = args . next () . and_then (| v | < u32 as crate :: wasm :: env_def :: ConvertibleToWasm > :: from_typed_value (v . clone ())) . expect ("precondition: all imports should be checked against the signatures of corresponding
functions defined by `#[define_env]` proc macro by the user of the macro;
thus this can never be `None`;
qed;") ;
let value_len : < u32 as crate :: wasm :: env_def :: ConvertibleToWasm > :: NativeType = args . next () . and_then (| v | < u32 as crate :: wasm :: env_def :: ConvertibleToWasm > :: from_typed_value (v . clone ())) . expect ("precondition: all imports should be checked against the signatures of corresponding
functions defined by `#[define_env]` proc macro by the user of the macro;
thus this can never be `None`;
qed;") ;
{
ctx.set_storage(KeyType::Fix, key_ptr, value_ptr, value_len)
}
};
let r = body().map_err(|reason| {
ctx.set_trap_reason(reason);
sp_sandbox::HostError
})?;
return Ok(sp_sandbox::ReturnValue::Value({ r.to_typed_value() }));
}
seal_set_storage::<E>
});it just stores the |
athei
left a comment
There was a problem hiding this comment.
You are right. The conversion happens explicitly. Mostly through ?.
| .ok_or(err("Invalid environment definition, expected `mod` to be inlined."))? | ||
| .1; | ||
|
|
||
| let mut host_funcs = Vec::<HostFn>::default(); |
There was a problem hiding this comment.
The functional style would be let host_funcs = items.iter().map(|i| HostFn::try_from(i.clone())).collect::<Result<Vec<_>, _>()?. To be fair a lot of people do not like this (e.g. Sergei) 🙈
|
|
||
| match *ret_ty { | ||
| syn::Type::Path(tp) => { | ||
| let result = &tp.path.segments.first().ok_or(err(span, &msg))?; |
There was a problem hiding this comment.
Should be last() in case of fully qualified type e.g. ::core::result::Result
| syn::Type::Path(tp) => Ok(tp | ||
| .path | ||
| .segments | ||
| .first() |
There was a problem hiding this comment.
| .first() | |
| .last() |
| syn::PathArguments::AngleBracketed(group) => { | ||
| group.args.len().eq(&2).then_some(42).ok_or(err(span, &msg))?; | ||
|
|
||
| let arg2 = group.args.last().ok_or(err(span, &msg))?; |
There was a problem hiding this comment.
Could possibly simply the args extraction with slice pattern matching e,g, if let [arg1, arg2] = &group.args[..] { }
There was a problem hiding this comment.
this would add up one more indent lvl 🙈
There was a problem hiding this comment.
You could do something like:
let (arg1, arg2) = if let [arg1, arg2] = &group.args[..] {
Ok((arg1, arrg2))
} else {
Err("Expected exactly 2 args")
}?;
There was a problem hiding this comment.
would be great, but &group.args is Punctuated and even .iter().collect() won't work on it (the trait FromIterator<GenericArgument> is not implemented for GenericArgument)
|
Once you satisfied the CI (clippy) we can merge. |
|
bot merge |
* define_env proc macro basics + can_satisfy part ready * expand_impls part done * fix of the &FunctionType bug * pallet is compiled * updated host fn definition syntax * docs comments allowed to host fn definitions * all 53 host funcs re-defined by the new macro * unstable feat fix * cleanup * legacy mbe macros cleaned up * Added Env ident to macro attribute; all tests pass! * \#[v(..)] -> \#[version(..)] * some tiny corrections * save * builds with non-magic rt; tests fail * tests pass * refactored errors + added docs * merge err fixed * fixes on @ascjones review, all except moving away from `pub mod env` syntax * debug printing cleared * clippy fix
Resolves #11344