use std::collections::BTreeSet;
use std::ops::Deref;
use crate::{collect_type_params, is_phantom_data, Mode};
use crate::{attrs::CustomCodec, fields::Fields};
pub(crate) struct Blacklist(BTreeSet<syn::Ident>);
impl Blacklist {
pub(crate) fn empty() -> Self {
Self(BTreeSet::new())
}
pub(crate) fn full(mode: Mode, fields: &Fields, g: &syn::Generics) -> Self {
Self::empty()
.with_mode(mode, fields, g)
.with_skipped(fields, g)
.with_phantoms(fields, g)
}
pub(crate) fn with_mode(mut self, mode: Mode, fields: &Fields, g: &syn::Generics) -> Self {
let mut blacklist = collect_type_params(g, fields.fields().filter(|f| {
match mode {
Mode::Encode => f.attrs.codec().map(|c| !c.require_encode_bound()).unwrap_or(false),
Mode::Decode => f.attrs.codec().map(|c| !c.require_decode_bound()).unwrap_or(false),
Mode::Length => f.attrs.cbor_len().is_some()
|| f.attrs.codec()
.map(|c| matches!(c, CustomCodec::Module(..)))
.unwrap_or(false)
}
}));
if !blacklist.is_empty() {
let others = collect_type_params(g, fields.fields().filter(|f| {
match mode {
Mode::Encode => f.attrs.codec().map(|c| c.require_encode_bound()).unwrap_or(true),
Mode::Decode => f.attrs.codec().map(|c| c.require_decode_bound()).unwrap_or(true),
Mode::Length => f.attrs.cbor_len().is_none()
&& f.attrs.codec()
.map(|c| !matches!(c, CustomCodec::Module(..)))
.unwrap_or(true)
}
}));
blacklist.retain(|ident| !others.contains(ident));
}
self.0.extend(blacklist);
self
}
pub(crate) fn with_skipped(mut self, fields: &Fields, g: &syn::Generics) -> Self {
let skipped = collect_type_params(g, fields.skipped());
if !skipped.is_empty() {
let regular = collect_type_params(g, fields.fields());
self.0.extend(skipped.difference(®ular).cloned())
}
self
}
pub(crate) fn with_phantoms(mut self, fields: &Fields, g: &syn::Generics) -> Self {
let phantoms = collect_type_params(g, fields.fields().chain(fields.skipped()).filter(|f| {
is_phantom_data(&f.typ)
}));
if !phantoms.is_empty() {
let non_phantom = collect_type_params(g, fields.fields().chain(fields.skipped()).filter(|f| {
!is_phantom_data(&f.typ)
}));
self.0.extend(phantoms.difference(&non_phantom).cloned());
}
self
}
pub(crate) fn merge(&mut self, f: &Fields, g: &syn::Generics, b: Blacklist) -> &mut Self {
for t in collect_type_params(g, f.fields().chain(f.skipped())).difference(&b) {
self.0.remove(t);
}
for t in b.0 {
self.0.insert(t);
}
self
}
pub(crate) fn add<I>(&mut self, it: I)
where
I: IntoIterator<Item = syn::Ident>
{
for id in it.into_iter() {
self.0.insert(id);
}
}
}
impl From<Blacklist> for BTreeSet<syn::Ident> {
fn from(b: Blacklist) -> Self {
b.0
}
}
impl Deref for Blacklist {
type Target = BTreeSet<syn::Ident>;
fn deref(&self) -> &Self::Target {
&self.0
}
}