ferment-sys 0.2.14

Syntax tree morphing of FFI-compatible stuff
Documentation
use std::fmt::{Debug, Display, Formatter};
use proc_macro2::Ident;
use quote::ToTokens;
use syn::__private::TokenStream2;
use syn::{Attribute, Generics, Item, ItemConst, ItemEnum, ItemFn, ItemImpl, ItemMod, ItemStruct, ItemTrait, ItemType, ParenthesizedGenericArguments, Path, PathSegment, QSelf, Signature, Type};
use syn::token::PathSep;
use crate::ast::{Colon2Punctuated, CommaPunctuated};
use crate::composable::{NestedArgument, TraitDecompositionPart1, TraitModel, TypeModel, TypeModeled};
use crate::composer::CommaPunctuatedNestedArguments;
use crate::context::ScopeContext;
use crate::kind::{DictFermentableModelKind, DictTypeModelKind, GenericBoundsModel, GenericTypeKind, GroupModelKind, ScopeItemKind, SmartPointerModelKind, TypeKind, TypeModelKind};
use crate::ext::{AsType, collect_bounds, MaybeLambdaArgs, ResolveAttrs, ToType, ValueReplaceScenario, handle_type_path_model, PunctuateOne};
use crate::lang::{NameComposable, Specification};

#[derive(Clone, PartialEq, Eq, Hash)]
pub enum ObjectKind {
    Type(TypeModelKind),
    Item(TypeModelKind, ScopeItemKind),
    Empty
}

impl ObjectKind {
    pub fn model_type<T: Fn(TypeModel) -> TypeModelKind>(model_kind_composer: T, model: TypeModel) -> Self {
        Self::Type(model_kind_composer(model))
    }
    pub fn model_item<T: Fn(TypeModel) -> TypeModelKind>(model_kind_composer: T, model: TypeModel, item: ScopeItemKind) -> Self {
        Self::Item(model_kind_composer(model), item)
    }

    pub fn object_model_type(model: TypeModel) -> Self {
        Self::model_type(TypeModelKind::Object, model)
    }
    pub fn array_model_type(model: TypeModel) -> Self {
        Self::model_type(TypeModelKind::Array, model)
    }
    pub fn slice_model_type(model: TypeModel) -> Self {
        Self::model_type(TypeModelKind::Slice, model)
    }
    pub fn tuple_model_type(model: TypeModel) -> Self {
        Self::model_type(TypeModelKind::Tuple, model)
    }
    pub fn optional_model_type(model: TypeModel) -> Self {
        Self::model_type(TypeModelKind::Optional, model)
    }
    pub fn trait_model_type(model: TypeModel) -> Self {
        Self::model_type(TypeModelKind::TraitType, model)
    }
    pub fn fn_model_type(model: TypeModel) -> Self {
        Self::model_type(TypeModelKind::Fn, model)
    }
    pub fn fn_pointer_model_type(model: TypeModel) -> Self {
        Self::model_type(TypeModelKind::FnPointer, model)
    }
    pub fn unknown_model_type(model: TypeModel) -> Self {
        Self::model_type(TypeModelKind::Unknown, model)
    }
    pub fn unknown_model_type_path(qself: &Option<QSelf>, sep: Option<PathSep>, segments: Colon2Punctuated<PathSegment>, nested_arguments: CommaPunctuatedNestedArguments) -> Self {
        Self::model_type(TypeModelKind::Unknown, handle_type_path_model(qself, sep, segments, nested_arguments))
    }
    pub fn unknown_type(ty: Type) -> Self {
        Self::Type(TypeModelKind::unknown_type(ty))
    }
    pub fn unknown_type_with_nested_arguments(ty: Type, nested_arguments: CommaPunctuatedNestedArguments) -> Self {
        Self::Type(TypeModelKind::unknown_type_with_nested_arguments(ty, nested_arguments))
    }
    pub fn bounds(model: GenericBoundsModel) -> Self {
        Self::Type(TypeModelKind::Bounds(model))
    }
    pub fn dict_type(kind: DictTypeModelKind) -> Self {
        Self::Type(TypeModelKind::Dictionary(kind))
    }
    pub fn imported_model_type(model: TypeModel, path: Path) -> Self {
        Self::Type(TypeModelKind::Imported(model, path))
    }
    pub fn primitive_type(ident: &Ident) -> Self {
        Self::dict_type(DictTypeModelKind::Primitive(TypeModel::new_default(ident.to_type())))
    }
    pub fn non_primitive_fermentable_type(kind: DictFermentableModelKind) -> Self {
        Self::dict_type(DictTypeModelKind::NonPrimitiveFermentable(kind))
    }
    pub fn group_type(kind: GroupModelKind) -> Self {
        Self::non_primitive_fermentable_type(DictFermentableModelKind::Group(kind))
    }
    pub fn lambda_fn_model_type(model: TypeModel) -> Self {
        Self::dict_type(DictTypeModelKind::LambdaFn(model))
    }
    pub fn smart_ptr_type(kind: SmartPointerModelKind) -> Self {
        Self::non_primitive_fermentable_type(DictFermentableModelKind::SmartPointer(kind))
    }

    pub fn str_type(ty: Type) -> Self {
        Self::non_primitive_fermentable_type(DictFermentableModelKind::Str(TypeModel::new_default(ty)))
    }
    pub fn string_type(ty: Type) -> Self {
        Self::non_primitive_fermentable_type(DictFermentableModelKind::String(TypeModel::new_default(ty)))
    }
    pub fn i128_type(ty: &Ident) -> Self {
        Self::non_primitive_fermentable_type(DictFermentableModelKind::I128(TypeModel::new_default(ty.to_type())))
    }
    pub fn u128_type(ty: &Ident) -> Self {
        Self::non_primitive_fermentable_type(DictFermentableModelKind::U128(TypeModel::new_default(ty.to_type())))
    }

    pub fn new_item(ty: TypeModelKind, item: ScopeItemKind) -> Self {
        Self::Item(ty, item)
    }
    fn new_obj_item(ty: TypeModel, item: ScopeItemKind) -> Self {
        Self::model_item(TypeModelKind::Object, ty, item)
    }
    pub fn new_generic_obj_item(ty: Type, generics: &Generics, nested_arguments: CommaPunctuatedNestedArguments, item: ScopeItemKind) -> Self {
        Self::new_obj_item(TypeModel::new_generic(ty, generics.clone(), nested_arguments), item)
    }
    pub fn new_generic_non_nested_obj_item(ty: Type, generics: &Generics, item: ScopeItemKind) -> Self {
        Self::new_obj_item(TypeModel::new_generic_non_nested(ty, generics), item)
    }
    pub fn new_trait_item(model: TraitModel, item: ScopeItemKind) -> Self {
        Self::new_item(TypeModelKind::Trait(model), item)
    }
    pub fn new_fn_item(ty: TypeModel, item: ScopeItemKind) -> Self {
        Self::model_item(TypeModelKind::Fn, ty, item)
    }
    pub fn new_fn_pointer_item(ty: TypeModel, item: ScopeItemKind) -> Self {
        Self::model_item(TypeModelKind::FnPointer, ty, item)
    }

}


impl ObjectKind {
    pub fn is_type(&self, ty: &Type) -> bool {
        match self {
            ObjectKind::Type(conversion) |
            ObjectKind::Item(conversion, _) =>
                ty.eq(conversion.as_type()),
            ObjectKind::Empty => false
        }
    }
    pub fn is_refined(&self) -> bool {
        match self {
            ObjectKind::Type(conversion) => conversion.is_refined(),
            _ => true
        }
    }
    pub fn maybe_callback(&self) -> Option<&ParenthesizedGenericArguments> {
        match self {
            ObjectKind::Type(tyc) |
            ObjectKind::Item(tyc, _) => tyc.maybe_callback(),
            ObjectKind::Empty => None
        }
    }

    pub fn is_lambda(&self) -> bool {
        match self {
            ObjectKind::Type(tyc) |
            ObjectKind::Item(tyc, _) => tyc.is_lambda(),
            ObjectKind::Empty => false
        }
    }


    pub fn maybe_trait_or_same_kind(&self, source: &ScopeContext) -> Option<TypeModelKind> {
        match self {
            ObjectKind::Item(.., ScopeItemKind::Fn(..)) =>
                source.maybe_parent_trait_or_regular_model_kind(),
            ObjectKind::Type(ref type_model_kind) |
            ObjectKind::Item(ref type_model_kind, ..) =>
                type_model_kind.maybe_trait_model_kind_or_same(source),
            ObjectKind::Empty => None
        }
    }
    pub fn maybe_fn_or_trait_or_same_kind(&self, source: &ScopeContext) -> Option<TypeModelKind> {
        match self {
            ObjectKind::Item(.., ScopeItemKind::Fn(..)) =>
                source.maybe_parent_trait_or_regular_model_kind(),
            ObjectKind::Type(ref type_model_kind) |
            ObjectKind::Item(ref type_model_kind, ..) =>
                type_model_kind.maybe_trait_object_maybe_model_kind(source)
                    .unwrap_or_else(|| Some(type_model_kind.clone())),
            ObjectKind::Empty => None
        }
    }

    pub fn maybe_fn_or_trait_or_same_kind2(&self, source: &ScopeContext) -> Option<TypeModelKind> {
        match self {
            ObjectKind::Item(.., ScopeItemKind::Fn(..)) =>
                source.maybe_parent_trait_or_regular_model_kind(),
            ObjectKind::Type(ref type_model_kind) |
            ObjectKind::Item(ref type_model_kind, ..) =>
                type_model_kind.maybe_trait_model_kind_or_same(source),
            _ => None,
        }
    }

    pub fn maybe_scope_item(&self) -> Option<&ScopeItemKind> {
        match self {
            ObjectKind::Item(_, scope_item) => Some(scope_item),
            _ => None
        }
    }
}

impl<SPEC> MaybeLambdaArgs<SPEC> for ObjectKind
    where SPEC: Specification {
    fn maybe_lambda_arg_names(&self) -> Option<CommaPunctuated<SPEC::Name>> {
        match self.maybe_callback() {
            Some(ParenthesizedGenericArguments { inputs, ..}) =>
                Some(CommaPunctuated::from_iter((0..inputs.len()).map(SPEC::Name::unnamed_arg))),
            _ => None
        }
    }
}

impl ValueReplaceScenario for ObjectKind {
    fn should_replace_with(&self, other: &Self) -> bool {
        match (self, other) {
            (_, ObjectKind::Item(..)) => true,
            (ObjectKind::Type(self_ty), ObjectKind::Type(candidate_ty)) => !self_ty.is_refined() || candidate_ty.is_bounds(),
            _ => false
        }
    }
}



impl ToTokens for ObjectKind {
    fn to_tokens(&self, tokens: &mut TokenStream2) {
        self.maybe_type().to_tokens(tokens)
    }
}
impl Debug for ObjectKind {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            ObjectKind::Type(tc) =>
                f.write_fmt(format_args!("Type({tc})")),
            ObjectKind::Item(tc, item) =>
                f.write_fmt(format_args!("Item({tc}, {item})")),
            ObjectKind::Empty =>
                f.write_str("Empty"),
        }
    }
}

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

impl ObjectKind {
    pub fn maybe_type_model_kind_ref(&self) -> Option<&TypeModelKind> {
        match self {
            ObjectKind::Type(tyc) |
            ObjectKind::Item(tyc, ..) => Some(tyc),
            ObjectKind::Empty => None
        }
    }
    pub fn maybe_type_model_kind(&self) -> Option<TypeModelKind> {
        self.maybe_type_model_kind_ref().cloned()
    }
    pub fn maybe_generic_type_kind(&self) -> Option<GenericTypeKind> {
        match self.maybe_type_model_kind_ref() {
            Some(kind) => match TypeKind::from(kind.to_type()) {
                TypeKind::Generic(kind) => Some(kind),
                _ => None
            }
            _ => None
        }
    }
    pub fn maybe_type_ref(&self) -> Option<&Type> {
        self.maybe_type_model_ref()
            .map(TypeModel::as_type)
    }
    pub fn maybe_type_model_ref(&self) -> Option<&TypeModel> {
        self.maybe_type_model_kind_ref()
            .map(TypeModelKind::type_model_ref)
    }
    pub fn maybe_type(&self) -> Option<Type> {
        self.maybe_type_model_kind_ref()
            .map(TypeModelKind::to_type)
    }
}

impl TryFrom<(&Item, &Path)> for ObjectKind {
    type Error = ();

    fn try_from((value, scope): (&Item, &Path)) -> Result<Self, Self::Error> {
        let item_kind = ScopeItemKind::item_ref(value, scope);
        match value {
            Item::Trait(ItemTrait { ident, generics, items, supertraits, .. }) =>
                Ok(ObjectKind::new_trait_item(TraitModel::new(TypeModel::new_generic_ident_non_nested(ident, generics), TraitDecompositionPart1::from_trait_items(ident, items), collect_bounds(supertraits)), item_kind)),
            Item::Const(ItemConst { ident, generics, .. }) |
            Item::Struct(ItemStruct { ident, generics, .. }) |
            Item::Enum(ItemEnum { ident, generics, .. }) |
            Item::Fn(ItemFn { sig: Signature { ident, generics, .. }, .. }) =>
                Ok(ObjectKind::new_generic_non_nested_obj_item(ident.to_type(), generics, item_kind)),
            Item::Type(ItemType { ident, generics, ty, .. }) =>
                Ok(match &**ty {
                    Type::BareFn(..) =>
                        ObjectKind::new_fn_pointer_item(TypeModel::new_generic_ident(ident, generics.clone(), NestedArgument::Object(ObjectKind::fn_model_type(TypeModel::new_generic_non_nested(*ty.clone(), generics))).punctuate_one()), item_kind),
                    _ =>
                        ObjectKind::new_generic_non_nested_obj_item(ident.to_type(), generics, item_kind)
                }),
            Item::Impl(ItemImpl { self_ty, generics, .. }) =>
                Ok(ObjectKind::new_generic_non_nested_obj_item(*self_ty.clone(), generics, item_kind)),
            Item::Mod(ItemMod { ident, .. }) =>
                Ok(ObjectKind::new_item(TypeModelKind::unknown_type(ident.to_type()), item_kind)),
            _ =>
                Err(()),
        }
    }
}

impl ResolveAttrs for ObjectKind {
    fn resolve_attrs(&self) -> Vec<Option<Attribute>> {
        match self {
            ObjectKind::Item(_, item) =>
                item.resolve_attrs(),
            _ => vec![],
        }
    }
}