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 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 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 fields.present(source)
156 .to_token_stream()
157 },
158 SeqKind::UnnamedVariantFields(((aspect, _attrs, _generics, _is_round), fields)) => {
159 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 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 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 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 let ffi_type = aspect.present(source);
201 let fields = fields.present(source);
202 present_struct(
204 &ffi_type.to_path().segments.last().unwrap().ident,
205 aspect.attrs(),
206 quote!({#fields}))
207 },
208 SeqKind::Enum(context) => {
209 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 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 aspect.present(source)
236 .to_token_stream()
237 },
238 SeqKind::EnumUnitFields(((aspect, _attrs, _generics, _is_round), fields)) => {
239 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 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::EnumVariantFrom(l_value, r_value) |
261 SeqKind::EnumVariantTo(l_value, r_value) |
262 SeqKind::EnumVariantDrop(l_value, r_value) => {
263 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 quote!(&*#field_path)
271 }
272 SeqKind::Obj => {
273 DictionaryName::Obj.to_token_stream()
275 },
276 SeqKind::StructDropBody((_, items)) => {
277 let destructors = items.present(source);
279 quote! {
280 let ffi_ref = self;
281 #destructors
282 }
283 },
284 SeqKind::DropCode((_, items)) => {
285 let destructors = items.present(source);
287 quote!({ #destructors })
288 }
289 };
290 result
292 }
293}