use crate::case::RenameRule;
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use serde_json::Value;
use syn::ext::IdentExt;
pub fn to_compile_errors(errors: impl AsRef<[syn::Error]>) -> TokenStream {
let compile_errors = errors.as_ref().iter().map(syn::Error::to_compile_error);
quote!(#(#compile_errors)*)
}
pub fn preserve_optional(op: Option<impl quote::ToTokens>) -> TokenStream {
if let Some(tt) = op {
quote! {::std::option::Option::Some(#tt.into())}
} else {
quote! {::std::option::Option::None}
}
}
pub fn aliases(op: &[impl AsRef<str>]) -> TokenStream {
let items: Vec<TokenStream> = op
.iter()
.map(|alias| {
let alias = alias.as_ref();
quote! {
::apache_avro::schema::Alias::new(#alias).expect("Alias is invalid")
}
})
.collect();
if items.is_empty() {
quote! {::std::option::Option::None}
} else {
quote! {::std::option::Option::Some(vec![#(#items),*])}
}
}
pub fn field_aliases(op: &[impl AsRef<str>]) -> TokenStream {
let items: Vec<TokenStream> = op
.iter()
.map(|string| {
let string = string.as_ref();
quote! {
::std::string::String::from(#string)
}
})
.collect();
quote! {vec![#(#items),*]}
}
pub fn json_value_expr(value: Value) -> TokenStream {
match value {
Value::Null => quote! {
::serde_json::Value::Null
},
Value::Bool(bool) => quote! {
::serde_json::Value::Bool(#bool)
},
Value::Number(number) => {
if let Some(n) = number.as_u64() {
quote! {
::serde_json::Value::Number(::serde_json::Number::from(#n))
}
} else if let Some(n) = number.as_i64() {
quote! {
::serde_json::Value::Number(::serde_json::Number::from(#n))
}
} else if let Some(n) = number.as_f64() {
quote! {
::serde_json::Value::Number(::serde_json::Number::from_f64(#n).expect("Unreachable, f64 is finite"))
}
} else {
let s = number.to_string();
quote! {
::serde_json::Value::Number(#s.parse().expect(concat!("This was a valid number at compile time: ", #s)))
}
}
}
Value::String(string) => quote! {
::serde_json::Value::String(::std::string::String::from(#string))
},
Value::Array(array) => {
let array = array.into_iter().map(json_value_expr);
quote! {
::serde_json::Value::Array(vec![#(#array),*])
}
}
Value::Object(object) => {
let len = object.len();
let mut keys = Vec::with_capacity(len);
let mut values = Vec::with_capacity(len);
for (key, value) in object {
keys.push(key);
values.push(json_value_expr(value));
}
quote! {
::serde_json::Value::Object({
let mut map = ::serde_json::Map::with_capacity(#len);
#(map.insert(::std::string::String::from(#keys), #values);)*
map
})
}
}
}
}
pub fn name_expr(name: &str) -> TokenStream {
quote! {
::apache_avro::schema::Name::new_with_enclosing_namespace(#name, enclosing_namespace).expect(concat!("Unable to parse `", #name, "` as a Name"))
}
}
pub fn rename_ident(
ident: &Ident,
rename: Option<String>,
rename_all: RenameRule,
func: fn(RenameRule, &str) -> String,
) -> String {
match (rename, rename_all) {
(Some(rename), _) => rename,
(None, rename_all) if !matches!(rename_all, RenameRule::None) => {
func(rename_all, &ident.unraw().to_string())
}
_ => ident.unraw().to_string(),
}
}