ferment-sys 0.2.14

Syntax tree morphing of FFI-compatible stuff
Documentation
use std::rc::Rc;
use std::cell::RefCell;
use std::clone::Clone;
use quote::ToTokens;
use syn::{Generics, Lifetime};
use syn::token::{Brace, Paren};
use ferment_macro::ComposerBase;
use crate::ast::{DelimiterTrait, Depunctuated, Void};
use crate::composable::{AttrsModel, GenModel, LifetimesModel};
use crate::composer::{BasicComposer, BasicComposerLink, BasicComposerOwner, BindingComposable, CommaArgComposers, CommaPunctuatedFields, ComposerLink, DocComposer, DocsComposable, FFIAspect, FFIBindingsSpec, FFIConversionsSpec, FFIFieldsSpec, FFIObjectComposable, FFIObjectSpec, FieldsContext, FieldsConversionComposable, FieldsOwnedSequenceComposerLink, ItemComposerSpec, Linkable, MaybeFFIBindingsComposerLink, MaybeFFIComposerLink, NameKind, NameKindComposable, SeqKindComposerLink, SourceAccessible, SourceComposable, ArgKindPairs};
use crate::context::ScopeContextLink;
use crate::lang::Specification;
use crate::presentable::{BindingPresentableContext, ScopeContextPresentable, SeqKind};
use crate::presentation::{DocPresentation, FFIObjectPresentation};


#[derive(ComposerBase)]
pub struct ItemComposer<SPEC, I>
    where SPEC: Specification + 'static,
          I: DelimiterTrait + 'static + ?Sized {
    pub base: BasicComposerLink<SPEC, Self>,
    pub fields_from_composer: FieldsOwnedSequenceComposerLink<SPEC, Self>,
    pub fields_to_composer: FieldsOwnedSequenceComposerLink<SPEC, Self>,
    pub field_composers: CommaArgComposers<SPEC>,

    pub ffi_object_composer: Option<SeqKindComposerLink<SPEC, Self>>,
    pub ffi_conversions_composer: MaybeFFIComposerLink<SPEC, Self>,
    pub bindings_composer: MaybeFFIBindingsComposerLink<SPEC, Self, ArgKindPairs<SPEC>>,
}


impl<SPEC, I> ItemComposer<SPEC, I>
    where SPEC: Specification,
          I: DelimiterTrait + ?Sized {

    pub(crate) fn new<C>(
        ty_context: SPEC::TYC,
        attrs: AttrsModel,
        lifetimes: Vec<Lifetime>,
        generics: Option<Generics>,
        fields: &CommaPunctuatedFields,
        context: &ScopeContextLink
    ) -> ComposerLink<Self>
        where C: FFIFieldsSpec<SPEC, ComposerLink<Self>>
        + FFIObjectSpec<SPEC, ComposerLink<Self>>
        + FFIBindingsSpec<SPEC, ComposerLink<Self>, ArgKindPairs<SPEC>>
        + FFIConversionsSpec<SPEC, ComposerLink<Self>>
        + ItemComposerSpec<SPEC> {
        let root = Rc::new(RefCell::new(Self {
            base: BasicComposer::from(DocComposer::from(&ty_context), attrs, ty_context, GenModel::new(generics), LifetimesModel::new(lifetimes), Rc::clone(context)),
            fields_from_composer: <C as FFIFieldsSpec<SPEC, ComposerLink<Self>>>::FROM,
            fields_to_composer: <C as FFIFieldsSpec<SPEC, ComposerLink<Self>>>::TO,
            bindings_composer: <C as FFIBindingsSpec<SPEC, ComposerLink<Self>, ArgKindPairs<SPEC>>>::COMPOSER,
            ffi_conversions_composer: <C as FFIConversionsSpec<SPEC, ComposerLink<Self>>>::COMPOSER,
            ffi_object_composer: <C as FFIObjectSpec<SPEC, ComposerLink<Self>>>::COMPOSER,
            field_composers: C::FIELD_COMPOSERS(fields),
        }));
        {
            root.borrow_mut().setup_composers(&root);
        }
        root
    }

    fn setup_composers(&mut self, root: &ComposerLink<Self>) {
        self.base.link(root);
        self.fields_from_composer.link(root);
        self.fields_to_composer.link(root);
        if let Some(ref mut composer) = self.bindings_composer {
            composer.link(root);
        }
        if let Some(ref mut composer) = self.ffi_object_composer {
            composer.link(root)
        }
        if let Some(ref mut composer) = self.ffi_conversions_composer {
            composer.link(root);
        }
    }

    pub(crate) fn compose_aspect(&self, aspect: FFIAspect) -> SeqKind<SPEC> {
        self.ffi_conversions_composer
            .as_ref()
            .expect("Composer doesn't exist")
            .compose(&aspect)
    }
}

impl<SPEC, I> FieldsContext<SPEC> for ItemComposer<SPEC, I>
    where SPEC: Specification,
          I: DelimiterTrait + ?Sized {
    fn field_composers_ref(&self) -> &CommaArgComposers<SPEC> {
        &self.field_composers
    }
}

impl<SPEC, I> FieldsConversionComposable<SPEC> for ItemComposer<SPEC, I>
    where SPEC: Specification,
          I: DelimiterTrait + ?Sized {
    fn fields_from(&self) -> &FieldsOwnedSequenceComposerLink<SPEC, Self> {
        &self.fields_from_composer
    }

    fn fields_to(&self) -> &FieldsOwnedSequenceComposerLink<SPEC, Self> {
        &self.fields_to_composer
    }
}

impl<SPEC> NameKindComposable for ItemComposer<SPEC, Paren>
    where SPEC: Specification {
    fn compose_name_kind(&self) -> NameKind {
        NameKind::Unnamed
    }
}
impl<SPEC> NameKindComposable for ItemComposer<SPEC, Brace>
    where SPEC: Specification {
    fn compose_name_kind(&self) -> NameKind {
        NameKind::Named
    }
}
impl<SPEC> NameKindComposable for ItemComposer<SPEC, Void>
    where SPEC: Specification {
    fn compose_name_kind(&self) -> NameKind {
        NameKind::Unit
    }
}

impl<SPEC, I> DocsComposable for ItemComposer<SPEC, I>
    where SPEC: Specification,
          I: DelimiterTrait + ?Sized {
    fn compose_docs(&self) -> DocPresentation {
        self.base.compose_docs()
    }
}

impl<SPEC, I> FFIObjectComposable for ItemComposer<SPEC, I>
    where SPEC: Specification,
          I: DelimiterTrait + ?Sized,
          SeqKind<SPEC>: ScopeContextPresentable {
    fn compose_object(&self) -> FFIObjectPresentation {
        if let Some(ref obj_composer) = self.ffi_object_composer {
            FFIObjectPresentation::Full(obj_composer.compose(&())
                .present(&self.source_ref())
                .to_token_stream())
        } else {
            FFIObjectPresentation::Empty
        }
    }
}

impl<SPEC, I> BindingComposable<SPEC> for ItemComposer<SPEC, I>
    where SPEC: Specification,
          I: DelimiterTrait + ?Sized {
    fn compose_bindings(&self) -> Depunctuated<BindingPresentableContext<SPEC>> {
        let source = self.source_ref();
        self.bindings_composer
            .as_ref()
            .map(|c| c.compose(&source))
            .unwrap_or_default()
    }
}