ferment-sys 0.2.14

Syntax tree morphing of FFI-compatible stuff
Documentation
use std::fmt::{Debug, Display, Formatter};
use std::hash::{Hash, Hasher};
use proc_macro2::Ident;
use quote::ToTokens;
use syn::__private::TokenStream2;
use syn::{Attribute, Generics, parse_quote, Path, Type, PathSegment};
use crate::composable::CfgAttributes;
use crate::context::{GenericChain, Scope, ScopeInfo};
use crate::kind::{ObjectKind, TypeModel};
use crate::ext::{CRATE, ResolveAttrs, ToPath, ToType, Join, GenericBoundKey, CrateBased};
use crate::formatter::{format_attrs, format_token_stream};


#[derive(Clone, Eq)]
#[repr(u8)]
pub enum ScopeChain {
    CrateRoot {
        info: ScopeInfo,
    },
    Mod {
        info: ScopeInfo,
        parent: Box<ScopeChain>,
    },
    Trait {
        info: ScopeInfo,
        parent: Box<ScopeChain>,
    },
    Fn {
        info: ScopeInfo,
        parent: Box<ScopeChain>,
    },
    Object {
        info: ScopeInfo,
        parent: Box<ScopeChain>,
    },
    Impl {
        info: ScopeInfo,
        parent: Box<ScopeChain>,
    },
}

impl ScopeChain {
    pub fn root(info: ScopeInfo) -> Self {
        Self::CrateRoot { info }
    }
    pub fn root_with(attrs: Vec<Attribute>, crate_ident: Ident, self_scope: Scope) -> Self {
        Self::CrateRoot { info: ScopeInfo::new(attrs, crate_ident, self_scope) }
    }
    pub fn object(info: ScopeInfo, parent: ScopeChain) -> Self {
        Self::Object { info, parent: parent.into() }
    }
    pub fn r#trait(info: ScopeInfo, parent: ScopeChain) -> Self {
        Self::Trait { info, parent: parent.into() }
    }
    pub fn r#impl(info: ScopeInfo, parent: ScopeChain) -> Self {
        Self::Impl { info, parent: parent.into() }
    }
    pub fn r#mod(info: ScopeInfo, parent: ScopeChain) -> Self {
        Self::Mod { info, parent: parent.into() }
    }
    pub fn r#fn(info: ScopeInfo, parent: ScopeChain) -> Self {
        Self::Fn { info, parent: parent.into() }
    }
    pub fn func(self_scope: Scope, attrs: &[Attribute], crate_ident: &Ident, parent: &ScopeChain) -> Self {
        Self::r#fn(ScopeInfo::new(attrs.to_owned(), crate_ident.clone(), self_scope), parent.clone())
    }

    pub fn obj_scope_priority(&self) -> u8 {
        match self {
            ScopeChain::CrateRoot { .. } => 0,
            ScopeChain::Mod { .. } => 1,
            ScopeChain::Trait { .. } => 4,
            ScopeChain::Fn { .. } => 3,
            ScopeChain::Object { .. } => 5,
            ScopeChain::Impl { .. } => 2,
        }
    }
}

impl PartialEq<Self> for ScopeChain {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (ScopeChain::Impl { info: ScopeInfo { crate_ident, self_scope, .. }, .. },
                ScopeChain::Impl { info: ScopeInfo { crate_ident: other_crate_ident, self_scope: other_self_scope, .. }, .. }) |
            (ScopeChain::CrateRoot { info: ScopeInfo { crate_ident, self_scope, .. }, .. },
                ScopeChain::CrateRoot { info: ScopeInfo { crate_ident: other_crate_ident, self_scope: other_self_scope, .. }, .. }) |
            (ScopeChain::Mod { info: ScopeInfo { crate_ident, self_scope, .. }, .. },
                ScopeChain::Mod { info: ScopeInfo { crate_ident: other_crate_ident, self_scope: other_self_scope, .. }, .. }) |
            (ScopeChain::Trait { info: ScopeInfo { crate_ident, self_scope, .. }, .. },
                ScopeChain::Trait { info: ScopeInfo { crate_ident: other_crate_ident, self_scope: other_self_scope, .. }, .. }) |
            (ScopeChain::Fn { info: ScopeInfo { crate_ident, self_scope, .. }, .. },
                ScopeChain::Fn { info: ScopeInfo { crate_ident: other_crate_ident, self_scope: other_self_scope, .. }, .. }) |
            (ScopeChain::Object { info: ScopeInfo { crate_ident, self_scope, .. }, .. },
                ScopeChain::Object { info: ScopeInfo { crate_ident: other_crate_ident, self_scope: other_self_scope, .. }, .. }) =>
                self_scope.eq(other_self_scope) && crate_ident.eq(other_crate_ident),
            _ => false
        }
    }
}
impl Hash for ScopeChain {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.variant_code().hash(state);
        self.self_scope_ref().hash(state);
    }
}

impl Debug for ScopeChain {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.fmt_long().as_str())
    }
}
impl Display for ScopeChain {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        Debug::fmt(self, f)
    }
}

impl ScopeChain {
    pub fn variant_code(&self) -> u8 {
        match self {
            ScopeChain::CrateRoot { .. } => 0,
            ScopeChain::Mod { .. } => 1,
            ScopeChain::Fn { .. } => 2,
            ScopeChain::Object { .. } => 3,
            ScopeChain::Impl { .. } => 4,
            ScopeChain::Trait { .. } => 5
        }
    }
    pub fn info(&self) -> &ScopeInfo {
        match self {
            ScopeChain::CrateRoot { info, .. } |
            ScopeChain::Mod { info, .. } |
            ScopeChain::Fn { info, .. } |
            ScopeChain::Object { info, .. } |
            ScopeChain::Impl { info, .. } |
            ScopeChain::Trait { info, .. } => info
        }
    }

    #[allow(unused)]
    pub fn fmt_short(&self) -> String {
        match self {
            ScopeChain::CrateRoot { info, .. } => format!("[{}({} + {})]", format_token_stream(info.self_path()), "CrateRoot", info.fmt_export_type()),
            ScopeChain::Mod { info, .. } => format!("[{}({} + {})]", format_token_stream(info.self_path()), "Mod", info.fmt_export_type()),
            ScopeChain::Fn { info, .. } => format!("[{}({} + {})]", format_token_stream(info.self_path()), "Fn", info.fmt_export_type()),
            ScopeChain::Object { info, .. } => format!("[{}({} + {})]", format_token_stream(info.self_path()), "Object", info.fmt_export_type()),
            ScopeChain::Impl { info, .. } => format!("[{}({} + {})]", format_token_stream(info.self_path()), "Impl", info.fmt_export_type()),
            ScopeChain::Trait { info, .. } => format!("[{}({} + {})]", format_token_stream(info.self_path()), "Trait", info.fmt_export_type()),
        }
    }
    #[allow(unused)]
    pub fn fmt_mid(&self) -> String {
        match self {
            ScopeChain::CrateRoot { info, .. } => format!("[{}({} + {} + {})]", format_token_stream(info.self_path()), "CrateRoot", info.fmt_export_type(), info.self_scope.object),
            ScopeChain::Mod { info, .. } => format!("[{}({} + {} + {})]", format_token_stream(info.self_path()), "Mod", info.fmt_export_type(), info.self_scope.object),
            ScopeChain::Fn { info, .. } => format!("[{}({} + {} + {})]", format_token_stream(info.self_path()), "Fn", info.fmt_export_type(), info.self_scope.object),
            ScopeChain::Object { info, .. } => format!("[{}({} + {} + {})]", format_token_stream(info.self_path()), "Object", info.fmt_export_type(), info.self_scope.object),
            ScopeChain::Impl { info, .. } => format!("[{}({} + {} + {})]", format_token_stream(info.self_path()), "Impl", info.fmt_export_type(), info.self_scope.object),
            ScopeChain::Trait { info, .. } => format!("[{}({} + {} + {})]", format_token_stream(info.self_path()), "Trait", info.fmt_export_type(), info.self_scope.object),
        }
    }
    #[allow(unused)]
    pub fn fmt_long(&self) -> String {
        match self {
            ScopeChain::CrateRoot { info } =>
                format!("[{}] :: {} + {} (CrateRoot)", format_attrs(&info.attrs), info.crate_ident, info.self_scope),
            ScopeChain::Mod { info, parent } =>
                format!("[{}] :: {} + {} (Mod) (parent: {:?})", format_attrs(&info.attrs), info.crate_ident, info.self_scope, parent),
            ScopeChain::Trait { info, parent } =>
                format!("[{}] :: {} + {} (Trait) (parent: {:?})", format_attrs(&info.attrs), info.crate_ident, info.self_scope, parent),
            ScopeChain::Fn { info, parent } =>
                format!("[{}] :: {} + {} (Fn) (parent: {:?})", format_attrs(&info.attrs), info.crate_ident, info.self_scope, parent),
            ScopeChain::Object { info, parent } =>
                format!("[{}] :: {} + {} (Object) (parent: {:?})", format_attrs(&info.attrs), info.crate_ident, info.self_scope, parent),
            ScopeChain::Impl { info, parent } =>
                format!("[{}] :: {} + {} (Impl) (parent: {:?})", format_attrs(&info.attrs), info.crate_ident, info.self_scope, parent),
        }
    }
}

impl ToTokens for ScopeChain {
    fn to_tokens(&self, tokens: &mut TokenStream2) {
        self.self_path_ref()
            .to_tokens(tokens)
    }
}

impl ToType for ScopeChain {
    fn to_type(&self) -> Type {
        self.self_path_ref().to_type()
    }
}

impl ScopeChain {

    fn crate_root_with(attrs: Vec<Attribute>, crate_ident: Ident, path: Path) -> Self {
        Self::root_with(attrs, crate_ident, Scope::empty(path))
    }
    fn new_mod(crate_ident: Ident, self_scope: Scope, parent_scope: &ScopeChain, attrs: Vec<Attribute>) -> Self {
        Self::r#mod(ScopeInfo::new(attrs, crate_ident, self_scope), parent_scope.clone())
    }

    pub fn crate_root_with_ident(crate_ident: Ident, attrs: Vec<Attribute>) -> Self {
        let path = crate_ident.to_path();
        Self::crate_root_with(attrs, crate_ident, path)
    }
    pub fn crate_root(crate_ident: Ident, attrs: Vec<Attribute>) -> Self {
        Self::crate_root_with(attrs, crate_ident, parse_quote!(crate))
    }

    pub fn child_mod(attrs: Vec<Attribute>, crate_ident: Ident, name: &Ident, parent_scope: &ScopeChain) -> Self {
        Self::new_mod(crate_ident, Scope::empty(parent_scope.self_path_ref().joined(name)), parent_scope, attrs)
    }

    pub fn crate_name(&self) -> TokenStream2 {
        if self.is_crate_root() {
            self.crate_ident_ref().to_token_stream()
        } else {
            self.head().to_token_stream()
        }
    }
    pub fn crate_ident_ref(&self) -> &Ident {
        &self.info().crate_ident
    }
    pub fn crate_ident(&self) -> Ident {
        self.crate_ident_ref().clone()
    }
    pub fn crate_ident_as_path(&self) -> Path {
        self.crate_ident_ref().to_path()
    }
    pub fn self_scope_ref(&self) -> &Scope {
        &self.info().self_scope
    }

    pub fn joined_path(&self, ident: &Ident) -> Path {
        self.self_path_ref()
            .joined(ident)
            .crate_named(&self.crate_ident_as_path())
    }

    pub fn self_path_ref(&self) -> &Path {
        &self.self_scope_ref().self_scope
    }
    pub fn self_object_ref(&self) -> &ObjectKind {
        &self.self_scope_ref().object
    }
    pub fn self_object(&self) -> ObjectKind {
        self.self_object_ref().clone()
    }
    pub fn parent_scope(&self) -> Option<&ScopeChain> {
        match self {
            ScopeChain::CrateRoot { .. } |
            ScopeChain::Mod { .. } => None,
            ScopeChain::Trait { parent, .. } |
            ScopeChain::Fn { parent, .. } |
            ScopeChain::Object { parent, .. } |
            ScopeChain::Impl { parent, .. } => Some(parent),
        }
    }
    pub fn parent_object(&self) -> Option<&ObjectKind> {
        self.parent_scope()
            .map(|scope| scope.self_object_ref())
    }
    pub fn obj_root_chain(&self) -> Option<&Self> {
        match self {
            ScopeChain::Fn { parent, .. } => parent.obj_root_chain(),
            ScopeChain::Trait { .. } |
            ScopeChain::Object { .. } |
            ScopeChain::Impl { .. } => Some(self),
            _ => None,
        }
    }

    pub fn obj_root_model_composer(&self) -> fn(TypeModel) -> ObjectKind {
        match self.obj_root_chain() {
            Some(ScopeChain::Trait { .. }) =>
                ObjectKind::trait_model_type,
            Some(ScopeChain::Object { .. } | ScopeChain::Impl { .. }) =>
                ObjectKind::object_model_type,
            _ =>
                ObjectKind::unknown_model_type
        }
    }

    pub(crate) fn is_crate_root(&self) -> bool {
        if let ScopeChain::CrateRoot { info, .. } = self {
            if let Some(PathSegment { ident, .. }) = info.self_path().segments.last() {
                return ident.eq(CRATE)
            }
        }
        false
    }

    pub fn head(&self) -> Ident {
        self.self_path_ref().segments.last().expect("Should have last segment here").ident.clone()
    }

    pub fn has_same_parent(&self, other: &ScopeChain) -> bool {
        match self {
            ScopeChain::CrateRoot { info, .. } |
            ScopeChain::Mod { info, .. } => info.crate_ident.eq(other.crate_ident_ref()) && info.self_scope.eq(other.self_scope_ref()),
            ScopeChain::Trait { parent, .. } |
            ScopeChain::Fn { parent, .. } |
            ScopeChain::Object { parent, .. } |
            ScopeChain::Impl { parent, .. } => other.eq(parent),
        }
    }

    pub fn maybe_generic_bound_for_path(&self, path: &GenericBoundKey) -> Option<(Generics, GenericChain)> {
        match self {
            ScopeChain::CrateRoot { .. } |
            ScopeChain::Mod { .. } => None,
            ScopeChain::Trait { info, .. } |
            ScopeChain::Object { info, .. } |
            ScopeChain::Impl { info, .. } =>
                info.maybe_generic_bound_for_path(path),
            ScopeChain::Fn { info, parent, .. } =>
                info.maybe_generic_bound_for_path(path)
                    .or_else(|| parent.maybe_generic_bound_for_path(path)),
        }
    }
}

impl ResolveAttrs for ScopeChain {
    fn resolve_attrs(&self) -> Vec<Option<Attribute>> {
        match self {
            ScopeChain::CrateRoot { info, .. } =>
                info.attrs.cfg_attributes_or_none(),
            ScopeChain::Mod { info, parent, .. } |
            ScopeChain::Trait { info, parent, .. } |
            ScopeChain::Fn { info, parent, .. } |
            ScopeChain::Object { info, parent, .. } |
            ScopeChain::Impl { info, parent, .. } => {
                let mut inherited_attrs = parent.resolve_attrs();
                inherited_attrs.extend(info.attrs.cfg_attributes_or_none());
                inherited_attrs
            }
        }
    }
}

impl ToPath for ScopeChain {
    fn to_path(&self) -> Path {
        self.self_path_ref().clone()
    }
}