ferment_sys/presentable/
sequence.rs

1use std::fmt::Debug;
2use quote::{quote, ToTokens};
3use syn::__private::TokenStream2;
4use syn::Path;
5use ferment_macro::Display;
6use crate::ast::{Assignment, BraceWrapped, CommaPunctuated, Lambda, ParenWrapped};
7use crate::composer::{AspectCommaPunctuatedArguments, AttrComposable, TypeAspect, VariantComposable, FieldsConversionComposable, SourceComposable, ComposerLinkRef, AspectTerminatedArguments, AspectPresentableArguments};
8use crate::context::ScopeContext;
9use crate::ext::{LifetimeProcessor, Mangle, ToPath};
10use crate::lang::{LangFermentable, RustSpecification, Specification};
11use crate::presentable::{Aspect, ScopeContextPresentable};
12use crate::presentation::{DictionaryName, InterfacesMethodExpr, present_struct, RustFermentate};
13
14
15#[derive(Clone, Debug, Display)]
16pub enum SeqKind<LANG, SPEC>
17    where LANG: LangFermentable,
18          SPEC: Specification<LANG> {
19    FromStub(AspectCommaPunctuatedArguments<LANG, SPEC>),
20    FromNamedFields(AspectCommaPunctuatedArguments<LANG, SPEC>),
21    ToNamedFields(AspectCommaPunctuatedArguments<LANG, SPEC>),
22    FromUnnamedFields(AspectCommaPunctuatedArguments<LANG, SPEC>),
23    ToUnnamedFields(AspectCommaPunctuatedArguments<LANG, SPEC>),
24    ToStub(AspectCommaPunctuatedArguments<LANG, SPEC>),
25    NamedVariantFields(AspectCommaPunctuatedArguments<LANG, SPEC>),
26    UnnamedVariantFields(AspectCommaPunctuatedArguments<LANG, SPEC>),
27    EnumUnitFields(AspectCommaPunctuatedArguments<LANG, SPEC>),
28
29    Variants(Aspect<SPEC::TYC>, SPEC::Attr, CommaPunctuated<SeqKind<LANG, SPEC>>),
30    Unit(Aspect<SPEC::TYC>),
31    NoFieldsConversion(Aspect<SPEC::TYC>),
32    TypeAliasFromConversion(AspectCommaPunctuatedArguments<LANG, SPEC>),
33    NamedStruct(AspectCommaPunctuatedArguments<LANG, SPEC>),
34    UnnamedStruct(AspectCommaPunctuatedArguments<LANG, SPEC>),
35    StubStruct(AspectCommaPunctuatedArguments<LANG, SPEC>),
36    Enum(Box<SeqKind<LANG, SPEC>>),
37
38    StructFrom(Box<SeqKind<LANG, SPEC>>, Box<SeqKind<LANG, SPEC>>),
39    StructTo(Box<SeqKind<LANG, SPEC>>, Box<SeqKind<LANG, SPEC>>),
40
41    EnumVariantFrom(Box<SeqKind<LANG, SPEC>>, Box<SeqKind<LANG, SPEC>>),
42    EnumVariantTo(Box<SeqKind<LANG, SPEC>>, Box<SeqKind<LANG, SPEC>>),
43    EnumVariantDrop(Box<SeqKind<LANG, SPEC>>, Box<SeqKind<LANG, SPEC>>),
44
45    DerefFFI,
46    Obj,
47    Empty,
48
49    DropStub(AspectTerminatedArguments<LANG, SPEC>),
50    StructDropBody(AspectTerminatedArguments<LANG, SPEC>),
51    DropCode(AspectTerminatedArguments<LANG, SPEC>),
52}
53
54impl<LANG, SPEC> SeqKind<LANG, SPEC>
55    where LANG: LangFermentable,
56          SPEC: Specification<LANG> {
57    pub fn struct_to(field_path: &SeqKind<LANG, SPEC>, conversions: SeqKind<LANG, SPEC>) -> Self {
58        Self::StructTo(field_path.clone().into(), conversions.into())
59    }
60    pub fn struct_from(field_path: &SeqKind<LANG, SPEC>, conversions: SeqKind<LANG, SPEC>) -> Self {
61        Self::StructFrom(field_path.clone().into(), conversions.into())
62    }
63    pub fn variant_from(left: &SeqKind<LANG, SPEC>, right: SeqKind<LANG, SPEC>) -> Self {
64        Self::EnumVariantFrom(left.clone().into(), right.clone().into())
65    }
66    pub fn variant_to(left: &SeqKind<LANG, SPEC>, right: SeqKind<LANG, SPEC>) -> Self {
67        Self::EnumVariantTo(left.clone().into(), right.clone().into())
68    }
69    pub fn variant_drop(left: &SeqKind<LANG, SPEC>, right: SeqKind<LANG, SPEC>) -> Self {
70        Self::EnumVariantDrop(left.clone().into(), right.clone().into())
71    }
72    pub fn struct_drop_post_processor(_: &SeqKind<LANG, SPEC>, right: SeqKind<LANG, SPEC>) -> Self {
73        right
74    }
75
76    pub fn no_fields<SEP: ToTokens>(((aspect, ..), _): AspectPresentableArguments<LANG, SPEC, SEP>) -> Self {
77        Self::NoFieldsConversion(match &aspect {
78            Aspect::Target(context) => Aspect::RawTarget(context.clone()),
79            _ => aspect.clone(),
80        })
81    }
82    pub fn unit(((aspect, ..), _): &AspectCommaPunctuatedArguments<LANG, SPEC>) -> Self {
83        Self::Unit(aspect.clone())
84    }
85    pub fn variants<C>(composer_ref: &ComposerLinkRef<C>) -> Self
86        where C: AttrComposable<SPEC::Attr> + TypeAspect<SPEC::TYC> + VariantComposable<LANG, SPEC> {
87        Self::Variants(C::target_type_aspect(composer_ref), C::compose_attributes(composer_ref), C::compose_variants(composer_ref))
88    }
89    pub fn deref_ffi<C>(_ctx: &ComposerLinkRef<C>) -> Self {
90        Self::DerefFFI
91    }
92    pub fn empty<C>(_ctx: &ComposerLinkRef<C>) -> Self {
93        Self::Empty
94    }
95    pub fn obj<C>(_ctx: &ComposerLinkRef<C>) -> Self {
96        Self::Obj
97    }
98    pub fn unit_fields(context: &AspectCommaPunctuatedArguments<LANG, SPEC>) -> Self {
99        Self::EnumUnitFields(context.clone())
100    }
101    pub fn brace_variants(context: &AspectCommaPunctuatedArguments<LANG, SPEC>) -> Self {
102        Self::NamedVariantFields(context.clone())
103    }
104    pub fn paren_variants(context: &AspectCommaPunctuatedArguments<LANG, SPEC>) -> Self {
105        Self::UnnamedVariantFields(context.clone())
106    }
107    pub fn empty_root(_: SeqKind<LANG, SPEC>) -> Self {
108        Self::Empty
109    }
110    pub fn bypass(sequence: SeqKind<LANG, SPEC>) -> Self {
111        sequence
112    }
113    pub fn r#enum(context: SeqKind<LANG, SPEC>) -> Self {
114        Self::Enum(Box::new(context))
115    }
116    pub fn fields_from<C>(ctx: &ComposerLinkRef<C>) -> Self
117        where C: FieldsConversionComposable<LANG, SPEC> + 'static {
118        ctx.fields_from().compose(&())
119    }
120    pub fn fields_to<C>(ctx: &ComposerLinkRef<C>) -> Self
121        where C: FieldsConversionComposable<LANG, SPEC> + 'static {
122        ctx.fields_to().compose(&())
123    }
124}
125
126impl<SPEC> ScopeContextPresentable for SeqKind<RustFermentate, SPEC>
127    where SPEC: RustSpecification {
128    type Presentation = TokenStream2;
129
130    fn present(&self, source: &ScopeContext) -> Self::Presentation {
131        let result = match self {
132            SeqKind::Empty |
133            SeqKind::FromStub(..) |
134            SeqKind::ToStub(..) |
135            SeqKind::DropStub(..) |
136            SeqKind::StubStruct(..) =>
137                quote!(),
138            SeqKind::FromUnnamedFields(((aspect, _attrs, _generics, _is_round), fields)) |
139            SeqKind::ToUnnamedFields(((aspect, _attrs, _generics, _is_round), fields)) => {
140                //println!("SequenceOutput::{}({}, {:?})", self, aspect, fields);
141                let name = aspect.present(source);
142                let presentation = fields.present(source);
143                quote!(#name ( #presentation ) )
144            },
145            SeqKind::FromNamedFields(((aspect, ..), fields)) |
146            SeqKind::ToNamedFields(((aspect, ..), fields)) => {
147                //println!("SequenceOutput::{}({}, {:?})", self, aspect, fields);
148                let name = aspect.present(source);
149                let cleaned_name = name.lifetimes_cleaned();
150                let presentation = fields.present(source);
151                quote!(#cleaned_name { #presentation })
152            },
153            SeqKind::TypeAliasFromConversion((_, fields)) => {
154                //println!("SequenceOutput::{}({:?})", self, fields);
155                fields.present(source)
156                    .to_token_stream()
157            },
158            SeqKind::UnnamedVariantFields(((aspect, _attrs, _generics, _is_round), fields)) => {
159                //println!("SequenceOutput::{}({}, {:?})", self, aspect, fields);
160                let attrs = aspect.attrs();
161                let path: Path = aspect.present(source).to_path();
162                let ident = &path.segments.last().unwrap().ident;
163                let presentation = ParenWrapped::new(fields.clone()).present(source);
164                quote! {
165                    #(#attrs)*
166                    #ident #presentation
167                }
168            }
169            SeqKind::NamedVariantFields(((aspect, _attrs, _generics, _is_round), fields)) => {
170                //println!("SequenceOutput::{}({}, {:?})", self, aspect, fields);
171                let attrs = aspect.attrs();
172                let path = aspect.present(source).to_path();
173                let ident = &path.segments.last().unwrap().ident;
174                let presentation = BraceWrapped::new(fields.clone()).present(source);
175                quote! {
176                    #(#attrs)*
177                    #ident #presentation
178                }
179            }
180            SeqKind::Variants(aspect, attrs, fields) => {
181                //println!("SequenceOutput::{}({}, {:?})", self, aspect, fields);
182                let name = aspect.present(source).mangle_ident_default();
183                let presentation = BraceWrapped::new(fields.clone()).present(source);
184                quote! {
185                    #(#attrs)*
186                    #name #presentation
187                }
188            },
189            SeqKind::UnnamedStruct(((aspect, _attrs, _generics, _is_round), fields)) => {
190                //println!("SequenceOutput::{}({}, {:?})", self, aspect, fields);
191                let ffi_type = aspect.present(source);
192                let fields = fields.present(source);
193                present_struct(
194                    &ffi_type.to_path().segments.last().unwrap().ident,
195                    aspect.attrs(),
196                    quote!((#fields);))
197            },
198            SeqKind::NamedStruct(((aspect, _attrs, _generics, _is_round), fields)) => {
199                //println!("SequenceOutput::{}({}, {:?})", self, aspect, fields);
200                let ffi_type = aspect.present(source);
201                let fields = fields.present(source);
202                //println!("SequenceOutput({})", ffi_type.to_token_stream());
203                present_struct(
204                    &ffi_type.to_path().segments.last().unwrap().ident,
205                    aspect.attrs(),
206                    quote!({#fields}))
207            },
208            SeqKind::Enum(context) => {
209                //println!("SequenceOutput::{}({:?})", self, context);
210                let enum_presentation = context.present(source);
211                quote! {
212                    #[repr(C)]
213                    #[derive(Clone)]
214                    #[non_exhaustive]
215                    pub enum #enum_presentation
216                }
217            },
218            SeqKind::Unit(aspect) => {
219                //println!("SequenceOutput::{}({})", self, aspect);
220                let attrs = aspect.attrs();
221                let path = aspect.present(source)
222                    .to_path();
223
224                let last_segment = path.segments
225                    .last()
226                    .expect("Empty path");
227
228                quote! {
229                    #(#attrs)*
230                    #last_segment
231                }
232            },
233            SeqKind::NoFieldsConversion(aspect) => {
234                // println!("SequenceOutput::{}({})", self, aspect);
235                aspect.present(source)
236                    .to_token_stream()
237            },
238            SeqKind::EnumUnitFields(((aspect, _attrs, _generics, _is_round), fields)) => {
239                //println!("SequenceOutput::{}({}, {:?})", self, aspect, fields);
240                Assignment::new(
241                    aspect.present(source).to_path().segments.last().unwrap().ident.clone(),
242                    fields.present(source))
243                    .to_token_stream()
244            },
245            SeqKind::StructFrom(field_context, conversions) => {
246                //println!("SequenceOutput::StructFrom({}, {:?})", field_context, conversions);
247                let conversions = conversions.present(source);
248                let field_path = field_context.present(source);
249                quote!(let ffi_ref = #field_path; #conversions)
250            }
251            SeqKind::StructTo(_field_context, conversions) => {
252                InterfacesMethodExpr::Boxed(conversions.present(source))
253                    .to_token_stream()
254            }
255            // SeqKind::Boxed(conversions) => {
256            //     //println!("SequenceOutput::{}({})", self, conversions);
257            //     InterfacesMethodExpr::Boxed(conversions.present(source))
258            //         .to_token_stream()
259            // }
260            SeqKind::EnumVariantFrom(l_value, r_value) |
261            SeqKind::EnumVariantTo(l_value, r_value) |
262            SeqKind::EnumVariantDrop(l_value, r_value) => {
263                //println!("SequenceOutput::{}({:?}, {:?})", self, l_value, r_value);
264                Lambda::new(l_value.present(source), r_value.present(source))
265                    .to_token_stream()
266            }
267            SeqKind::DerefFFI => {
268                let field_path = DictionaryName::Ffi;
269                //println!("SequenceOutput::{}({})", self, field_path);
270                quote!(&*#field_path)
271            }
272            SeqKind::Obj => {
273                //println!("SequenceOutput::{}", self);
274                DictionaryName::Obj.to_token_stream()
275            },
276            SeqKind::StructDropBody((_, items)) => {
277                //println!("SequenceOutput::{}({:?})", self, items);
278                let destructors = items.present(source);
279                quote! {
280                    let ffi_ref = self;
281                    #destructors
282                }
283            },
284            SeqKind::DropCode((_, items)) => {
285                //println!("SequenceOutput::{}({:?})", self, items);
286                let destructors = items.present(source);
287                quote!({ #destructors })
288            }
289        };
290        // println!("SequenceOutput::{}({})", self, result);
291        result
292    }
293}