use super::ExpCtxt;
use ast::{ItemFunction, ParameterList, Spanned, Type, VariableDeclaration, VariableDefinition};
use proc_macro2::TokenStream;
use syn::{Error, Result};
pub(super) fn expand(cx: &ExpCtxt<'_>, var_def: &VariableDefinition) -> Result<TokenStream> {
if !var_def.attributes.visibility().map_or(false, |v| v.is_public() || v.is_external()) {
return Ok(TokenStream::new());
}
let mut function = ItemFunction::from_variable_definition(var_def.clone());
expand_returns(cx, &mut function)?;
super::function::expand(cx, &function)
}
fn expand_returns(cx: &ExpCtxt<'_>, f: &mut ItemFunction) -> Result<()> {
let returns = f.returns.as_mut().expect("generated getter function with no returns");
let ret = returns.returns.first_mut().unwrap();
if !ret.ty.has_custom_simple() {
return Ok(());
}
let mut ty = &ret.ty;
if let Type::Custom(name) = ty {
ty = cx.custom_type(name);
}
let Type::Tuple(tup) = ty else { return Ok(()) };
if !tup.types.iter().any(type_is_complex) {
return Ok(());
}
let mut new_returns = ParameterList::new();
for p in tup.types.pairs() {
let (ty, comma) = p.into_tuple();
if !type_is_complex(ty) {
new_returns.push_value(VariableDeclaration::new(ty.clone()));
if let Some(comma) = comma {
new_returns.push_punct(*comma);
}
}
}
if new_returns.is_empty() {
return Err(Error::new(f.name().span(), "invalid state variable type"));
}
returns.returns = new_returns;
Ok(())
}
fn type_is_complex(ty: &Type) -> bool {
matches!(ty, Type::Mapping(_) | Type::Array(_))
}