use std::cell::Ref;
use std::fmt::Debug;
use quote::ToTokens;
use syn::__private::TokenStream2;
use crate::ast::{CommaPunctuated, Depunctuated};
use crate::composer::{BasicComposerLink, ComposerLinkRef, CommaArgComposers, FieldsOwnedSequenceComposerLink};
use crate::context::{ScopeContext, ScopeContextLink};
use crate::ext::{WrapIntoCurlyBraces, WrapIntoRoundBraces};
use crate::lang::Specification;
use crate::presentable::{Aspect, BindingPresentableContext, NameTreeContext, ScopeContextPresentable, SeqKind};
use crate::presentation::{DocPresentation, FFIObjectPresentation};
pub trait BasicComposerOwner<SPEC>: Sized + 'static
where SPEC: Specification {
fn base(&self) -> &BasicComposerLink<SPEC, Self>;
}
pub trait SourceAccessible {
fn context(&self) -> &ScopeContextLink;
fn source_ref(&self) -> Ref<'_, ScopeContext> { self.context().borrow() }
}
pub trait SourceFermentable<Fermentate> {
fn ferment(&self) -> Fermentate;
}
pub trait TypeAspect<TYC>
where TYC: NameTreeContext {
fn type_context(&self) -> TYC { self.type_context_ref().clone() }
fn type_context_ref(&self) -> &TYC;
fn ffi_type_aspect(&self) -> Aspect<TYC> { Aspect::Ffi(self.type_context()) }
fn target_type_aspect(&self) -> Aspect<TYC> { Aspect::Target(self.type_context()) }
fn raw_target_type_aspect(&self) -> Aspect<TYC> { Aspect::RawTarget(self.type_context()) }
}
pub trait AspectPresentable<TYC>: TypeAspect<TYC>
where TYC: NameTreeContext,
Aspect<TYC>: ScopeContextPresentable {
fn present_ffi_aspect(&self) -> <Aspect<TYC> as ScopeContextPresentable>::Presentation;
fn present_target_aspect(&self) -> <Aspect<TYC> as ScopeContextPresentable>::Presentation;
#[allow(unused)]
fn present_ffi_aspect_ref(ref_self: &ComposerLinkRef<Self>) -> <Aspect<TYC> as ScopeContextPresentable>::Presentation {
ref_self.present_ffi_aspect()
}
#[allow(unused)]
fn present_target_aspect_ref(ref_self: &ComposerLinkRef<Self>) -> <Aspect<TYC> as ScopeContextPresentable>::Presentation {
ref_self.present_target_aspect()
}
}
pub trait FieldsContext<SPEC>
where SPEC: Specification {
fn field_composers_ref(&self) -> &CommaArgComposers<SPEC>;
#[allow(unused)]
fn field_composers(&self) -> CommaArgComposers<SPEC> {
self.field_composers_ref()
.clone()
}
#[allow(unused)]
fn field_composers_by_ref(by_ref: &ComposerLinkRef<Self>) -> CommaArgComposers<SPEC> {
by_ref.field_composers()
}
}
pub trait FieldsConversionComposable<SPEC>
where SPEC: Specification {
fn fields_from(&self) -> &FieldsOwnedSequenceComposerLink<SPEC, Self>
where Self: Sized + 'static;
fn fields_to(&self) -> &FieldsOwnedSequenceComposerLink<SPEC, Self>
where Self: Sized + 'static;
}
pub trait DocsComposable {
fn compose_docs(&self) -> DocPresentation;
}
#[derive(Clone, Debug)]
pub enum NameKind {
Named,
Unnamed,
Unit
}
impl NameKind {
pub fn wrap<T: ToTokens>(&self, expr: T) -> TokenStream2 {
match self {
NameKind::Unnamed => WrapIntoRoundBraces::wrap(expr),
_ => WrapIntoCurlyBraces::wrap(expr)
}
}
}
pub trait NameKindComposable {
fn compose_name_kind(&self) -> NameKind;
}
pub trait AttrComposable<T> {
fn compose_attributes(&self) -> T;
}
pub trait GenericsComposable<T> {
fn compose_generics(&self) -> T;
}
pub trait LifetimesComposable<T> {
fn compose_lifetimes(&self) -> T;
}
#[allow(unused)]
pub trait SignatureAspectComposable<Attr, Lt, Gen>: AttrComposable<Attr> + LifetimesComposable<Lt> + GenericsComposable<Gen> {
fn compose_signature_aspect(&self) -> (Attr, Lt, Gen) {
(self.compose_attributes(), self.compose_lifetimes(), self.compose_generics())
}
}
pub trait VariantComposable<SPEC>
where SPEC: Specification {
fn compose_variants(&self) -> CommaPunctuated<SeqKind<SPEC>>;
}
pub trait InterfaceComposable<T> where T: ToTokens {
fn compose_interfaces(&self) -> Depunctuated<T>;
}
pub trait FFIObjectComposable {
fn compose_object(&self) -> FFIObjectPresentation;
}
pub trait BindingComposable<SPEC>
where SPEC: Specification {
fn compose_bindings(&self) -> Depunctuated<BindingPresentableContext<SPEC>>;
}
impl<Link, TYC> AspectPresentable<TYC> for Link
where Link: SourceAccessible + TypeAspect<TYC>,
TYC: NameTreeContext,
Aspect<TYC>: ScopeContextPresentable {
fn present_ffi_aspect(&self) -> <Aspect<TYC> as ScopeContextPresentable>::Presentation {
self.ffi_type_aspect()
.present(&self.source_ref())
}
fn present_target_aspect(&self) -> <Aspect<TYC> as ScopeContextPresentable>::Presentation {
self.target_type_aspect()
.present(&self.source_ref())
}
}