ferment-sys 0.2.14

Syntax tree morphing of FFI-compatible stuff
Documentation
use proc_macro2::Ident;
use quote::ToTokens;
use syn::{parse_quote, ImplItemFn, Item, Path, PathSegment, Signature, TraitItemFn, Type, TypePath};
use syn::punctuated::Punctuated;
use crate::ast::Colon2Punctuated;
use crate::composable::TypeModel;
use crate::context::{Scope, ScopeChain, ScopeContext, ScopeInfo};
use crate::kind::{ObjectKind, ScopeItemKind};
use crate::ext::{GenericBoundKey, MaybeAttrs, ToType};

pub trait Join<T: ToTokens> {
    fn joined(&self, other: &T) -> Self;
}
#[macro_export]
macro_rules! impl_parseable_join {
    ($SelfTy:ty, $JoinTy:ty) => {
        impl Join<$JoinTy> for $SelfTy {
            fn joined(&self, other: &$JoinTy) -> Self {
                parse_quote!(#self::#other)
            }
        }
    };
}
impl_parseable_join!(Path, Path);
impl_parseable_join!(Path, Type);
impl_parseable_join!(Type, Path);
impl_parseable_join!(Type, Colon2Punctuated<PathSegment>);
impl_parseable_join!(Path, Colon2Punctuated<PathSegment>);
impl_parseable_join!(Colon2Punctuated<PathSegment>, Colon2Punctuated<PathSegment>);
impl_parseable_join!(Colon2Punctuated<PathSegment>, Ident);
impl_parseable_join!(Colon2Punctuated<PathSegment>, Path);
impl_parseable_join!(TypePath, Colon2Punctuated<PathSegment>);
impl_parseable_join!(TypePath, Ident);

impl Join<Item> for ScopeChain {
    fn joined(&self, item: &Item) -> Self {
        let attrs = item.maybe_attrs().cloned().unwrap_or_default();
        let self_scope = self.self_scope_ref().joined(item);
        match item {
            Item::Const(..) |
            Item::Type(..) |
            Item::Enum(..) |
            Item::Struct(..) =>
                ScopeChain::object(ScopeInfo::new(attrs, self.crate_ident(), self_scope), self.clone()),
            Item::Trait(..) =>
                ScopeChain::r#trait(ScopeInfo::new(attrs, self.crate_ident(), self_scope), self.clone()),
            Item::Fn(..) =>
                ScopeChain::r#fn(ScopeInfo::new(attrs, self.crate_ident(), self_scope), self.clone()),
            Item::Impl(..) =>
                ScopeChain::r#impl(ScopeInfo::new(attrs, self.crate_ident(), self_scope), self.clone()),
            Item::Mod(..) =>
                ScopeChain::r#mod(ScopeInfo::new(attrs, self.crate_ident(), self_scope), self.clone()),
            _ => self.clone()
        }
    }
}
impl Join<ImplItemFn> for ScopeChain {
    fn joined(&self, item: &ImplItemFn) -> Self {
        let ImplItemFn { attrs, sig, .. } = item;
        let Signature { ident, generics, .. } = sig;
        let self_path = self.self_path_ref();
        let fn_self_scope = self_path.joined(ident);
        let self_type = fn_self_scope.to_type();
        ScopeChain::func(
            Scope::new(fn_self_scope, ObjectKind::new_fn_item(TypeModel::new_generic_non_nested(self_type, generics), ScopeItemKind::fn_ref(sig, self_path))),
            attrs,
            self.crate_ident_ref(),
            self
        )
    }
}
impl Join<TraitItemFn> for ScopeChain {
    fn joined(&self, item: &TraitItemFn) -> Self {
        let TraitItemFn { attrs, sig, .. } = item;
        let Signature { ident, generics, .. } = sig;
        let self_path = self.self_path_ref();
        let fn_self_scope = self_path.joined(ident);
        let self_type = fn_self_scope.to_type();
        ScopeChain::func(
            Scope::new(fn_self_scope, ObjectKind::new_fn_item(TypeModel::new_generic_non_nested(self_type, generics), ScopeItemKind::fn_ref(sig, self_path))),
            attrs,
            self.crate_ident_ref(),
            self
        )
    }
}

impl Join<ImplItemFn> for ScopeContext {
    fn joined(&self, other: &ImplItemFn) -> Self {
        Self::with(self.scope.joined(other), self.context.clone())
    }
}

impl Join<TraitItemFn> for ScopeContext {
    fn joined(&self, other: &TraitItemFn) -> Self {
        Self::with(self.scope.joined(other), self.context.clone())
    }
}

impl Join<Ident> for Path {
    fn joined(&self, other: &Ident) -> Self {
        let mut new_path = self.clone();
        new_path.segments.push(PathSegment::from(other.clone()));
        new_path
    }
}

impl Join<GenericBoundKey> for Path {
    fn joined(&self, other: &GenericBoundKey) -> Self {
        match other {
            GenericBoundKey::Ident(ident) => self.joined(ident),
            GenericBoundKey::Path(path) => self.joined(path)
        }
    }
}


pub trait PunctuateOne<T: Default> {
    fn punctuate_one(self) -> Punctuated<Self, T> where Self: Sized {
        Punctuated::from_iter([self])
    }
}

impl<T, P: ToTokens + Default> PunctuateOne<P> for T {}