use vapabi;
use proc_macro2::TokenStream;
use super::{
input_names, template_param_type, rust_type, get_template_names, to_token, from_template_param,
to_vapabi_param_vec,
};
pub struct Constructor {
inputs_declarations: Vec<TokenStream>,
inputs_definitions: Vec<TokenStream>,
tokenize: Vec<TokenStream>,
recreate_inputs: TokenStream,
}
impl<'a> From<&'a vapabi::Constructor> for Constructor {
fn from(c: &'a vapabi::Constructor) -> Self {
let input_names = input_names(&c.inputs);
let inputs_declarations = c.inputs.iter().enumerate()
.map(|(index, param)| template_param_type(¶m.kind, index))
.collect();
let kinds: Vec<_> = c.inputs
.iter()
.map(|param| rust_type(¶m.kind))
.collect();
let template_names: Vec<_> = get_template_names(&kinds);
let inputs_definitions = input_names.iter().zip(template_names.iter())
.map(|(param_name, template_name)| quote! { #param_name: #template_name });
let inputs_definitions = Some(quote! { code: vapabi::Bytes }).into_iter()
.chain(inputs_definitions)
.collect();
let tokenize: Vec<_> = input_names.iter().zip(c.inputs.iter())
.map(|(param_name, param)| to_token(&from_template_param(¶m.kind, ¶m_name), ¶m.kind))
.collect();
Constructor {
inputs_declarations,
inputs_definitions,
tokenize,
recreate_inputs: to_vapabi_param_vec(&c.inputs),
}
}
}
impl Constructor {
pub fn generate(&self) -> TokenStream {
let declarations = &self.inputs_declarations;
let definitions = &self.inputs_definitions;
let tokenize = &self.tokenize;
let recreate_inputs = &self.recreate_inputs;
quote! {
pub fn constructor<#(#declarations),*>(#(#definitions),*) -> vapabi::Bytes {
let c = vapabi::Constructor {
inputs: #recreate_inputs,
};
let tokens = vec![#(#tokenize),*];
c.encode_input(code, &tokens).expect(INTERNAL_ERR)
}
}
}
}
#[cfg(test)]
mod tests {
use vapabi;
use super::Constructor;
#[test]
fn test_no_params() {
let vapabi_constructor = vapabi::Constructor {
inputs: vec![],
};
let c = Constructor::from(&vapabi_constructor);
let expected = quote! {
pub fn constructor<>(code: vapabi::Bytes) -> vapabi::Bytes {
let c = vapabi::Constructor {
inputs: vec![],
};
let tokens = vec![];
c.encode_input(code, &tokens).expect(INTERNAL_ERR)
}
};
assert_eq!(expected.to_string(), c.generate().to_string());
}
#[test]
fn test_one_param() {
let vapabi_constructor = vapabi::Constructor {
inputs: vec![
vapabi::Param {
name: "foo".into(),
kind: vapabi::ParamType::Uint(256),
}
],
};
let c = Constructor::from(&vapabi_constructor);
let expected = quote! {
pub fn constructor<T0: Into<vapabi::Uint> >(code: vapabi::Bytes, foo: T0) -> vapabi::Bytes {
let c = vapabi::Constructor {
inputs: vec![vapabi::Param {
name: "foo".to_owned(),
kind: vapabi::ParamType::Uint(256usize)
}],
};
let tokens = vec![vapabi::Token::Uint(foo.into())];
c.encode_input(code, &tokens).expect(INTERNAL_ERR)
}
};
assert_eq!(expected.to_string(), c.generate().to_string());
}
}