ferment-sys 0.2.14

Syntax tree morphing of FFI-compatible stuff
Documentation
use syn::{Attribute, parse_quote, Type, TypeSlice, ItemFn, Signature, TypePath};
use std::fmt::{Debug, Display};
use proc_macro2::Ident;
use crate::composable::FnSignatureContext;
use crate::composer::{AspectArgComposers, AttrComposable, ComposerLinkRef, FieldsContext, GenericsComposable, LifetimesComposable, NameKindComposable, TypeAspect};
use crate::context::ScopeContext;
use crate::kind::{GenericTypeKind, MixinKind};
use crate::ext::{Accessory, Join, LifetimeProcessor, Mangle, Resolve, ResolveTrait, ToType};
use crate::lang::Specification;
use crate::presentable::{TypeContext, ScopeContextPresentable, NameTreeContext};

#[derive(Clone, Debug)]
pub enum Aspect<T> {
    Target(T),
    Ffi(T),
    RawTarget(T),
}

impl<T> Aspect<T> where T: NameTreeContext {
    pub fn ffi<SPEC, C>(by_ref: &ComposerLinkRef<C>) -> AspectArgComposers<SPEC>
    where C: AttrComposable<SPEC::Attr> + LifetimesComposable<SPEC::Lt> + GenericsComposable<SPEC::Gen> + TypeAspect<SPEC::TYC> + FieldsContext<SPEC> + NameKindComposable,
          SPEC: Specification<TYC=T> {
        ((Aspect::Ffi(C::type_context(by_ref)), (C::compose_attributes(by_ref), C::compose_lifetimes(by_ref), C::compose_generics(by_ref)), C::compose_name_kind(by_ref)), C::field_composers(by_ref))
    }
    pub fn target<SPEC, C>(by_ref: &ComposerLinkRef<C>) -> AspectArgComposers<SPEC>
    where C: AttrComposable<SPEC::Attr> + LifetimesComposable<SPEC::Lt> + GenericsComposable<SPEC::Gen> + TypeAspect<SPEC::TYC> + FieldsContext<SPEC> + NameKindComposable,
          SPEC: Specification<TYC=T> {
        ((Aspect::Target(C::type_context(by_ref)), (C::compose_attributes(by_ref), C::compose_lifetimes(by_ref), C::compose_generics(by_ref)), C::compose_name_kind(by_ref)), C::field_composers(by_ref))
    }
}

impl Aspect<TypeContext> {
    pub fn attrs(&self) -> &Vec<Attribute> {
        match self {
            Aspect::Target(context) => context.attrs(),
            Aspect::Ffi(context) => context.attrs(),
            Aspect::RawTarget(context) => context.attrs(),
        }
    }
    pub fn raw_struct_ident(ident: Ident) -> Self {
        Aspect::RawTarget(TypeContext::struct_ident(ident))
    }
}

impl<T> Display for Aspect<T> where T: ToString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(match self {
            Self::Target(context) => format!("Target({})", context.to_string()),
            Self::Ffi(context) => format!("FFI({})", context.to_string()),
            Self::RawTarget(context) => format!("RawTarget({})", context.to_string()),
        }.as_str())
    }
}

impl ScopeContextPresentable for Aspect<TypeContext> {
    type Presentation = Type;

    fn present(&self, source: &ScopeContext) -> Self::Presentation {
        match self {
            Aspect::Target(TypeContext::Fn { path, .. }) |
            Aspect::Ffi(TypeContext::Fn { path, sig_context: FnSignatureContext::Impl(..), .. }) |
            Aspect::RawTarget(TypeContext::Fn { path, .. } |
                              TypeContext::Trait { path, .. }) =>
                path.to_type(),
            Aspect::Target(TypeContext::Enum { ident, .. } |
                           TypeContext::Struct { ident, .. }) |
            Aspect::RawTarget(TypeContext::Enum { ident, .. } |
                              TypeContext::Struct { ident, .. }) =>
                Resolve::<Type>::resolve(ident, source),
            Aspect::Target(TypeContext::EnumVariant { ident, variant_ident, .. }) =>
                Resolve::<Type>::resolve(ident, source)
                    .lifetimes_cleaned()
                    .joined_ident(variant_ident),
            Aspect::Target(TypeContext::Trait { path, .. } | TypeContext::Impl { path, .. }) |
            Aspect::RawTarget(TypeContext::Impl { trait_: Some(path), .. } | TypeContext::Impl { path, .. }) =>
                path.to_type()
                    .resolve(source),
            Aspect::Target(TypeContext::Mixin { mixin_kind: MixinKind::Generic(GenericTypeKind::Slice(Type::Slice(TypeSlice { elem, ..}))), .. }) =>
                parse_quote!(Vec<#elem>),
            Aspect::Target(TypeContext::Mixin { mixin_kind: MixinKind::Generic(kind), .. }) |
            Aspect::RawTarget(TypeContext::Mixin { mixin_kind: MixinKind::Generic(kind), .. }) =>
                kind.ty()
                    .cloned()
                    .unwrap(),
            Aspect::Target(TypeContext::Mixin { mixin_kind: MixinKind::Bounds(model), .. }) |
            Aspect::RawTarget(TypeContext::Mixin { mixin_kind: MixinKind::Bounds(model), .. }) =>
                model.to_type(),
            Aspect::Ffi(TypeContext::Mixin { mixin_kind: MixinKind::Generic(kind), .. }) =>
                kind.ty()
                    .cloned()
                    .unwrap()
                    .mangle_ident_default()
                    .to_type(),
            Aspect::Ffi(TypeContext::Mixin { mixin_kind: MixinKind::Bounds(model), .. }) =>
                model.mangle_ident_default()
                    .to_type(),
            Aspect::Ffi(TypeContext::Enum { ident , .. } |
                        TypeContext::Struct { ident , .. } |
                        TypeContext::Fn { sig_context:
                            FnSignatureContext::ModFn(ItemFn { sig: Signature { ident, .. }, .. }) |
                            FnSignatureContext::Bare(ident, _), .. }) =>
                Resolve::<Type>::resolve(ident, source)
                    .mangle_ident_default()
                    .to_type(),
            Aspect::Ffi(TypeContext::Trait { path , .. } |
                        TypeContext::Impl { path , .. }) =>
                Resolve::<Type>::resolve(path, source)
                    .mangle_ident_default()
                    .to_type(),
            Aspect::Ffi(TypeContext::EnumVariant { ident, variant_ident, .. }) =>
                Resolve::<Type>::resolve(ident, source)
                    .mangle_ident_default()
                    .to_type()
                    .joined_ident(variant_ident),
            Aspect::Ffi(TypeContext::Fn { sig_context: FnSignatureContext::TraitInner(_, self_ty, _), .. }) =>
                Resolve::<Type>::resolve(self_ty, source)
                    .mangle_ident_default()
                    .to_type(),
            Aspect::Ffi(TypeContext::Fn { path, sig_context: FnSignatureContext::TraitImpl(_, self_ty, trait_ty) | FnSignatureContext::TraitAsType(_, self_ty, trait_ty), .. }) =>
                Resolve::<Type>::resolve(trait_ty, source)
                    .maybe_trait_ty(source)
                    .map(|full_trait_ty| {
                        let self_ty = Resolve::<Type>::resolve(self_ty, source);
                        let type_path: TypePath = parse_quote!(<#self_ty as #full_trait_ty>);
                        Type::Path(type_path.joined(&path.segments.last().expect("Expect ident").ident))
                    }).unwrap_or_else(|| path.to_type()),
            Aspect::RawTarget(TypeContext::EnumVariant { ident, variant_ident, .. }) =>
                Resolve::<Type>::resolve(ident, source)
                    .joined_ident(variant_ident),
        }
    }
}