Skip to main content

melodium_macro/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("../README.md")]
3
4mod data_traits;
5
6use convert_case::{Case, Casing};
7use core::{borrow::Borrow, convert::TryFrom, iter::FromIterator, slice::Iter};
8use data_traits::data_traits;
9use litrs::StringLit;
10use proc_macro::TokenStream;
11use proc_macro2::{token_stream::IntoIter as IntoIterTokenStream, TokenTree};
12use quote::quote;
13use std::collections::HashMap;
14use syn::{
15    parse, parse_file, Fields, FnArg, GenericArgument, Item, ItemFn, ItemStruct, Pat,
16    PathArguments, ReturnType, Type,
17};
18
19fn into_mel_type(ty: &Type) -> Vec<String> {
20    match ty {
21        Type::Path(path) => {
22            let ty = path.path.segments.first().expect("Type expected");
23
24            let text_ty = ty.ident.to_string();
25            let mut desc = Vec::new();
26            desc.push(text_ty.clone());
27            match text_ty.as_str() {
28                "Vec" | "Option" => {
29                    if let PathArguments::AngleBracketed(ab) = &ty.arguments {
30                        if let GenericArgument::Type(ty) = ab.args.first().expect("Type expected") {
31                            desc.append(&mut into_mel_type(ty));
32                        } else {
33                            panic!("Type expected");
34                        }
35                    } else {
36                        panic!("Type expected");
37                    }
38                }
39                _ => {}
40            }
41
42            desc
43        }
44        _ => {
45            panic!("Type expected");
46        }
47    }
48}
49
50fn into_mel_datatype(ty: &Vec<String>) -> String {
51    fn write_datatype(iter: &mut Iter<String>) -> String {
52        let mut desc = String::new();
53        if let Some(ty) = iter.next() {
54            match ty.as_str() {
55                "byte" | "bool" | "void" | "char" | "string" | "f32" | "f64" | "u8" | "u16"
56                | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" | "i128" => {
57                    desc.push_str("melodium_core::common::descriptor::DataType::");
58                    desc.push_str(&ty.to_case(Case::UpperCamel));
59                }
60                "Vec" | "Option" => {
61                    desc.push_str("melodium_core::common::descriptor::DataType::");
62                    desc.push_str(ty.as_str());
63                    desc.push_str("(Box::new(");
64                    desc.push_str(&write_datatype(iter));
65                    desc.push_str("))");
66                }
67                data => {
68                    desc.push_str(
69                        r#"melodium_core::common::descriptor::DataType::Data(__mel_data_"#,
70                    );
71                    desc.push_str(data);
72                    desc.push_str(r#"::descriptor())"#);
73                }
74            }
75        }
76        desc
77    }
78
79    write_datatype(&mut ty.iter())
80}
81
82fn into_mel_described_type(ty: &Vec<String>, generics: &Vec<String>) -> String {
83    fn write_described_type(iter: &mut Iter<String>, generics: Vec<&str>) -> String {
84        let mut desc = String::new();
85        if let Some(ty) = iter.next() {
86            match ty.as_str() {
87                "byte" | "bool" | "void" | "char" | "string" | "f32" | "f64" | "u8" | "u16"
88                | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" | "i128" => {
89                    desc.push_str("melodium_core::common::descriptor::DescribedType::");
90                    desc.push_str(&ty.to_case(Case::UpperCamel));
91                }
92                "Vec" | "Option" => {
93                    desc.push_str("melodium_core::common::descriptor::DescribedType::");
94                    desc.push_str(ty.as_str());
95                    desc.push_str("(Box::new(");
96                    desc.push_str(&write_described_type(iter, generics));
97                    desc.push_str("))");
98                }
99                generic if generics.contains(&generic) => {
100                    desc.push_str(r#"melodium_core::common::descriptor::DescribedType::Generic(Box::new(melodium_core::common::descriptor::Generic::new(""#);
101                    desc.push_str(generic);
102                    desc.push_str(r#"".to_string(), Vec::new())))"#);
103                }
104                data => {
105                    desc.push_str(r#"melodium_core::common::descriptor::DescribedType::Data(Box::new(__mel_data_"#);
106                    desc.push_str(data);
107                    desc.push_str(r#"::descriptor()))"#);
108                }
109            }
110        }
111        desc
112    }
113
114    write_described_type(
115        &mut ty.iter(),
116        generics.iter().map(|s| s.as_str()).collect(),
117    )
118}
119
120fn into_rust_type(ty: &Vec<String>, as_dyn_if_data: bool) -> String {
121    fn add_type(iter: &mut Iter<String>, as_dyn_if_data: bool) -> String {
122        let mut desc = String::new();
123        if let Some(ty) = iter.next() {
124            match ty.as_str() {
125                "byte" | "bool" | "void" | "char" | "string" | "f32" | "f64" | "u8" | "u16"
126                | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" | "i128" | "Vec"
127                | "Option" => {
128                    desc.push_str(ty);
129                }
130                data => {
131                    desc.push_str("std::sync::Arc<");
132
133                    if as_dyn_if_data {
134                        desc.push_str("dyn melodium_core::common::executive::Data");
135                    } else {
136                        desc.push_str(data);
137                    }
138                    desc.push_str(">");
139                }
140            }
141
142            let next = add_type(iter, as_dyn_if_data);
143            if !next.is_empty() {
144                desc.push('<');
145                desc.push_str(&next);
146                desc.push('>');
147            }
148        }
149        desc
150    }
151
152    add_type(&mut ty.iter(), as_dyn_if_data)
153}
154
155fn into_rust_value(ty: &Vec<String>, lit: &str) -> String {
156    fn add_value(iter: &mut Iter<String>, lit: &str) -> String {
157        let mut desc = String::new();
158        if let Some(ty) = iter.next() {
159            match ty.as_str() {
160                "Vec" => {
161                    desc.push_str("melodium_core::common::executive::Value::Vec(vec![");
162                    let next = add_value(iter, lit);
163                    if !next.is_empty() {
164                        desc.push_str(&next);
165                    }
166                    desc.push_str("])");
167                }
168                "Option" => {
169                    let next = add_value(iter, lit);
170                    if !next.is_empty() {
171                        desc.push_str(
172                            "melodium_core::common::executive::Value::Option(Some(Box::new(",
173                        );
174                        desc.push_str(&next);
175                        desc.push_str(")))");
176                    } else {
177                        desc.push_str(
178                            "melodium_core::common::executive::Value::Option(Box::new(None))",
179                        );
180                    }
181                }
182                mel_ty => {
183                    desc.push_str("melodium_core::common::executive::Value::");
184                    desc.push_str(&mel_ty.to_case(Case::UpperCamel));
185                    desc.push('(');
186                    match mel_ty {
187                        "byte" => {
188                            desc.push_str(lit);
189                            desc.push_str("u8");
190                        }
191                        "f32" => {
192                            desc.push_str(lit);
193                            desc.push_str("f32");
194                        }
195                        "f64" => {
196                            desc.push_str(lit);
197                            desc.push_str("f64");
198                        }
199                        "string" => {
200                            desc.push_str(lit);
201                            desc.push_str(".to_string()");
202                        }
203                        _ => desc.push_str(lit),
204                    }
205                    desc.push(')');
206                }
207            }
208        }
209        desc
210    }
211
212    add_value(&mut ty.iter(), lit)
213}
214
215fn into_mel_value_call(ty: &Vec<String>, inner_param: String) -> String {
216    fn apply_ops(mut iter: &mut Iter<String>) -> String {
217        if let Some(step) = iter.next() {
218            match step.as_str() {
219                "byte" | "bool" | "void" | "char" | "string" | "f32" | "f64" | "u8" | "u16"
220                | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" | "i128" => "".to_string(),
221                "Vec" => format!(
222                    ".into_iter().map(|v| v{}).collect::<Vec<_>>()",
223                    apply_ops(&mut iter)
224                ),
225                "Option" => format!(".map(|v| v{})", apply_ops(&mut iter)),
226                _ => ".downcast_arc().unwrap()".to_string(),
227            }
228        } else {
229            "".to_string()
230        }
231    }
232
233    format!(
234        "melodium_core::common::executive::GetData::<{}>::try_data({inner_param}).unwrap(){}",
235        into_rust_type(ty, true),
236        apply_ops(&mut ty.iter()),
237    )
238}
239
240fn convert_to_mel_value(ty: &Vec<String>, generics: &Vec<String>, call: &str) -> String {
241    fn conv_value(iter: &mut Iter<String>, generics: &Vec<&str>) -> String {
242        let conv;
243        if let Some(ty) = iter.next() {
244            match ty.as_str() {
245                "byte" | "bool" | "void" | "char" | "string" | "f32" | "f64" | "u8" | "u16"
246                | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" | "i128" => {
247                    conv = format!(
248                        "melodium_core::Value::{}(value)",
249                        ty.to_case(Case::UpperCamel)
250                    )
251                }
252                "Vec" => {
253                    let deeper = conv_value(iter, generics);
254                    conv = format!(
255                        "melodium_core::Value::Vec(value.into_iter().map(|value| {deeper}).collect())"
256                    )
257                }
258                "Option" => {
259                    let deeper = conv_value(iter, generics);
260                    conv = format!("value.map(|value| {deeper}).into()")
261                }
262                generic if generics.contains(&generic) => conv = "value".to_string(),
263                _data => {
264                    conv = "melodium_core::Value::Data(std::sync::Arc::new(value) as std::sync::Arc<dyn melodium_core::Data>)"
265                        .to_string()
266                }
267            }
268        } else {
269            panic!("Deeper type expected")
270        }
271        conv
272    }
273
274    format!(
275        "{{let value = {call}; {}}}",
276        conv_value(
277            &mut ty.iter(),
278            &generics.iter().map(|s| s.as_str()).collect()
279        )
280    )
281}
282
283fn convert_to_rust_value(ty: &Vec<String>, generics: &Vec<String>, call: &str) -> String {
284    fn conv_value(iter: &mut Iter<String>, generics: &Vec<&str>) -> String {
285        let conv;
286        if let Some(ty) = iter.next() {
287            match ty.as_str() {
288            "byte" | "bool" | "void" | "char" | "string" | "f32" | "f64" | "u8" | "u16"
289                | "u32" | "u64" | "u128" | "i8" | "i16" | "i32" | "i64" | "i128" => {
290                    conv = format!(
291                        "melodium_core::common::executive::GetData::<{ty}>::try_data(value).unwrap()"
292                    )
293                },
294            "Vec" => {
295                let deeper = conv_value(iter, generics);
296                conv = format!(r#"match value {{
297                    melodium_core::common::executive::Value::Vec(value) => {{
298                        value.into_iter().map(|value| {{
299                            {deeper}
300                        }}).collect::<Vec<_>>()
301                    }}
302                    _ => panic!("Invalid type")
303                }}"#)
304                },
305            "Option" => {
306                    let deeper = conv_value(iter, generics);
307                    conv = format!(
308                    r#"match value {{
309                        melodium_core::common::executive::Value::Option(value) => {{
310                            value.map(|value| {{ let value = *value; {deeper} }})
311                        }}
312                        _ => panic!("Invalid type")
313                    }}"#);
314                },
315            generic if generics.contains(&generic) => {
316                conv = "value".to_string();
317            }
318            _ => {
319                conv = "std::sync::Arc::unwrap_or_clone(melodium_core::common::executive::GetData::<std::sync::Arc<dyn melodium_core::Data>>::try_data(value).unwrap().downcast_arc().unwrap())".to_string()
320            }
321            }
322        } else {
323            panic!("Deeper type expected")
324        }
325        conv
326    }
327
328    format!(
329        "{{ let value = {call}; {} }}",
330        conv_value(
331            &mut ty.iter(),
332            &generics.iter().map(|s| s.as_str()).collect()
333        )
334    )
335}
336
337fn config_default(ts: &mut IntoIterTokenStream) -> (String, String) {
338    if let Some(TokenTree::Ident(name)) = ts.next() {
339        (name.to_string(), config_value(ts))
340    } else {
341        panic!("Name identity expected")
342    }
343}
344
345fn config_param(
346    ts: &mut IntoIterTokenStream,
347) -> (String, Vec<String>, Option<String>, HashMap<String, String>) {
348    let mut next = ts.next();
349    let attributes;
350    if let Some(TokenTree::Group(attrs)) = next {
351        attributes = config_attributes(&mut attrs.stream().into_iter());
352        next = ts.next();
353    } else {
354        attributes = HashMap::new();
355    }
356
357    if let Some(TokenTree::Ident(name)) = next {
358        (
359            name.to_string(),
360            config_ty(ts),
361            config_optional_value(ts),
362            attributes,
363        )
364    } else {
365        panic!(
366            "Name identity expected, found: {}",
367            next.unwrap().to_string()
368        )
369    }
370}
371
372fn config_full_source(
373    ts: &mut IntoIterTokenStream,
374) -> (
375    String,
376    Vec<String>,
377    HashMap<String, (Vec<String>, Option<String>, HashMap<String, String>)>,
378    Vec<(String, String, Vec<String>, HashMap<String, String>)>,
379    HashMap<String, String>,
380) {
381    let mut next = ts.next();
382    let attributes;
383    if let Some(TokenTree::Group(attrs)) = next {
384        attributes = config_attributes(&mut attrs.stream().into_iter());
385        next = ts.next();
386    } else {
387        attributes = HashMap::new();
388    }
389    if let Some(TokenTree::Ident(name)) = next {
390        let mut contextes = Vec::new();
391        if let Some(TokenTree::Group(group)) = ts.next() {
392            for tt in group.stream() {
393                if let TokenTree::Ident(c) = tt {
394                    contextes.push(format!("__mel_context_{c}"))
395                } else if let TokenTree::Group(g) = tt {
396                    contextes.push(token_stream_to_context_address(g.stream()))
397                } else {
398                    panic!("Context identity expected")
399                }
400            }
401        } else {
402            panic!("Context list expected")
403        }
404
405        let mut params = HashMap::new();
406        if let Some(TokenTree::Group(group)) = ts.next() {
407            let mut ts = group.stream().into_iter();
408
409            while let Some(TokenTree::Ident(id)) = ts.next() {
410                let qualif = id.to_string();
411                match qualif.as_str() {
412                    "param" => {
413                        let param = config_param(&mut ts);
414                        params.insert(param.0, (param.1, param.2, param.3));
415                    }
416                    _ => panic!("Unrecognized source parameter configuration"),
417                }
418            }
419        } else {
420            panic!("Parameters list expected")
421        }
422
423        let mut outputs = Vec::new();
424        if let Some(TokenTree::Group(group)) = ts.next() {
425            let mut ts = group.stream().into_iter();
426            loop {
427                if let Some(output) = config_io(&mut ts) {
428                    outputs.push(output);
429                } else {
430                    break;
431                }
432            }
433        } else {
434            panic!("Outputs list expected")
435        }
436
437        (name.to_string(), contextes, params, outputs, attributes)
438    } else {
439        panic!("Name identity expected")
440    }
441}
442
443fn token_stream_to_context_address(ts: proc_macro2::TokenStream) -> String {
444    let full_address = ts.to_string().replace(" ", "");
445    let mut steps = full_address
446        .split("::")
447        .map(|s| s.to_string())
448        .collect::<Vec<_>>();
449    if let Some(last) = steps.pop() {
450        steps.push(format!("__mel_context_{last}"));
451    } else {
452        panic!("Wrong context address")
453    }
454    steps.join("::")
455}
456
457fn config_value(ts: &mut IntoIterTokenStream) -> String {
458    let next = ts.next();
459    if let Some(TokenTree::Literal(default)) = next {
460        default.to_string()
461    } else if let Some(TokenTree::Ident(ident)) = next {
462        ident.to_string()
463    } else if let Some(TokenTree::Punct(punct)) = next {
464        match punct.as_char() {
465            '-' => {
466                if let Some(TokenTree::Literal(default)) = ts.next() {
467                    format!("-{}", default.to_string())
468                } else {
469                    panic!("Default value expected")
470                }
471            }
472            _ => panic!("Unexpected punctuation"),
473        }
474    } else {
475        panic!("Default value expected")
476    }
477}
478
479fn config_optional_value(ts: &mut IntoIterTokenStream) -> Option<String> {
480    let next = ts.next();
481    if let Some(TokenTree::Literal(default)) = next {
482        Some(default.to_string())
483    } else if let Some(TokenTree::Punct(punct)) = next {
484        match punct.as_char() {
485            '-' => {
486                if let Some(TokenTree::Literal(default)) = ts.next() {
487                    Some(format!("-{}", default.to_string()))
488                } else {
489                    panic!("Default value expected")
490                }
491            }
492            _ => panic!("Unexpected punctuation"),
493        }
494    } else if let Some(TokenTree::Ident(ident)) = next {
495        if ident.to_string() == "none" {
496            None
497        } else if ident.to_string() == "true" || ident.to_string() == "false" {
498            Some(ident.to_string())
499        } else {
500            panic!("Unrecognized default value")
501        }
502    } else {
503        panic!("Default value expected")
504    }
505}
506
507fn config_model(ts: &mut IntoIterTokenStream) -> (String, String) {
508    if let Some(TokenTree::Ident(name)) = ts.next() {
509        let next = ts.next();
510        if let Some(TokenTree::Ident(ty)) = next {
511            (name.to_string(), format!("__mel_model_{ty}"))
512        } else if let Some(TokenTree::Group(group)) = next {
513            (
514                name.to_string(),
515                token_stream_to_model_address(group.stream()),
516            )
517        } else {
518            panic!("Type identity expected")
519        }
520    } else {
521        panic!("Name identity expected")
522    }
523}
524
525fn config_source(ts: &mut IntoIterTokenStream) -> (String, String, String) {
526    if let Some(TokenTree::Ident(name)) = ts.next() {
527        let next = ts.next();
528        if let Some(TokenTree::Ident(ty)) = next {
529            if let Some(TokenTree::Ident(source)) = ts.next() {
530                (
531                    name.to_string(),
532                    format!("__mel_model_{ty}"),
533                    source.to_string(),
534                )
535            } else {
536                panic!("Source identity expected")
537            }
538        } else if let Some(TokenTree::Group(group)) = next {
539            if let Some(TokenTree::Ident(source)) = ts.next() {
540                (
541                    name.to_string(),
542                    token_stream_to_model_address(group.stream()),
543                    source.to_string(),
544                )
545            } else {
546                panic!("Source identity expected")
547            }
548        } else {
549            panic!("Type identity expected")
550        }
551    } else {
552        panic!("Name identity expected")
553    }
554}
555
556fn token_stream_to_model_address(ts: proc_macro2::TokenStream) -> String {
557    let full_address = ts.to_string().replace(" ", "");
558    let mut steps = full_address
559        .split("::")
560        .map(|s| s.to_string())
561        .collect::<Vec<_>>();
562    if let Some(last) = steps.pop() {
563        steps.push(format!("__mel_model_{last}"));
564    } else {
565        panic!("Wrong model address")
566    }
567    steps.join("::")
568}
569
570fn config_ty(mut ts: &mut IntoIterTokenStream) -> Vec<String> {
571    let mut list = Vec::new();
572    if let Some(TokenTree::Ident(ty)) = ts.next() {
573        let ty = ty.to_string();
574        list.push(ty.clone());
575        match ty.as_str() {
576            "Vec" | "Option" => {
577                ts.next(); // <
578                list.append(&mut config_ty(&mut ts));
579                ts.next(); // >
580            }
581            _ => {}
582        }
583    } else {
584        panic!("Type identity expected")
585    }
586    list
587}
588
589fn config_io(
590    ts: &mut IntoIterTokenStream,
591) -> Option<(String, String, Vec<String>, HashMap<String, String>)> {
592    let mut next = ts.next();
593    let attributes;
594    if let Some(TokenTree::Group(attrs)) = next {
595        attributes = config_attributes(&mut attrs.stream().into_iter());
596        next = ts.next();
597    } else {
598        attributes = HashMap::new();
599    }
600    if let Some(TokenTree::Ident(name)) = next {
601        if let Some(TokenTree::Ident(flow)) = ts.next() {
602            ts.next(); // <
603
604            let mel_ty = config_ty(ts);
605
606            ts.next(); // >
607            Some((name.to_string(), flow.to_string(), mel_ty, attributes))
608        } else {
609            panic!("Flow identity expected")
610        }
611    } else {
612        None
613    }
614}
615
616fn config_attributes(ts: &mut IntoIterTokenStream) -> HashMap<String, String> {
617    let mut attributes = HashMap::new();
618    while let Some(next) = ts.next() {
619        if let TokenTree::Ident(name) = next {
620            ts.next(); // (
621
622            let mut attribute = String::new();
623            while let Some(next) = ts.next() {
624                if let TokenTree::Punct(punct) = &next {
625                    if punct.as_char() == ')' {
626                        break;
627                    }
628                }
629                attribute.push_str(&next.to_string());
630            }
631            attributes.insert(name.to_string(), attribute);
632        }
633    }
634
635    attributes
636}
637
638fn config_attribute(ts: &mut IntoIterTokenStream) -> (String, String) {
639    if let Some(TokenTree::Ident(name)) = ts.next() {
640        ts.next(); // (
641
642        let mut attribute = String::new();
643        while let Some(next) = ts.next() {
644            if let TokenTree::Punct(punct) = &next {
645                if punct.as_char() == ')' {
646                    break;
647                }
648            }
649            attribute.push_str(&next.to_string());
650        }
651        (name.to_string(), attribute)
652    } else {
653        panic!("Name identity expected")
654    }
655}
656
657fn config_generic(mut ts: &mut IntoIterTokenStream) -> (String, Vec<String>) {
658    if let Some(TokenTree::Ident(name)) = ts.next() {
659        let name = name.to_string();
660
661        (name, config_traits(&mut ts))
662    } else {
663        panic!("Name identity expected")
664    }
665}
666
667fn config_traits(ts: &mut IntoIterTokenStream) -> Vec<String> {
668    if let Some(TokenTree::Group(group)) = ts.next() {
669        group
670            .stream()
671            .into_iter()
672            .map(|tt| {
673                if let TokenTree::Ident(trait_name) = tt {
674                    trait_name.to_string()
675                } else {
676                    panic!("Expecting trait name")
677                }
678            })
679            .collect()
680    } else {
681        panic!("Trait list expected")
682    }
683}
684
685#[proc_macro]
686pub fn mel_package(_: TokenStream) -> TokenStream {
687    let mut functions = Vec::new();
688    let mut contexts = Vec::new();
689    let mut models = Vec::new();
690    let mut sources = Vec::new();
691    let mut treatments = Vec::new();
692    let mut types = Vec::new();
693
694    let mut root = std::env::var("CARGO_MANIFEST_DIR").unwrap();
695    root.push_str("/src/");
696    root = root.replace("/", &std::path::MAIN_SEPARATOR.to_string());
697    for entry in glob::glob(&format!("{root}**/*.rs")).unwrap() {
698        match &entry {
699            Ok(path) => {
700                if let Ok(content) = parse_file(&std::fs::read_to_string(path).unwrap()) {
701                    for item in &content.items {
702                        let name;
703                        let mut is_mel_function = false;
704                        let mut is_mel_treatment = false;
705                        let mut is_mel_model = false;
706                        let mut is_mel_context = false;
707                        let mut is_mel_data = false;
708                        match item {
709                            Item::Fn(item_fn) => {
710                                name = item_fn.sig.ident.to_string();
711
712                                item_fn.attrs.iter().for_each(|attr| {
713                                    match attr
714                                        .path
715                                        .segments
716                                        .first()
717                                        .unwrap()
718                                        .ident
719                                        .to_string()
720                                        .as_str()
721                                    {
722                                        "mel_function" => is_mel_function = true,
723                                        "mel_treatment" => is_mel_treatment = true,
724                                        _ => {}
725                                    }
726                                });
727                            }
728                            Item::Struct(item_struct) => {
729                                name = item_struct.ident.to_string();
730
731                                item_struct.attrs.iter().for_each(|attr| {
732                                    match attr
733                                        .path
734                                        .segments
735                                        .first()
736                                        .unwrap()
737                                        .ident
738                                        .to_string()
739                                        .as_str()
740                                    {
741                                        "mel_model" => is_mel_model = true,
742                                        "mel_context" => is_mel_context = true,
743                                        "mel_data" => is_mel_data = true,
744                                        _ => {}
745                                    }
746                                });
747                            }
748                            _ => continue,
749                        }
750
751                        let mut call = path
752                            .to_str()
753                            .unwrap()
754                            .strip_prefix(&root)
755                            .unwrap()
756                            .strip_suffix(".rs")
757                            .unwrap()
758                            .replace(std::path::MAIN_SEPARATOR, "::");
759
760                        if call == "lib" {
761                            call = "".to_string();
762                        } else {
763                            call = format!("::{call}");
764                        }
765
766                        if call.ends_with("::mod") {
767                            call = call.strip_suffix("::mod").unwrap().to_string();
768                        }
769
770                        if is_mel_function {
771                            call.push_str(&format!("::__mel_function_{name}::descriptor()"));
772                            functions.push(call);
773                        } else if is_mel_treatment {
774                            call.push_str(&format!("::__mel_treatment_{name}::descriptor()"));
775                            treatments.push(call);
776                        } else if is_mel_model {
777                            let mut model_call = call.clone();
778                            model_call.push_str(&format!("::__mel_model_{name}::descriptor()"));
779                            models.push(model_call);
780                            let mut sources_call = call.clone();
781                            sources_call.push_str(&format!("::__mel_model_{name}::sources()"));
782                            sources.push(sources_call);
783                        } else if is_mel_context {
784                            call.push_str(&format!("::__mel_context_{name}::descriptor()"));
785                            contexts.push(call);
786                        } else if is_mel_data {
787                            call.push_str(&format!("::__mel_data_{name}::descriptor()"));
788                            types.push(call);
789                        }
790                    }
791                }
792            }
793            _ => {}
794        }
795    }
796
797    let functions = functions
798        .iter()
799        .map(|elmt| {
800            format!(
801                "collection.insert(melodium_core::common::descriptor::Entry::Function(crate{elmt}));"
802            )
803        })
804        .collect::<Vec<_>>()
805        .join("\n");
806
807    let contexts = contexts
808        .iter()
809        .map(|elmt| {
810            format!("collection.insert(melodium_core::common::descriptor::Entry::Context(crate{elmt}));")
811        })
812        .collect::<Vec<_>>()
813        .join("\n");
814
815    let models = models
816        .iter()
817        .map(|elmt| {
818            format!(
819                "collection.insert(melodium_core::common::descriptor::Entry::Model(crate{elmt}));"
820            )
821        })
822        .collect::<Vec<_>>()
823        .join("\n");
824
825    let sources = sources
826    .iter()
827    .map(|elmt| format!(
828        "crate{elmt}.into_iter().for_each(|s| collection.insert(melodium_core::common::descriptor::Entry::Treatment(s)));"
829    ))
830    .collect::<Vec<_>>()
831    .join("\n");
832
833    let treatments = treatments
834        .iter()
835        .map(|elmt| {
836            format!(
837                "collection.insert(melodium_core::common::descriptor::Entry::Treatment(crate{elmt}));"
838            )
839        })
840        .collect::<Vec<_>>()
841        .join("\n");
842
843    let types = types
844        .iter()
845        .map(|elmt| {
846            format!(
847                "collection.insert(melodium_core::common::descriptor::Entry::Data(crate{elmt}));"
848            )
849        })
850        .collect::<Vec<_>>()
851        .join("\n");
852
853    let collection: proc_macro2::TokenStream = format!(
854        r"
855            let mut collection = melodium_core::common::descriptor::Collection::new();
856            {types}
857            {functions}
858            {contexts}
859            {models}
860            {sources}
861            {treatments}
862            collection
863        "
864    )
865    .parse()
866    .unwrap();
867
868    let cargo_toml: toml::Table = toml::from_str(
869        &std::fs::read_to_string(&format!(
870            "{}/Cargo.toml",
871            std::env::var("CARGO_MANIFEST_DIR").unwrap()
872        ))
873        .unwrap(),
874    )
875    .unwrap();
876    let name = cargo_toml
877        .get("package")
878        .and_then(|v| {
879            if let toml::Value::Table(pkg) = v {
880                Some(pkg)
881            } else {
882                None
883            }
884        })
885        .unwrap()
886        .get("name")
887        .and_then(|v| {
888            if let toml::Value::String(s) = v {
889                Some(s)
890            } else {
891                None
892            }
893        })
894        .unwrap()
895        .strip_suffix("-mel")
896        .unwrap()
897        .to_string();
898
899    let requirements: proc_macro2::TokenStream = cargo_toml
900        .get("dependencies")
901        .and_then(|v| {
902            if let toml::Value::Table(deps) = v {
903                Some(deps)
904            } else {
905                None
906            }
907        })
908        .unwrap()
909        .iter()
910        .filter_map(|(k, v)| {
911            if let (Some(mel_pkg), Some(version)) = (k.strip_suffix("-mel"), v.as_table().and_then(|t| t.get("version").and_then(|v| v.as_str()))) {
912                Some(format!(r#"melodium_core::common::descriptor::PackageRequirement{{package:"{mel_pkg}".to_string(),version_requirement:melodium_core::common::descriptor::VersionReq::parse("{version}").unwrap()}}"#))
913            } else { None }
914        })
915        .collect::<Vec<_>>()
916        .join(",")
917        .parse()
918        .unwrap();
919
920    let mut embedded = Vec::new();
921    let mut root = std::env::var("CARGO_MANIFEST_DIR").unwrap();
922    root.push_str("/mel/");
923    root = root.replace("/", &std::path::MAIN_SEPARATOR.to_string());
924    for entry in glob::glob(&format!("{root}**/*.mel")).unwrap() {
925        match &entry {
926            Ok(path) => {
927                let plat_name = path.to_string_lossy().to_string();
928                let mel_name = plat_name
929                    .strip_prefix(&root)
930                    .unwrap()
931                    .replace(std::path::MAIN_SEPARATOR, "/");
932                embedded.push((plat_name, mel_name))
933            }
934            _ => {}
935        }
936    }
937
938    let embedded: proc_macro2::TokenStream = embedded
939        .into_iter()
940        .map(|(path, filename)| {
941            format!(r#"embedded.insert("{name}/{filename}", &include_bytes!(r"{path}")[..])"#)
942        })
943        .collect::<Vec<_>>()
944        .join(";")
945        .parse()
946        .unwrap();
947
948    let expanded = quote! {
949
950        #[no_mangle]
951        #[cfg(feature = "plugin")]
952        pub extern "C" fn melodium_package() -> *const melodium_core::common::descriptor::Package {
953            std::sync::Arc::into_raw(__mel_package::package())
954        }
955
956        pub mod __mel_package {
957
958            static NAME: &str = #name;
959            static VERSION: melodium_core::Lazy<melodium_core::common::descriptor::Version> = melodium_core::Lazy::new(|| melodium_core::common::descriptor::Version::parse(env!("CARGO_PKG_VERSION")).unwrap());
960            static REQUIREMENTS: melodium_core::Lazy<Vec<melodium_core::common::descriptor::PackageRequirement>> = melodium_core::Lazy::new(|| { vec![#requirements] });
961            static EMBEDDED: melodium_core::Lazy<std::collections::HashMap<&'static str, &'static [u8]>> = melodium_core::Lazy::new(|| { let mut embedded = std::collections::HashMap::new(); #embedded; embedded });
962
963            pub fn package() -> std::sync::Arc<dyn melodium_core::common::descriptor::Package> {
964                std::sync::Arc::new(MelPackage::new())
965            }
966
967            #[derive(Debug)]
968            pub struct MelPackage {}
969
970            impl MelPackage {
971                pub fn new() -> Self {
972                    Self {}
973                }
974
975                pub fn collection(&self) -> melodium_core::common::descriptor::Collection {
976                    #collection
977                }
978            }
979
980            impl melodium_core::common::descriptor::Package for MelPackage {
981                fn name(&self) -> &str {
982                    NAME
983                }
984
985                fn version(&self) -> &melodium_core::common::descriptor::Version {
986                    &VERSION
987                }
988
989                fn requirements(&self) -> &Vec<melodium_core::common::descriptor::PackageRequirement> {
990                    &REQUIREMENTS
991                }
992
993                fn collection(&self, _: &dyn melodium_core::common::descriptor::Loader) -> melodium_core::common::descriptor::LoadingResult<melodium_core::common::descriptor::Collection> {
994                    melodium_core::common::descriptor::LoadingResult::new_success(MelPackage::collection(&self))
995                }
996
997                fn embedded(&self) -> &std::collections::HashMap<&'static str, &'static [u8]> {
998                    &EMBEDDED
999                }
1000            }
1001        }
1002
1003    };
1004
1005    TokenStream::from(expanded)
1006}
1007
1008#[proc_macro_attribute]
1009pub fn mel_treatment(attr: TokenStream, item: TokenStream) -> TokenStream {
1010    let mut defaults = HashMap::new();
1011    let mut models = HashMap::new();
1012    let mut inputs = HashMap::new();
1013    let mut outputs = HashMap::new();
1014    let mut attributes = HashMap::new();
1015    let mut generics = Vec::new();
1016
1017    let mut iter_attr = Into::<proc_macro2::TokenStream>::into(attr).into_iter();
1018    while let Some(tt) = iter_attr.next() {
1019        if let TokenTree::Ident(id) = tt {
1020            let qualif = id.to_string();
1021            match qualif.as_str() {
1022                "default" => {
1023                    let (param, default_val) = config_default(&mut iter_attr);
1024                    defaults.insert(param, default_val);
1025                }
1026                "model" => {
1027                    let (name, ident) = config_model(&mut iter_attr);
1028                    models.insert(name, (ident, None));
1029                }
1030                "source" => {
1031                    let (name, ident, source) = config_source(&mut iter_attr);
1032                    models.insert(name, (ident, Some(source)));
1033                }
1034                "input" => {
1035                    let (name, flow, ty, attributes) =
1036                        config_io(&mut iter_attr).expect("Name identity expected");
1037                    inputs.insert(name, (flow, ty, attributes));
1038                }
1039                "output" => {
1040                    let (name, flow, ty, attributes) =
1041                        config_io(&mut iter_attr).expect("Name identity expected");
1042                    outputs.insert(name, (flow, ty, attributes));
1043                }
1044                "attribute" => {
1045                    let (name, value) = config_attribute(&mut iter_attr);
1046                    attributes.insert(name, value);
1047                }
1048                "generic" => {
1049                    let name = config_generic(&mut iter_attr);
1050                    generics.push(name);
1051                }
1052                _ => panic!("Unrecognized configuration"),
1053            }
1054        }
1055    }
1056    let generics_list = generics
1057        .iter()
1058        .map(|(gen, _)| gen.clone())
1059        .collect::<Vec<_>>();
1060
1061    let treatment: ItemFn = parse(item).unwrap();
1062    if treatment.sig.asyncness.is_none() {
1063        panic!("Treatments must be async");
1064    }
1065    let mut documentation = Vec::new();
1066    for attr in treatment.attrs.clone() {
1067        if let Some(segment) = attr.path.segments.first() {
1068            if segment.ident.to_string() == "doc" {
1069                for tt in attr.tokens {
1070                    if let TokenTree::Literal(lit) = tt {
1071                        let doclit = StringLit::try_from(lit).unwrap();
1072                        documentation.push(doclit.value().to_string());
1073                    }
1074                }
1075            }
1076        }
1077    }
1078
1079    let name = treatment.sig.ident.to_string();
1080    let mut params = HashMap::new();
1081    for arg in &treatment.sig.inputs {
1082        match arg {
1083            FnArg::Typed(t) => {
1084                let name = if let Pat::Ident(ident) = t.pat.borrow() {
1085                    ident.ident.to_string()
1086                } else {
1087                    eprintln!("Argument name expected");
1088                    break;
1089                };
1090
1091                let attributes = t
1092                    .attrs
1093                    .iter()
1094                    .filter_map(|attr| {
1095                        if let Some(name) = attr.path.get_ident() {
1096                            if name.to_string() == "mel" {
1097                                Some(config_attributes(&mut attr.tokens.clone().into_iter()))
1098                            } else {
1099                                None
1100                            }
1101                        } else {
1102                            None
1103                        }
1104                    })
1105                    .fold(HashMap::new(), |mut acc, attrs| {
1106                        for attr in attrs {
1107                            acc.insert(attr.0, attr.1);
1108                        }
1109                        acc
1110                    });
1111
1112                let ty = into_mel_type(t.ty.borrow());
1113
1114                params.insert(name, (ty, attributes));
1115            }
1116            _ => eprintln!("Only Mélodium types are admissible arguments"),
1117        }
1118    }
1119
1120    let description;
1121    {
1122        let documentation = documentation.join("\n");
1123        let attributes: proc_macro2::TokenStream = attributes
1124            .iter()
1125            .map(|(name, value)| {
1126                format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)
1127            })
1128            .collect::<Vec<_>>()
1129            .join(";")
1130            .parse()
1131            .unwrap();
1132        let generics: proc_macro2::TokenStream = generics
1133            .iter()
1134            .map(|(name, traits)| format!(r#"melodium_core::common::descriptor::Generic::new("{name}".to_string(), vec![{}])"#, traits.iter().map(|tr| format!("melodium_core::common::descriptor::DataTrait::{tr}")).collect::<Vec<_>>().join(", ")))
1135            .collect::<Vec<_>>()
1136            .join(",")
1137            .parse()
1138            .unwrap();
1139        let parameters: proc_macro2::TokenStream = params.iter().map(|(name, (ty, attributes))| {
1140            let described_type = into_mel_described_type(ty, &generics_list);
1141            let default = defaults.get(name).map(|lit| format!("Some({val})", val = into_rust_value(ty, lit))).unwrap_or_else(|| String::from("None"));
1142            let attributes = attributes.iter().map(|(name, value)| format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)).collect::<Vec<_>>().join(";");
1143            format!(
1144                r#"melodium_core::common::descriptor::Parameter::new("{name}", melodium_core::common::descriptor::Variability::Var, {described_type}, {default}, {{let mut attrs = melodium_core::common::descriptor::Attributes::new();{attributes};attrs}})"#
1145            )
1146        }).collect::<Vec<_>>().join(",").parse().unwrap();
1147        let inputs: proc_macro2::TokenStream = inputs.iter().map(|(name, (flow, ty, attributes))| {
1148            let described_type = into_mel_described_type(ty, &generics_list);
1149            let attributes = attributes.iter().map(|(name, value)| format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)).collect::<Vec<_>>().join(";");
1150            format!(r#"melodium_core::common::descriptor::Input::new("{name}", {described_type}, melodium_core::common::descriptor::Flow::{flow}, {{let mut attrs = melodium_core::common::descriptor::Attributes::new();{attributes};attrs}})"#)
1151        }).collect::<Vec<_>>().join(",").parse().unwrap();
1152        let outputs: proc_macro2::TokenStream = outputs.iter().map(|(name, (flow, ty, attributes))| {
1153            let described_type = into_mel_described_type(ty, &generics_list);
1154            let attributes = attributes.iter().map(|(name, value)| format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)).collect::<Vec<_>>().join(";");
1155            format!(r#"melodium_core::common::descriptor::Output::new("{name}", {described_type}, melodium_core::common::descriptor::Flow::{flow}, {{let mut attrs = melodium_core::common::descriptor::Attributes::new();{attributes};attrs}})"#)
1156        }).collect::<Vec<_>>().join(",").parse().unwrap();
1157        let sources: proc_macro2::TokenStream = models
1158            .iter()
1159            .filter(|(_, (_, source))| source.is_some())
1160            .map(|(name, (_, source))| {
1161                format!(
1162                    r#"("{name}".to_string(), vec!["{}".to_string()])"#,
1163                    source.as_ref().unwrap()
1164                )
1165            })
1166            .collect::<Vec<_>>()
1167            .join(",")
1168            .parse()
1169            .unwrap();
1170        let models: proc_macro2::TokenStream = models
1171            .iter()
1172            .map(|(name, (ident, _))| format!(r#"("{name}".to_string(), {ident}::descriptor())"#))
1173            .collect::<Vec<_>>()
1174            .join(",")
1175            .parse()
1176            .unwrap();
1177
1178        let element_name = name.to_case(Case::Camel);
1179
1180        description = quote! {
1181
1182            static DESCRIPTOR: std::sync::Mutex<Option<std::sync::Arc<melodium_core::descriptor::Treatment>>> = std::sync::Mutex::new(None);
1183
1184            pub fn identifier() -> melodium_core::common::descriptor::Identifier {
1185                melodium_core::descriptor::module_path_to_identifier(env!("CARGO_PKG_VERSION"), module_path!(), #element_name)
1186            }
1187
1188            pub fn descriptor() -> std::sync::Arc<melodium_core::descriptor::Treatment> {
1189                let mut desc = DESCRIPTOR.lock().unwrap();
1190                if let Some(desc) = &*desc {
1191                    std::sync::Arc::clone(&desc)
1192                }
1193                else {
1194
1195                    let new = melodium_core::descriptor::Treatment::new(
1196                        identifier(),
1197                        #documentation.to_string(),
1198                        {
1199                            let mut attrs = melodium_core::common::descriptor::Attributes::new();
1200                            #attributes;
1201                            attrs
1202                        },
1203                        vec![#generics],
1204                        vec![#models],
1205                        vec![#sources],
1206                        vec![#parameters],
1207                        vec![#inputs],
1208                        vec![#outputs],
1209                        AdHocTreatment::new
1210                    );
1211
1212                    *desc = Some(std::sync::Arc::clone(&new));
1213
1214                    new
1215                }
1216            }
1217        };
1218    }
1219
1220    let declaration;
1221    {
1222        let parameters: proc_macro2::TokenStream = params
1223            .iter()
1224            .map(|(name, (ty, _))| {
1225                if generics.iter().any(|(gen, _)| gen == ty.last().unwrap()) {
1226                    format!(r#"r#{name}: std::sync::Mutex<Option<melodium_core::common::executive::Value>>,"#)
1227                } else {
1228                    let rust_type = into_rust_type(ty, false);
1229                    format!(r#"r#{name}: std::sync::Mutex<Option<{rust_type}>>,"#)
1230                }
1231            })
1232            .collect::<Vec<_>>()
1233            .join("")
1234            .parse()
1235            .unwrap();
1236        let inputs: proc_macro2::TokenStream = inputs.iter().map(|(name, _)| {
1237            format!(r#"r#{name}: std::sync::Mutex<Option<Box<dyn melodium_core::common::executive::Input>>>,"#)
1238        }).collect::<Vec<_>>().join("").parse().unwrap();
1239        let outputs: proc_macro2::TokenStream = outputs.iter().map(|(name, _)| {
1240            format!(r#"r#{name}: std::sync::Mutex<Option<Box<dyn melodium_core::common::executive::Output>>>,"#)
1241        }).collect::<Vec<_>>().join("").parse().unwrap();
1242        let models: proc_macro2::TokenStream = models.iter().map(|(name, _)| {
1243            format!(r#"r#{name}: std::sync::Mutex<Option<std::sync::Arc<dyn melodium_core::common::executive::Model>>>,"#)
1244        }).collect::<Vec<_>>().join("").parse().unwrap();
1245        let generics:proc_macro2::TokenStream = generics.iter().map(|(name, _)| {
1246            format!(r#"#[allow(non_snake_case)] r#{name}: std::sync::Mutex<Option<melodium_core::common::descriptor::DataType>>,"#)
1247        }).collect::<Vec<_>>().join("").parse().unwrap();
1248
1249        declaration = quote! {
1250            #[derive(Debug)]
1251            pub struct AdHocTreatment {
1252                #models
1253                #generics
1254                #inputs
1255                #outputs
1256                #parameters
1257            }
1258        };
1259    }
1260
1261    let self_implementation;
1262    {
1263        let parameters: proc_macro2::TokenStream = params
1264            .iter()
1265            .map(|(name, (ty, _))| {
1266                let default = defaults
1267                    .get(name)
1268                    .map(|lit| {
1269                        if generics.iter().any(|(gen, _)| gen == ty.last().unwrap()) {
1270                            format!("Some({val})", val = into_rust_value(ty, lit))
1271                        } else {
1272                            format!(
1273                                "Some({call})",
1274                                call = into_mel_value_call(ty, into_rust_value(ty, lit)),
1275                            )
1276                        }
1277                    })
1278                    .unwrap_or_else(|| String::from("None"));
1279                format!(r#"r#{name}: std::sync::Mutex::new({default}),"#)
1280            })
1281            .collect::<Vec<_>>()
1282            .join("")
1283            .parse()
1284            .unwrap();
1285        let inputs: proc_macro2::TokenStream = inputs
1286            .iter()
1287            .map(|(name, _)| format!(r#"r#{name}: std::sync::Mutex::new(None),"#))
1288            .collect::<Vec<_>>()
1289            .join("")
1290            .parse()
1291            .unwrap();
1292        let outputs: proc_macro2::TokenStream = outputs
1293            .iter()
1294            .map(|(name, _)| format!(r#"r#{name}: std::sync::Mutex::new(None),"#))
1295            .collect::<Vec<_>>()
1296            .join("")
1297            .parse()
1298            .unwrap();
1299        let models: proc_macro2::TokenStream = models
1300            .iter()
1301            .map(|(name, _)| format!(r#"r#{name}: std::sync::Mutex::new(None),"#))
1302            .collect::<Vec<_>>()
1303            .join("")
1304            .parse()
1305            .unwrap();
1306        let generics: proc_macro2::TokenStream = generics
1307            .iter()
1308            .map(|(name, _)| format!(r#"r#{name}: std::sync::Mutex::new(None),"#))
1309            .collect::<Vec<_>>()
1310            .join("")
1311            .parse()
1312            .unwrap();
1313
1314        self_implementation = quote! {
1315            impl AdHocTreatment {
1316                pub fn new() -> std::sync::Arc<dyn melodium_core::common::executive::Treatment> {
1317                    std::sync::Arc::new(Self {
1318                        #parameters
1319                        #inputs
1320                        #outputs
1321                        #models
1322                        #generics
1323                    })
1324                }
1325            }
1326        };
1327    }
1328
1329    let trait_implementation;
1330    {
1331        let parameters: proc_macro2::TokenStream = params
1332            .iter()
1333            .map(|(name, (ty, _))| {
1334                if generics.iter().any(|(gen, _)| gen == ty.last().unwrap()) {
1335                    format!(r#""{name}" => *self.r#{name}.lock().unwrap() = Some(value),"#)
1336                } else {
1337                    let call = into_mel_value_call(ty, "value".to_string());
1338                    format!(r#""{name}" => *self.r#{name}.lock().unwrap() = Some({call}),"#)
1339                }
1340            })
1341            .collect::<Vec<_>>()
1342            .join("")
1343            .parse()
1344            .unwrap();
1345        let inputs: proc_macro2::TokenStream = inputs
1346            .iter()
1347            .map(|(name, _)| {
1348                format!(r#""{name}" => *self.r#{name}.lock().unwrap() = Some(transmitter),"#)
1349            })
1350            .collect::<Vec<_>>()
1351            .join("")
1352            .parse()
1353            .unwrap();
1354        let outputs: proc_macro2::TokenStream = outputs
1355            .iter()
1356            .map(|(name, _)| {
1357                format!(r#""{name}" => *self.r#{name}.lock().unwrap() = Some(transmitter),"#)
1358            })
1359            .collect::<Vec<_>>()
1360            .join("")
1361            .parse()
1362            .unwrap();
1363        let models: proc_macro2::TokenStream = models
1364            .iter()
1365            .map(|(name, _)| {
1366                format!(r#""{name}" => *self.r#{name}.lock().unwrap() = Some(model),"#)
1367            })
1368            .collect::<Vec<_>>()
1369            .join("")
1370            .parse()
1371            .unwrap();
1372        let generics: proc_macro2::TokenStream = generics
1373            .iter()
1374            .map(|(name, _)| {
1375                format!(r#""{name}" => *self.r#{name}.lock().unwrap() = Some(data_type),"#)
1376            })
1377            .collect::<Vec<_>>()
1378            .join("")
1379            .parse()
1380            .unwrap();
1381
1382        trait_implementation = quote! {
1383            fn descriptor(&self) -> std::sync::Arc<dyn melodium_core::common::descriptor::Treatment> {
1384                descriptor()
1385            }
1386
1387            fn set_generic(&self, generic: &str, data_type: melodium_core::common::descriptor::DataType) {
1388                match generic {
1389                    #generics
1390                    _ => {},
1391                }
1392            }
1393
1394            fn set_parameter(&self, param: &str, value: melodium_core::common::executive::Value) {
1395                match param {
1396                    #parameters
1397                    _ => {},
1398                }
1399            }
1400
1401            fn set_model(&self, name: &str, model: std::sync::Arc<dyn melodium_core::common::executive::Model>) {
1402                match name {
1403                    #models
1404                    _ => {},
1405                }
1406            }
1407
1408            fn assign_input(&self, input_name: &str, transmitter: Box<dyn melodium_core::common::executive::Input>) {
1409                match input_name {
1410                    #inputs
1411                    _ => {},
1412                }
1413            }
1414
1415            fn assign_output(&self, output_name: &str, transmitter: Box<dyn melodium_core::common::executive::Output>) {
1416                match output_name {
1417                    #outputs
1418                    _ => {},
1419                }
1420            }
1421        };
1422    }
1423
1424    let prepare_implementation;
1425    {
1426        let parameters: proc_macro2::TokenStream = params.iter().map(|(name, _)| {
1427            format!(r#"let {name} = std::mem::replace(&mut *self.r#{name}.lock().unwrap(), None).unwrap()"#)
1428        }).collect::<Vec<_>>().join(";").parse().unwrap();
1429        let pre_inputs: proc_macro2::TokenStream = inputs.iter().map(|(name, _)| {
1430            format!(r#"let {name} = std::mem::replace(&mut *self.r#{name}.lock().unwrap(), None).unwrap()"#)
1431        }).collect::<Vec<_>>().join(";").parse().unwrap();
1432        let borrow_inputs: proc_macro2::TokenStream = inputs
1433            .iter()
1434            .map(|(name, _)| format!(r#"let {name} = &{name}"#))
1435            .collect::<Vec<_>>()
1436            .join(";")
1437            .parse()
1438            .unwrap();
1439        let post_inputs: proc_macro2::TokenStream = inputs
1440            .iter()
1441            .map(|(name, _)| format!(r#"{name}.close()"#))
1442            .collect::<Vec<_>>()
1443            .join(";")
1444            .parse()
1445            .unwrap();
1446        let pre_outputs: proc_macro2::TokenStream = outputs.iter().map(|(name, _)| {
1447            format!(r#"let {name} = std::mem::replace(&mut *self.r#{name}.lock().unwrap(), None).unwrap()"#)
1448        }).collect::<Vec<_>>().join(";").parse().unwrap();
1449        let borrow_outputs: proc_macro2::TokenStream = outputs
1450            .iter()
1451            .map(|(name, _)| format!(r#"let {name} = &{name}"#))
1452            .collect::<Vec<_>>()
1453            .join(";")
1454            .parse()
1455            .unwrap();
1456        let post_outputs: proc_macro2::TokenStream = outputs
1457            .iter()
1458            .map(|(name, _)| format!(r#"{name}.close().await"#))
1459            .collect::<Vec<_>>()
1460            .join(";")
1461            .parse()
1462            .unwrap();
1463        let models: proc_macro2::TokenStream = models.iter().map(|(name, _)| {
1464            format!(r#"let {name} = std::mem::replace(&mut *self.r#{name}.lock().unwrap(), None).unwrap()"#)
1465        }).collect::<Vec<_>>().join(";").parse().unwrap();
1466        let generics: proc_macro2::TokenStream = generics.iter().map(|(name, _)| {
1467            format!(r#"#[allow(non_snake_case)] let {name} = std::mem::replace(&mut *self.r#{name}.lock().unwrap(), None).unwrap()"#)
1468        }).collect::<Vec<_>>().join(";").parse().unwrap();
1469
1470        let body = treatment.block;
1471
1472        prepare_implementation = quote! {
1473            fn prepare(&self, track_id: usize, debug_start: core::pin::Pin<Box<dyn core::future::Future<Output = ()> + Send + Sync>>, debug_finish: core::pin::Pin<Box<dyn core::future::Future<Output = ()> + Send + Sync>>) -> Vec<melodium_core::common::executive::TrackFuture> {
1474
1475                #generics;
1476                #parameters;
1477                #models;
1478                #pre_inputs;
1479                #pre_outputs;
1480
1481                vec![Box::new(Box::pin(async move {
1482
1483                    debug_start.await;
1484                    let exec = || {
1485                        #borrow_inputs;
1486                        #borrow_outputs;
1487                        async move #body
1488                    };
1489                    exec().await;
1490
1491                    #post_inputs;
1492                    #post_outputs;
1493
1494                    debug_finish.await;
1495                    melodium_core::common::executive::ResultStatus::Ok
1496                }))]
1497            }
1498        };
1499    }
1500
1501    let module_name: proc_macro2::TokenStream = format!("__mel_treatment_{name}").parse().unwrap();
1502
1503    let expanded = quote! {
1504        #[allow(non_snake_case)]
1505        pub mod #module_name {
1506            use super::*;
1507
1508            #description
1509
1510            #declaration
1511
1512            #self_implementation
1513
1514            impl melodium_core::common::executive::Treatment for AdHocTreatment {
1515                #trait_implementation
1516                #prepare_implementation
1517            }
1518        }
1519    };
1520
1521    TokenStream::from(expanded)
1522}
1523
1524#[proc_macro_attribute]
1525pub fn mel_model(attr: TokenStream, item: TokenStream) -> TokenStream {
1526    let mut params = HashMap::new();
1527    let mut sources = HashMap::new();
1528    let mut initialization = None;
1529    let mut continuous = Vec::new();
1530    let mut shutdown = None;
1531    let mut attributes = HashMap::new();
1532
1533    let mut iter_attr = Into::<proc_macro2::TokenStream>::into(attr).into_iter();
1534    while let Some(tt) = iter_attr.next() {
1535        if let TokenTree::Ident(id) = tt {
1536            let qualif = id.to_string();
1537            match qualif.as_str() {
1538                "param" => {
1539                    let (param, ty, default_val, attributes) = config_param(&mut iter_attr);
1540                    params.insert(param, (ty, default_val, attributes));
1541                }
1542                "source" => {
1543                    let (name, contexts, params, outputs, attributes) =
1544                        config_full_source(&mut iter_attr);
1545                    sources.insert(name, (contexts, params, outputs, attributes));
1546                }
1547                "initialize" => {
1548                    if let Some(TokenTree::Ident(name)) = iter_attr.next() {
1549                        initialization = Some(name.to_string());
1550                    } else {
1551                        panic!("Initialize function name expected")
1552                    }
1553                }
1554                "continuous" => {
1555                    if let Some(TokenTree::Group(group)) = iter_attr.next() {
1556                        for tt in group.stream() {
1557                            if let TokenTree::Ident(c) = tt {
1558                                continuous.push(c.to_string())
1559                            } else {
1560                                panic!("Function identity expected")
1561                            }
1562                        }
1563                    } else {
1564                        panic!("Continuous list expected")
1565                    }
1566                }
1567                "shutdown" => {
1568                    if let Some(TokenTree::Ident(name)) = iter_attr.next() {
1569                        shutdown = Some(name.to_string());
1570                    } else {
1571                        panic!("Shutdown function name expected")
1572                    }
1573                }
1574                "attribute" => {
1575                    let (name, value) = config_attribute(&mut iter_attr);
1576                    attributes.insert(name, value);
1577                }
1578                _ => panic!("Unrecognized configuration"),
1579            }
1580        }
1581    }
1582
1583    let model: ItemStruct = parse(item).unwrap();
1584    let mut documentation = Vec::new();
1585    for attr in model.attrs.clone() {
1586        if let Some(segment) = attr.path.segments.first() {
1587            if segment.ident.to_string() == "doc" {
1588                for tt in attr.tokens {
1589                    if let TokenTree::Literal(lit) = tt {
1590                        let doclit = StringLit::try_from(lit).unwrap();
1591                        documentation.push(doclit.value().to_string());
1592                    }
1593                }
1594            }
1595        }
1596    }
1597    let name = model.ident.to_string();
1598
1599    let model_description;
1600    {
1601        let documentation = documentation.join("\n");
1602        let attributes: proc_macro2::TokenStream = attributes
1603            .iter()
1604            .map(|(name, value)| {
1605                format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)
1606            })
1607            .collect::<Vec<_>>()
1608            .join(";")
1609            .parse()
1610            .unwrap();
1611        let parameters: proc_macro2::TokenStream = params.iter().map(|(name, (ty, default, attributes))| {
1612            let described_type = into_mel_described_type(ty, &Vec::default());
1613            let default = default.as_ref().map(|lit| format!("Some({val})", val = into_rust_value(ty, lit))).unwrap_or_else(|| String::from("None"));
1614            let attributes = attributes.iter().map(|(name, value)| format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)).collect::<Vec<_>>().join(";");
1615            format!(
1616                r#"melodium_core::common::descriptor::Parameter::new("{name}", melodium_core::common::descriptor::Variability::Const, {described_type}, {default}, {{let mut attrs = melodium_core::common::descriptor::Attributes::new();{attributes};attrs}})"#
1617            )
1618        }).collect::<Vec<_>>().join(",").parse().unwrap();
1619        let sources: proc_macro2::TokenStream = sources
1620            .iter()
1621            .map(|(name, (contextes, _, _, _))| {
1622                let contextes = contextes
1623                    .iter()
1624                    .map(|name| format!(r#"{name}::descriptor()"#))
1625                    .collect::<Vec<_>>()
1626                    .join(",");
1627                format!(r#"("{name}".to_string(), vec![{contextes}])"#)
1628            })
1629            .collect::<Vec<_>>()
1630            .join(",")
1631            .parse()
1632            .unwrap();
1633
1634        model_description = quote! {
1635            let model = melodium_core::descriptor::Model::new(
1636                    melodium_core::descriptor::module_path_to_identifier(env!("CARGO_PKG_VERSION"), module_path!(), #name),
1637                    #documentation.to_string(),
1638                    {
1639                        let mut attrs = melodium_core::common::descriptor::Attributes::new();
1640                        #attributes;
1641                        attrs
1642                    },
1643                    vec![#parameters],
1644                    vec![#sources],
1645                    AdHocModel::new,
1646                );
1647        };
1648    }
1649
1650    let mut sources_description = proc_macro2::TokenStream::new();
1651    {
1652        let fancy_model_name = name.to_case(Case::Snake);
1653        for (source_name, (_, params, outputs, attributes)) in &sources {
1654            let attributes = attributes
1655                .iter()
1656                .map(|(name, value)| {
1657                    format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)
1658                })
1659                .collect::<Vec<_>>()
1660                .join(";");
1661            let parameters: proc_macro2::TokenStream = params.iter().map(|(name, (ty, default, attributes))| {
1662                let described_type = into_mel_described_type(ty, &Vec::default());
1663                let default = default.as_ref().map(|lit| format!("Some({val})", val = into_rust_value(ty, lit))).unwrap_or_else(|| String::from("None"));
1664                let attributes = attributes.iter().map(|(name, value)| format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)).collect::<Vec<_>>().join(";");
1665                format!(
1666                    r#"melodium_core::common::descriptor::Parameter::new("{name}", melodium_core::common::descriptor::Variability::Const, {described_type}, {default}, {{let mut attrs = melodium_core::common::descriptor::Attributes::new();{attributes};attrs}})"#
1667                )
1668            }).collect::<Vec<_>>().join(",").parse().unwrap();
1669            let outputs: proc_macro2::TokenStream = outputs.iter().map(|(name, flow, ty, attributes)| {
1670                let described_type = into_mel_described_type(ty, &Vec::default());
1671                let attributes = attributes.iter().map(|(name, value)| format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)).collect::<Vec<_>>().join(";");
1672                format!(r#"melodium_core::common::descriptor::Output::new("{name}", {described_type}, melodium_core::common::descriptor::Flow::{flow}, {{let mut attrs = melodium_core::common::descriptor::Attributes::new();{attributes};attrs}})"#)
1673            }).collect::<Vec<_>>().join(",").parse().unwrap();
1674
1675            sources_description = quote! {
1676                #sources_description
1677                melodium_core::descriptor::Source::new(
1678                    melodium_core::descriptor::module_path_to_identifier(env!("CARGO_PKG_VERSION"), module_path!(), #source_name),
1679                    "".to_string(),
1680                    {
1681                        let mut attrs = melodium_core::common::descriptor::Attributes::new();
1682                        #attributes;
1683                        attrs
1684                    },
1685                    vec![(#fancy_model_name.to_string(), std::sync::Arc::clone(&model) as std::sync::Arc<dyn melodium_core::common::descriptor::Model>)],
1686                    vec![#parameters],
1687                    vec![(#fancy_model_name.to_string(), vec![#source_name.to_string()])],
1688                    vec![#outputs],
1689                ),
1690            };
1691        }
1692    }
1693
1694    let mut helper_implementation: proc_macro2::TokenStream;
1695    {
1696        let parameters: proc_macro2::TokenStream = params
1697            .iter()
1698            .map(|(name, (ty, _, _))| {
1699                let rust_type = into_rust_type(ty, false);
1700                let call = into_mel_value_call(ty, format!(r#"self.parameter("{name}").unwrap()"#));
1701                format!(
1702                    r#"
1703                pub fn get_{name}(&self) -> {rust_type} {{
1704                    {call}
1705                }}
1706            "#
1707                )
1708            })
1709            .collect::<Vec<_>>()
1710            .join("")
1711            .parse()
1712            .unwrap();
1713
1714        helper_implementation = parameters;
1715
1716        for (source_name, (contextes, _, _, _)) in sources {
1717            let mut param_contextes = String::new();
1718            let mut assign_contextes = String::new();
1719            for context in &contextes {
1720                let mut path = context
1721                    .split("::")
1722                    .map(|s| s.to_string())
1723                    .collect::<Vec<_>>();
1724                let name = path.pop().unwrap().split("_").last().unwrap().to_string();
1725                let fancy_name = name.to_case(Case::Snake);
1726                path.push(name);
1727
1728                param_contextes = format!("{param_contextes} {fancy_name}: {},", path.join("::"));
1729                assign_contextes = format!("{assign_contextes} std::sync::Arc::new({fancy_name}),");
1730            }
1731
1732            let param_contextes: proc_macro2::TokenStream = param_contextes.parse().unwrap();
1733            let assign_contextes: proc_macro2::TokenStream = assign_contextes.parse().unwrap();
1734            let fn_name: proc_macro2::TokenStream = format!("new_{source_name}").parse().unwrap();
1735
1736            helper_implementation = quote! {
1737                #helper_implementation
1738                pub async fn #fn_name(&self,
1739                        parent_track: Option<melodium_core::common::executive::TrackId>,
1740                        #param_contextes
1741                        params: &std::collections::HashMap<String, melodium_core::common::executive::Value>,
1742                        callback: Option<Box<dyn FnOnce(Box<melodium_core::common::executive::Outputs>) -> Vec<melodium_core::common::executive::TrackFuture> + Send>>
1743                    ) {
1744                    self.world.create_track(
1745                        self.id().unwrap(),
1746                        #source_name,
1747                        params,
1748                        vec![#assign_contextes],
1749                        parent_track,
1750                        callback,
1751                    ).await
1752                }
1753            };
1754        }
1755    }
1756
1757    let parameters_initialization: proc_macro2::TokenStream = params
1758        .iter()
1759        .filter_map(|(name, (ty, default, _))| {
1760            if let Some(default) = default {
1761                Some(format!(
1762                    r#"("{name}".to_string(), {val})"#,
1763                    val = into_rust_value(ty, default)
1764                ))
1765            } else {
1766                None
1767            }
1768        })
1769        .collect::<Vec<_>>()
1770        .join(",")
1771        .parse()
1772        .unwrap();
1773
1774    let element_name = name.to_case(Case::UpperCamel);
1775    let module_name: proc_macro2::TokenStream = format!("__mel_model_{name}").parse().unwrap();
1776    let model_name: proc_macro2::TokenStream = name.parse().unwrap();
1777    let adhoc_model_name: proc_macro2::TokenStream = format!("{name}Model").parse().unwrap();
1778    let initialize: proc_macro2::TokenStream = initialization
1779        .map(|s| format!("self.model.{s}()"))
1780        .unwrap_or_else(|| String::from("()"))
1781        .parse()
1782        .unwrap();
1783    let continuous: proc_macro2::TokenStream = continuous.iter().map(|c| format!("let auto_self = self.auto_reference.upgrade().unwrap(); self.world.add_continuous_task(Box::new(Box::pin(async move {{ auto_self.inner().{c}().await }})));")).collect::<Vec<_>>().join("").parse()
1784    .unwrap();
1785    let shutdown: proc_macro2::TokenStream = shutdown
1786        .map(|s| format!("self.model.{s}()"))
1787        .unwrap_or_else(|| String::from("()"))
1788        .parse()
1789        .unwrap();
1790
1791    let expanded = quote! {
1792        #[allow(non_snake_case)]
1793        pub mod #module_name {
1794
1795            use super::*;
1796
1797            static DESCRIPTOR: std::sync::Mutex<Option<std::sync::Arc<melodium_core::descriptor::Model>>> = std::sync::Mutex::new(None);
1798            static SOURCES: std::sync::Mutex<Option<Vec<std::sync::Arc<melodium_core::descriptor::Source>>>> = std::sync::Mutex::new(None);
1799
1800            pub fn identifier() -> melodium_core::common::descriptor::Identifier {
1801                melodium_core::descriptor::module_path_to_identifier(env!("CARGO_PKG_VERSION"), module_path!(), #element_name)
1802            }
1803
1804            pub fn descriptor() -> std::sync::Arc<melodium_core::descriptor::Model> {
1805
1806                let mut desc = DESCRIPTOR.lock().unwrap();
1807                if let Some(desc) = &*desc {
1808                    std::sync::Arc::clone(&desc)
1809                }
1810                else {
1811                    #model_description
1812
1813                    *desc = Some(std::sync::Arc::clone(&model));
1814                    model
1815                }
1816            }
1817
1818            pub fn sources() -> Vec<std::sync::Arc<melodium_core::descriptor::Source>> {
1819                let mut desc = SOURCES.lock().unwrap();
1820                if let Some(sources) = &*desc {
1821                    sources.iter().map(|s| std::sync::Arc::clone(&s)).collect::<Vec<_>>()
1822                }
1823                else {
1824                    let model = descriptor();
1825                    let sources = vec![#sources_description];
1826
1827                    *desc = Some(sources.iter().map(|s| std::sync::Arc::clone(&s)).collect::<Vec<_>>());
1828                    sources
1829                }
1830            }
1831
1832            #[derive(Debug)]
1833            pub struct AdHocModel {
1834                id: std::sync::Mutex<Option<melodium_core::common::executive::ModelId>>,
1835                params: std::sync::Mutex<std::collections::HashMap<String, melodium_core::common::executive::Value>>,
1836                model: #model_name,
1837                world: std::sync::Arc<dyn melodium_core::common::executive::World>,
1838                auto_reference: std::sync::Weak<Self>,
1839            }
1840
1841            impl AdHocModel {
1842
1843                pub fn new(world: std::sync::Arc<dyn melodium_core::common::executive::World>) -> std::sync::Arc<dyn melodium_core::common::executive::Model> {
1844                    std::sync::Arc::new_cyclic(|me| Self {
1845                        id: std::sync::Mutex::new(None),
1846                        params: std::sync::Mutex::new(vec![#parameters_initialization].into_iter().collect()),
1847                        model: #model_name::new(me.clone()),
1848                        world,
1849                        auto_reference: me.clone(),
1850                    })
1851                }
1852
1853                pub fn into(model: std::sync::Arc<dyn melodium_core::common::executive::Model>) -> std::sync::Arc<Self> {
1854                    model.downcast_arc::<Self>().unwrap()
1855                }
1856
1857                pub fn inner(&self) -> &#model_name {
1858                    &self.model
1859                }
1860
1861                pub fn world(&self) -> &std::sync::Arc<dyn melodium_core::common::executive::World> {
1862                    &self.world
1863                }
1864
1865                pub fn id(&self) -> Option<melodium_core::common::executive::ModelId> {
1866                    *self.id.lock().unwrap()
1867                }
1868
1869                pub fn set_id(&self, id: melodium_core::common::executive::ModelId) {
1870                    *self.id.lock().unwrap() = Some(id);
1871                }
1872
1873                pub fn parameter(&self, name: &str) -> Option<melodium_core::common::executive::Value> {
1874                    self.params.lock().unwrap().get(name).cloned()
1875                }
1876
1877                pub fn set_parameter(&self, param: &str, value: melodium_core::common::executive::Value) {
1878                    self.params.lock().unwrap().insert(param.to_string(), value);
1879                }
1880
1881                #helper_implementation
1882            }
1883
1884            impl melodium_core::common::executive::Model for AdHocModel {
1885                fn descriptor(&self) -> std::sync::Arc<dyn melodium_core::common::descriptor::Model> {
1886                    descriptor()
1887                }
1888
1889                fn id(&self) -> Option<melodium_core::common::executive::ModelId> {
1890                    Self::id(self)
1891                }
1892
1893                fn set_id(&self, id: melodium_core::common::executive::ModelId) {
1894                    Self::set_id(self, id)
1895                }
1896
1897                fn set_parameter(&self, param: &str, value: melodium_core::common::executive::Value) {
1898                    Self::set_parameter(self, param, value)
1899                }
1900
1901                fn initialize(&self) {
1902                    #initialize;
1903                    #continuous
1904                }
1905
1906                fn shutdown(&self) {
1907                    #shutdown
1908                }
1909
1910                fn invoke_source(&self, source: &str, params: std::collections::HashMap<String, melodium_core::common::executive::Value>) {
1911                    self.model.invoke_source(source, params);
1912                }
1913            }
1914        }
1915        pub use #module_name::AdHocModel as #adhoc_model_name;
1916
1917        #model
1918    };
1919
1920    TokenStream::from(expanded)
1921}
1922
1923#[proc_macro_attribute]
1924pub fn mel_context(attr: TokenStream, item: TokenStream) -> TokenStream {
1925    let context: ItemStruct = parse(item).unwrap();
1926    let mut attributes = HashMap::new();
1927
1928    let mut iter_attr = Into::<proc_macro2::TokenStream>::into(attr).into_iter();
1929    while let Some(tt) = iter_attr.next() {
1930        if let TokenTree::Ident(id) = tt {
1931            let qualif = id.to_string();
1932            match qualif.as_str() {
1933                "attribute" => {
1934                    let (name, value) = config_attribute(&mut iter_attr);
1935                    attributes.insert(name, value);
1936                }
1937                _ => panic!("Unrecognized configuration"),
1938            }
1939        }
1940    }
1941
1942    let mut documentation = Vec::new();
1943    for attr in context.attrs.clone() {
1944        if let Some(segment) = attr.path.segments.first() {
1945            if segment.ident.to_string() == "doc" {
1946                for tt in attr.tokens {
1947                    if let TokenTree::Literal(lit) = tt {
1948                        let doclit = StringLit::try_from(lit).unwrap();
1949                        documentation.push(doclit.value().to_string());
1950                    }
1951                }
1952            }
1953        }
1954    }
1955
1956    let name = context.ident.to_string();
1957    let mut fields = HashMap::new();
1958    if let Fields::Named(fields_named) = &context.fields {
1959        for field in &fields_named.named {
1960            if let Some(field_ident) = &field.ident {
1961                let ty = into_mel_type(&field.ty);
1962                fields.insert(field_ident.to_string(), ty);
1963            } else {
1964                panic!("Field identity expected")
1965            }
1966        }
1967    } else {
1968        panic!("Named field expected")
1969    }
1970
1971    let description;
1972    {
1973        let documentation = documentation.join("\n");
1974        let attributes: proc_macro2::TokenStream = attributes
1975            .iter()
1976            .map(|(name, value)| {
1977                format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)
1978            })
1979            .collect::<Vec<_>>()
1980            .join(";")
1981            .parse()
1982            .unwrap();
1983
1984        let fields: proc_macro2::TokenStream = fields
1985            .iter()
1986            .map(|(name, ty)| {
1987                let datatype = into_mel_datatype(ty);
1988                format!(r#"("{name}", {datatype})"#)
1989            })
1990            .collect::<Vec<_>>()
1991            .join(",")
1992            .parse()
1993            .unwrap();
1994
1995        description = quote! {
1996            melodium_core::descriptor::Context::new(
1997                    identifier(),
1998                    vec![#fields],
1999                    #documentation.to_string(),
2000                    {
2001                        let mut attrs = melodium_core::common::descriptor::Attributes::new();
2002                        #attributes;
2003                        attrs
2004                    },
2005                )
2006        };
2007    }
2008
2009    let implementation;
2010    {
2011        let get: proc_macro2::TokenStream = fields
2012            .iter()
2013            .map(|(name, ty)| {
2014                format!(
2015                    r#""{name}" => {{ let value = self.{name}.clone(); {} }}"#,
2016                    convert_to_mel_value(ty, &Vec::new(), "value")
2017                )
2018            })
2019            .collect::<Vec<_>>()
2020            .join(",")
2021            .parse()
2022            .unwrap();
2023
2024        let set: proc_macro2::TokenStream = fields
2025            .iter()
2026            .map(|(name, ty)| {
2027                let call = convert_to_rust_value(ty, &Vec::new(), "value");
2028                format!(r#""{name}" => {{self.{name} = {call};}}"#)
2029            })
2030            .collect::<Vec<_>>()
2031            .join(",")
2032            .parse()
2033            .unwrap();
2034
2035        implementation = quote! {
2036            fn set_value(&mut self, name: &str, value: melodium_core::common::executive::Value) {
2037                match name {
2038                    #set,
2039                    _ => {}
2040                }
2041            }
2042
2043            fn get_value(&self, name: &str) -> melodium_core::common::executive::Value {
2044                match name {
2045                    #get,
2046                    _ => panic!("Unexisting field")
2047                }
2048            }
2049        };
2050    }
2051
2052    let element_name = format!("@{}", name.to_case(Case::UpperCamel));
2053    let name: proc_macro2::TokenStream = name.parse().unwrap();
2054    let module_name: proc_macro2::TokenStream = format!("__mel_context_{name}").parse().unwrap();
2055    let expanded = quote! {
2056        pub mod #module_name {
2057            use super::*;
2058
2059            static DESCRIPTOR: std::sync::Mutex<Option<std::sync::Arc<melodium_core::descriptor::Context>>> = std::sync::Mutex::new(None);
2060
2061            pub fn identifier() -> melodium_core::common::descriptor::Identifier {
2062                melodium_core::descriptor::module_path_to_identifier(env!("CARGO_PKG_VERSION"), module_path!(), #element_name)
2063            }
2064
2065            pub fn descriptor() -> std::sync::Arc<melodium_core::descriptor::Context> {
2066                let mut desc = DESCRIPTOR.lock().unwrap();
2067                if let Some(desc) = &*desc {
2068                    std::sync::Arc::clone(&desc)
2069                }
2070                else {
2071                    let new = #description;
2072                    *desc = Some(std::sync::Arc::clone(&new));
2073                    new
2074                }
2075            }
2076        }
2077
2078        #[derive(Debug)]
2079        #context
2080
2081        impl melodium_core::common::executive::Context for #name {
2082            fn descriptor(&self) -> std::sync::Arc<dyn melodium_core::common::descriptor::Context> {
2083                #module_name::descriptor()
2084            }
2085
2086            #implementation
2087        }
2088    };
2089
2090    TokenStream::from(expanded)
2091}
2092
2093#[proc_macro_attribute]
2094pub fn mel_data(attr: TokenStream, item: TokenStream) -> TokenStream {
2095    let typ: ItemStruct = parse(item).unwrap();
2096    let mut attributes = HashMap::new();
2097    let mut traits = Vec::new();
2098
2099    let mut iter_attr = Into::<proc_macro2::TokenStream>::into(attr).into_iter();
2100    while let Some(tt) = iter_attr.next() {
2101        if let TokenTree::Ident(id) = tt {
2102            let qualif = id.to_string();
2103            match qualif.as_str() {
2104                "attribute" => {
2105                    let (name, value) = config_attribute(&mut iter_attr);
2106                    attributes.insert(name, value);
2107                }
2108                "traits" => {
2109                    traits = config_traits(&mut iter_attr);
2110                }
2111                _ => panic!("Unrecognized configuration"),
2112            }
2113        }
2114    }
2115
2116    let mut documentation = Vec::new();
2117    for attr in typ.attrs.clone() {
2118        if let Some(segment) = attr.path.segments.first() {
2119            if segment.ident.to_string() == "doc" {
2120                for tt in attr.tokens {
2121                    if let TokenTree::Literal(lit) = tt {
2122                        let doclit = StringLit::try_from(lit).unwrap();
2123                        documentation.push(doclit.value().to_string());
2124                    }
2125                }
2126            }
2127        }
2128    }
2129
2130    let name = typ.ident.to_string();
2131
2132    let description;
2133    {
2134        let documentation = documentation.join("\n");
2135        let attributes: proc_macro2::TokenStream = attributes
2136            .iter()
2137            .map(|(name, value)| {
2138                format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)
2139            })
2140            .collect::<Vec<_>>()
2141            .join(";")
2142            .parse()
2143            .unwrap();
2144
2145        let deserialize_trait: proc_macro2::TokenStream =
2146            if traits.iter().any(|tr| tr.as_str() == "Deserialize") {
2147                let name: proc_macro2::TokenStream = name.parse().unwrap();
2148                quote! {
2149                    Some(Box::new(|deserializer| {
2150                        let obj: #name = melodium_core::erased_deserialize(deserializer)?;
2151                        Ok(melodium_core::common::executive::Value::Data(
2152                            std::sync::Arc::new(obj)
2153                        ))
2154                    }))
2155                }
2156            } else {
2157                "None".parse().unwrap()
2158            };
2159        let (bounded_min, bounded_max): (proc_macro2::TokenStream, proc_macro2::TokenStream) =
2160            if traits.iter().any(|tr| tr.as_str() == "Bounded") {
2161                let function_min: proc_macro2::TokenStream =
2162                    format!("{name}_bounded_min", name = name.to_case(Case::Snake))
2163                        .parse()
2164                        .unwrap();
2165                let function_max: proc_macro2::TokenStream =
2166                    format!("{name}_bounded_max", name = name.to_case(Case::Snake))
2167                        .parse()
2168                        .unwrap();
2169                (
2170                    quote! {
2171                        Some(Box::new(|| {
2172                            let obj = #function_min();
2173                            melodium_core::common::executive::Value::Data(
2174                                std::sync::Arc::new(obj)
2175                            )
2176                        }))
2177                    },
2178                    quote! {
2179                        Some(Box::new(|| {
2180                            let obj = #function_max();
2181                            melodium_core::common::executive::Value::Data(
2182                                std::sync::Arc::new(obj)
2183                            )
2184                        }))
2185                    },
2186                )
2187            } else {
2188                ("None".parse().unwrap(), "None".parse().unwrap())
2189            };
2190        let (float_infinity, float_neg_infinity, float_nan): (
2191            proc_macro2::TokenStream,
2192            proc_macro2::TokenStream,
2193            proc_macro2::TokenStream,
2194        ) = if traits.iter().any(|tr| tr.as_str() == "Float") {
2195            let function_infinity: proc_macro2::TokenStream =
2196                format!("{name}_float_infinity", name = name.to_case(Case::Snake))
2197                    .parse()
2198                    .unwrap();
2199            let function_neg_infinity: proc_macro2::TokenStream = format!(
2200                "{name}_float_neg_infinity",
2201                name = name.to_case(Case::Snake)
2202            )
2203            .parse()
2204            .unwrap();
2205            let function_nan: proc_macro2::TokenStream =
2206                format!("{name}_float_nan", name = name.to_case(Case::Snake))
2207                    .parse()
2208                    .unwrap();
2209            (
2210                quote! {
2211                    Some(Box::new(|| {
2212                        let obj = #function_infinity();
2213                        melodium_core::common::executive::Value::Data(
2214                            std::sync::Arc::new(obj)
2215                        )
2216                    }))
2217                },
2218                quote! {
2219                    Some(Box::new(|| {
2220                        let obj = #function_neg_infinity();
2221                        melodium_core::common::executive::Value::Data(
2222                            std::sync::Arc::new(obj)
2223                        )
2224                    }))
2225                },
2226                quote! {
2227                    Some(Box::new(|| {
2228                        let obj = #function_nan();
2229                        melodium_core::common::executive::Value::Data(
2230                            std::sync::Arc::new(obj)
2231                        )
2232                    }))
2233                },
2234            )
2235        } else {
2236            (
2237                "None".parse().unwrap(),
2238                "None".parse().unwrap(),
2239                "None".parse().unwrap(),
2240            )
2241        };
2242
2243        let traits: proc_macro2::TokenStream = traits
2244            .iter()
2245            .map(|name| format!(r#"melodium_core::common::descriptor::DataTrait::{name}"#))
2246            .collect::<Vec<_>>()
2247            .join(",")
2248            .parse()
2249            .unwrap();
2250
2251        description = quote! {
2252            melodium_core::descriptor::Data::new(
2253                    identifier(),
2254                    #documentation.to_string(),
2255                    {
2256                        let mut attrs = melodium_core::common::descriptor::Attributes::new();
2257                        #attributes;
2258                        attrs
2259                    },
2260                    vec![#traits],
2261                    #bounded_min,
2262                    #bounded_max,
2263                    #float_infinity,
2264                    #float_neg_infinity,
2265                    #float_nan,
2266                    #deserialize_trait
2267                )
2268        };
2269    }
2270
2271    let implementation = data_traits(&name, &traits);
2272    /*{
2273        let get: proc_macro2::TokenStream = fields.iter().map(|(name, _)| {
2274            format!(
2275                r#""{name}" => melodium_core::common::executive::Value::from(self.{name}.clone())"#
2276            )
2277        }).collect::<Vec<_>>().join(",").parse().unwrap();
2278
2279        let set: proc_macro2::TokenStream = fields
2280            .iter()
2281            .map(|(name, ty)| {
2282                let call = into_mel_value_call(ty);
2283                format!(r#""{name}" => {{self.{name} = {call}(value).unwrap();}}"#)
2284            })
2285            .collect::<Vec<_>>()
2286            .join(",")
2287            .parse()
2288            .unwrap();
2289
2290        implementation = quote! {
2291            fn set_value(&mut self, name: &str, value: melodium_core::common::executive::Value) {
2292                match name {
2293                    #set,
2294                    _ => {}
2295                }
2296            }
2297
2298            fn get_value(&self, name: &str) -> melodium_core::common::executive::Value {
2299                match name {
2300                    #get,
2301                    _ => panic!("Unexisting field")
2302                }
2303            }
2304        };
2305    }*/
2306
2307    let element_name = name.clone();
2308    let name: proc_macro2::TokenStream = name.parse().unwrap();
2309    let module_name: proc_macro2::TokenStream = format!("__mel_data_{name}").parse().unwrap();
2310    let expanded = quote! {
2311        #[allow(non_snake_case)]
2312        pub mod #module_name {
2313            use super::*;
2314
2315            static DESCRIPTOR: std::sync::Mutex<Option<std::sync::Arc<melodium_core::descriptor::Data>>> = std::sync::Mutex::new(None);
2316
2317            pub fn identifier() -> melodium_core::common::descriptor::Identifier {
2318                melodium_core::descriptor::module_path_to_identifier(env!("CARGO_PKG_VERSION"), module_path!(), #element_name)
2319            }
2320
2321            pub fn descriptor() -> std::sync::Arc<melodium_core::descriptor::Data> {
2322                let mut desc = DESCRIPTOR.lock().unwrap();
2323                if let Some(desc) = &*desc {
2324                    std::sync::Arc::clone(&desc)
2325                }
2326                else {
2327                    let new = #description;
2328                    *desc = Some(std::sync::Arc::clone(&new));
2329                    new
2330                }
2331            }
2332        }
2333
2334        #typ
2335
2336        #implementation
2337
2338        impl melodium_core::common::executive::Data for #name {
2339            fn descriptor(&self) -> std::sync::Arc<dyn melodium_core::common::descriptor::Data> {
2340                #module_name::descriptor()
2341            }
2342        }
2343    };
2344
2345    TokenStream::from(expanded)
2346}
2347
2348#[proc_macro_attribute]
2349pub fn mel_function(attr: TokenStream, item: TokenStream) -> TokenStream {
2350    let mut function: ItemFn = parse(item).unwrap();
2351    let mut attributes = HashMap::new();
2352    let mut generics = Vec::new();
2353
2354    let mut iter_attr = Into::<proc_macro2::TokenStream>::into(attr).into_iter();
2355    while let Some(tt) = iter_attr.next() {
2356        if let TokenTree::Ident(id) = tt {
2357            let qualif = id.to_string();
2358            match qualif.as_str() {
2359                "attribute" => {
2360                    let (name, value) = config_attribute(&mut iter_attr);
2361                    attributes.insert(name, value);
2362                }
2363                "generic" => {
2364                    let name = config_generic(&mut iter_attr);
2365                    generics.push(name);
2366                }
2367                _ => panic!("Unrecognized configuration"),
2368            }
2369        }
2370    }
2371    let generics_list = generics
2372        .iter()
2373        .map(|(gen, _)| gen.clone())
2374        .collect::<Vec<_>>();
2375
2376    let mut documentation = Vec::new();
2377    for attr in function.attrs.clone() {
2378        if let Some(segment) = attr.path.segments.first() {
2379            if segment.ident.to_string() == "doc" {
2380                for tt in attr.tokens {
2381                    if let TokenTree::Literal(lit) = tt {
2382                        let doclit = StringLit::try_from(lit).unwrap();
2383                        documentation.push(doclit.value().to_string());
2384                    }
2385                }
2386            }
2387        }
2388    }
2389
2390    let name = function.sig.ident.to_string();
2391    let mut args = Vec::new();
2392    for arg in &mut function.sig.inputs {
2393        match arg {
2394            FnArg::Typed(t) => {
2395                let name = if let Pat::Ident(ident) = t.pat.borrow() {
2396                    ident.ident.to_string()
2397                } else {
2398                    eprintln!("Argument name expected");
2399                    break;
2400                };
2401
2402                let attributes = t
2403                    .attrs
2404                    .iter()
2405                    .filter_map(|attr| {
2406                        if let Some(name) = attr.path.get_ident() {
2407                            if name.to_string() == "mel" {
2408                                Some(config_attributes(&mut attr.tokens.clone().into_iter()))
2409                            } else {
2410                                None
2411                            }
2412                        } else {
2413                            None
2414                        }
2415                    })
2416                    .fold(HashMap::new(), |mut acc, attrs| {
2417                        for attr in attrs {
2418                            acc.insert(attr.0, attr.1);
2419                        }
2420                        acc
2421                    });
2422                t.attrs.retain(|attr| {
2423                    attr.path
2424                        .get_ident()
2425                        .map(|name| name.to_string() != "mel")
2426                        .unwrap_or(true)
2427                });
2428
2429                let ty = into_mel_type(t.ty.borrow());
2430
2431                args.push((name, (ty, attributes)));
2432            }
2433            _ => eprintln!("Only Mélodium types are admissible arguments"),
2434        }
2435    }
2436
2437    let closure = {
2438        let params = function.sig.inputs.clone();
2439        let return_type = function.sig.output.clone();
2440        let content = function.block.clone();
2441        let name = function.sig.ident.clone();
2442
2443        quote! {
2444            let #name = move |#params| #return_type #content;
2445        }
2446    };
2447
2448    let typedefs: proc_macro2::TokenStream = generics
2449        .iter()
2450        .map(|(name, _)| format!(r#"type {name} = melodium_core::common::executive::Value"#))
2451        .collect::<Vec<_>>()
2452        .join(";")
2453        .parse()
2454        .unwrap();
2455    let return_type = if let ReturnType::Type(_, rt) = &function.sig.output {
2456        into_mel_type(rt)
2457    } else {
2458        panic!("Return type expected");
2459    };
2460    let params_call = args
2461        .iter()
2462        .enumerate()
2463        .map(|(i, (_, (ty, _)))| {
2464            /*if generics
2465                .iter()
2466                .find(|(gen, _)| gen == ty.last().unwrap())
2467                .is_some()
2468            { // #######################################
2469                format!("params[{i}].clone()")
2470            } else {
2471                into_mel_value_call(ty, format!("params[{i}].clone()"))
2472            }*/
2473            convert_to_rust_value(ty, &generics_list, &format!("params[{i}].clone()"))
2474        })
2475        .collect::<Vec<_>>()
2476        .join(",");
2477    let mel_call = convert_to_mel_value(
2478        &return_type,
2479        &generics_list,
2480        &format!("{name}({params_call})"),
2481    );
2482
2483    let attributes: proc_macro2::TokenStream = attributes
2484        .iter()
2485        .map(|(name, value)| {
2486            format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)
2487        })
2488        .collect::<Vec<_>>()
2489        .join(";")
2490        .parse()
2491        .unwrap();
2492    let generics: proc_macro2::TokenStream = generics
2493        .iter()
2494        .map(|(name, traits)| format!(r#"melodium_core::common::descriptor::Generic::new("{name}".to_string(), vec![{}])"#, traits.iter().map(|tr| format!("melodium_core::common::descriptor::DataTrait::{tr}")).collect::<Vec<_>>().join(", ")))
2495        .collect::<Vec<_>>()
2496        .join(",")
2497        .parse()
2498        .unwrap();
2499    let parameters = args.iter().map(|(name, (ty, attributes))| {
2500        let name = name.to_case(Case::Snake);
2501        let described_type = into_mel_described_type(ty, &generics_list);
2502        let attributes = attributes.iter().map(|(name, value)| format!(r#"attrs.insert("{name}".to_string(), "{value}".to_string())"#)).collect::<Vec<_>>().join(";");
2503        format!(
2504            r#"melodium_core::common::descriptor::Parameter::new("{name}", melodium_core::common::descriptor::Variability::Var, {described_type}, None, {{let mut attrs = melodium_core::common::descriptor::Attributes::new();{attributes};attrs}})"#
2505        )
2506    }).collect::<Vec<_>>().join(",");
2507
2508    let element_name = format!("|{}", name.from_case(Case::Snake).to_case(Case::Snake));
2509    let module_name: proc_macro2::TokenStream = format!("__mel_function_{name}").parse().unwrap();
2510    let documentation = documentation.join("\n");
2511    let parameters: proc_macro2::TokenStream = parameters.parse().unwrap();
2512    let return_type: proc_macro2::TokenStream =
2513        into_mel_described_type(&return_type, &generics_list)
2514            .parse()
2515            .unwrap();
2516    let mel_call: proc_macro2::TokenStream = mel_call.parse().unwrap();
2517
2518    let expanded = quote! {
2519        pub mod #module_name {
2520
2521            use super::*;
2522
2523            static DESCRIPTOR: std::sync::Mutex<Option<std::sync::Arc<melodium_core::descriptor::Function>>> = std::sync::Mutex::new(None);
2524
2525            pub fn identifier() -> melodium_core::common::descriptor::Identifier {
2526                melodium_core::descriptor::module_path_to_identifier(env!("CARGO_PKG_VERSION"), module_path!(), #element_name)
2527            }
2528
2529            pub fn descriptor() -> std::sync::Arc<melodium_core::descriptor::Function> {
2530                let mut desc = DESCRIPTOR.lock().unwrap();
2531                if let Some(desc) = &*desc {
2532                    std::sync::Arc::clone(&desc)
2533                }
2534                else {
2535                    let new = melodium_core::descriptor::Function::new(
2536                        identifier(),
2537                        #documentation.to_string(),
2538                        {
2539                            let mut attrs = melodium_core::common::descriptor::Attributes::new();
2540                            #attributes;
2541                            attrs
2542                        },
2543                        vec![#generics],
2544                        vec![#parameters],
2545                        #return_type,
2546                        mel_function
2547                    );
2548                    *desc = Some(std::sync::Arc::clone(&new));
2549                    new
2550                }
2551            }
2552
2553            fn mel_function(generics: std::collections::HashMap<String, melodium_core::common::descriptor::DataType>, params: Vec<melodium_core::common::executive::Value>) -> melodium_core::common::executive::Value {
2554
2555                #typedefs;
2556
2557                #closure
2558
2559                #mel_call
2560            }
2561        }
2562    };
2563
2564    TokenStream::from(expanded)
2565}
2566
2567#[proc_macro]
2568pub fn check(item: TokenStream) -> TokenStream {
2569    let item: proc_macro2::TokenStream = proc_macro2::TokenStream::from(item);
2570
2571    let mut iter = item.clone().into_iter();
2572    if let Some(TokenTree::Punct(punct)) = iter.next() {
2573        if punct.as_char() == '\'' {
2574            let label = if let Some(TokenTree::Ident(label)) = iter.next() {
2575                label
2576            } else {
2577                panic!("Label expected")
2578            };
2579
2580            let label: proc_macro2::TokenStream =
2581                format!("'{}", label.to_string()).parse().unwrap();
2582
2583            // Discarding ','
2584            let _ = iter.next();
2585
2586            let expr = proc_macro2::TokenStream::from_iter(iter);
2587
2588            let expanded = quote! {
2589                if let Err(_) = {#expr} {
2590                    break #label;
2591                }
2592            };
2593
2594            return TokenStream::from(expanded);
2595        }
2596    }
2597
2598    let expanded = quote! {
2599        if let Err(_) = {#item} {
2600            break;
2601        }
2602    };
2603
2604    TokenStream::from(expanded)
2605}