use crate::CratePath;
use syn::{parse_quote, Path};
use std::collections::{HashMap, HashSet};
#[derive(Debug, Clone)]
pub struct DerivesRegistry {
default_derives: Derives,
specific_type_derives: HashMap<syn::TypePath, Derives>,
}
impl Default for DerivesRegistry {
fn default() -> Self {
Self::new()
}
}
impl DerivesRegistry {
pub fn new() -> Self {
Self {
default_derives: Derives::new(),
specific_type_derives: Default::default(),
}
}
pub fn with_default_derives(crate_path: &CratePath) -> Self {
Self {
default_derives: Derives::with_defaults(crate_path),
specific_type_derives: Default::default(),
}
}
pub fn extend_for_all(
&mut self,
derives: impl IntoIterator<Item = syn::Path>,
attributes: impl IntoIterator<Item = syn::Attribute>,
) {
self.default_derives.derives.extend(derives);
self.default_derives.attributes.extend(attributes);
}
pub fn extend_for_type(
&mut self,
ty: syn::TypePath,
derives: impl IntoIterator<Item = syn::Path>,
attributes: impl IntoIterator<Item = syn::Attribute>,
) {
let type_derives = self.specific_type_derives.entry(ty).or_default();
type_derives.derives.extend(derives);
type_derives.attributes.extend(attributes);
}
pub fn default_derives(&self) -> &Derives {
&self.default_derives
}
pub fn resolve(&self, ty: &syn::TypePath) -> Derives {
let mut resolved_derives = self.default_derives.clone();
if let Some(specific) = self.specific_type_derives.get(ty) {
resolved_derives.extend_from(specific.clone());
}
resolved_derives
}
}
#[derive(Debug, Clone)]
pub struct Derives {
derives: HashSet<syn::Path>,
attributes: HashSet<syn::Attribute>,
}
impl Default for Derives {
fn default() -> Self {
Self::new()
}
}
impl FromIterator<syn::Path> for Derives {
fn from_iter<T: IntoIterator<Item = Path>>(iter: T) -> Self {
let derives = iter.into_iter().collect();
Self {
derives,
attributes: HashSet::new(),
}
}
}
impl Derives {
pub fn new() -> Self {
Self {
derives: HashSet::new(),
attributes: HashSet::new(),
}
}
pub fn with_defaults(crate_path: &CratePath) -> Self {
let mut derives = HashSet::new();
let mut attributes = HashSet::new();
derives.insert(syn::parse_quote!(#crate_path::ext::scale_encode::EncodeAsType));
let encode_crate_path = quote::quote! { #crate_path::ext::scale_encode }.to_string();
attributes.insert(syn::parse_quote!(#[encode_as_type(crate_path = #encode_crate_path)]));
derives.insert(syn::parse_quote!(#crate_path::ext::scale_decode::DecodeAsType));
let decode_crate_path = quote::quote! { #crate_path::ext::scale_decode }.to_string();
attributes.insert(syn::parse_quote!(#[decode_as_type(crate_path = #decode_crate_path)]));
derives.insert(syn::parse_quote!(#crate_path::ext::codec::Encode));
derives.insert(syn::parse_quote!(#crate_path::ext::codec::Decode));
attributes.insert(syn::parse_quote!(#[codec(crate = #crate_path::ext::codec)]));
derives.insert(syn::parse_quote!(Debug));
Self {
derives,
attributes,
}
}
pub fn extend_from(&mut self, other: Derives) {
self.derives.extend(other.derives);
self.attributes.extend(other.attributes);
}
pub fn insert_codec_compact_as(&mut self, crate_path: &CratePath) {
self.insert_derive(parse_quote!(#crate_path::ext::codec::CompactAs));
}
pub fn extend(&mut self, derives: impl Iterator<Item = syn::Path>) {
for derive in derives {
self.insert_derive(derive)
}
}
pub fn insert_derive(&mut self, derive: syn::Path) {
self.derives.insert(derive);
}
pub fn insert_attribute(&mut self, attribute: syn::Attribute) {
self.attributes.insert(attribute);
}
}
impl quote::ToTokens for Derives {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
if !self.derives.is_empty() {
let mut sorted = self.derives.iter().cloned().collect::<Vec<_>>();
sorted.sort_by(|a, b| {
quote::quote!(#a)
.to_string()
.cmp("e::quote!(#b).to_string())
});
tokens.extend(quote::quote! {
#[derive(#( #sorted ),*)]
})
}
if !self.attributes.is_empty() {
let mut sorted = self.attributes.iter().cloned().collect::<Vec<_>>();
sorted.sort_by(|a, b| {
quote::quote!(#a)
.to_string()
.cmp("e::quote!(#b).to_string())
});
tokens.extend(quote::quote! {
#( #sorted )*
})
}
}
}