mwapi_responses_derive/
params.rsuse crate::metadata::{default_query_fields, FieldContainer, Metadata};
use crate::Result;
use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, ToTokens};
use std::collections::HashMap;
use syn::{Error, LitStr};
pub(crate) enum ParsedParams {
List(LitStr, HashMap<String, String>),
Props(Vec<LitStr>, HashMap<String, String>),
None(HashMap<String, String>),
}
impl ParsedParams {
pub fn new(mut input: HashMap<String, LitStr>) -> Result<Self> {
let mut params = HashMap::new();
if let Some(val) = input.remove("action") {
if val.value() != "query" {
return Err(Error::new(
val.span(),
"only action=query is supported",
));
}
}
let list = input.remove("list");
let prop = input.remove("prop");
for (key, value) in input.into_iter() {
params.insert(key, value.value());
}
set_defaults(&mut params);
let res = match (list, prop) {
(None, None) => ParsedParams::None(params),
(Some(list), Some(_)) => {
return Err(Error::new(
list.span(),
"only one of list= or prop= can be specified, not both",
));
}
(Some(listname), None) => {
params.insert("list".to_string(), listname.value());
ParsedParams::List(listname, params)
}
(None, Some(prop)) => {
params.insert("prop".to_string(), prop.value());
let props: Vec<_> = prop
.value()
.split('|')
.map(|p| LitStr::new(p, prop.span()))
.collect();
ParsedParams::Props(props, params)
}
};
Ok(res)
}
pub(crate) fn get_fieldname(&self) -> Result<String> {
let res = match self {
ParsedParams::List(listname, _) => {
Metadata::new(listname)?.fieldname
}
ParsedParams::Props(_, _) | ParsedParams::None(_) => {
"pages".to_string()
}
};
Ok(res)
}
fn get_params(&self) -> &HashMap<String, String> {
match self {
ParsedParams::List(_, params) => params,
ParsedParams::Props(_, params) => params,
ParsedParams::None(params) => params,
}
}
fn get_fields_for(
&self,
module: &LitStr,
container: &mut FieldContainer,
) -> Result<()> {
let info = Metadata::new(module)?;
let props: Vec<&str> = match &info.prop {
Some(prop) => {
match self.get_params().get(prop) {
Some(value) => value.split('|').collect(),
None => {
vec![]
}
}
}
None => vec![],
};
let wrap_field = if info.wrap_in_vec {
Some(info.fieldname.to_string())
} else {
None
};
container.add_fields(wrap_field, info.get_fields(&props));
Ok(())
}
pub(crate) fn get_fields(&self) -> Result<FieldContainer> {
let mut container = FieldContainer::default();
match self {
ParsedParams::List(listname, _) => {
self.get_fields_for(listname, &mut container)?;
}
ParsedParams::Props(props, _) => {
container.top.extend(default_query_fields());
for prop in props {
self.get_fields_for(prop, &mut container)?;
}
}
ParsedParams::None(_) => {
container.top.extend(default_query_fields());
}
}
Ok(container)
}
}
impl ToTokens for ParsedParams {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let params = self.get_params();
let keys = params.keys();
let values = params.values();
let stream = quote! {
&[
#((#keys, #values),)*
]
};
stream.to_tokens(tokens);
}
}
fn set_defaults(params: &mut HashMap<String, String>) {
params.insert("action".to_string(), "query".to_string());
params.insert("format".to_string(), "json".to_string());
params.insert("formatversion".to_string(), "2".to_string());
}