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(); list.append(&mut config_ty(&mut ts));
579 ts.next(); }
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(); let mel_ty = config_ty(ts);
605
606 ts.next(); 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(); 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(); 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 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 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 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}