reactive_graph_plugin_derive/lib.rs
1// #[macro_use]
2// extern crate darling;
3// extern crate proc_macro;
4//
5// use proc_macro::TokenStream;
6// use proc_macro2::TokenStream as TokenStream2;
7//
8// use quote::format_ident;
9// use quote::quote;
10// use syn::parse_macro_input;
11// use syn::DeriveInput;
12// use syn::Ident;
13//
14// use crate::darling::FromDeriveInput;
15//
16// #[derive(FromDeriveInput)]
17// #[darling(attributes(type_provider))]
18// struct TypeProviderConfig {
19// tys: syn::Type,
20// path: String,
21// component_alias: Option<bool>,
22// }
23//
24// uses_type_params!(TypeProviderConfig, tys);
25//
26// #[proc_macro_derive(TypeProvider, attributes(type_provider))]
27// pub fn type_provider(input: TokenStream) -> TokenStream {
28// let input: DeriveInput = parse_macro_input!(input);
29//
30// let ident: Ident = input.ident.clone();
31// let ident_assets = format_ident!("{}Assets", ident);
32//
33// let type_provider_config = match TypeProviderConfig::from_derive_input(&input) {
34// Ok(type_provider_config) => type_provider_config,
35// Err(e) => {
36// return e.write_errors().into();
37// }
38// };
39// let tys = type_provider_config.tys;
40// let path = type_provider_config.path;
41// let type_provider_id = ident.to_string();
42//
43// let component_alias = if type_provider_config.component_alias.unwrap_or(true) {
44// quote! {
45// #[reactive_graph_plugin_api::springtime_di::component_alias]
46// }
47// } else {
48// TokenStream2::new()
49// };
50//
51// #[cfg(feature = "json")]
52// let json = {
53// quote! {
54// match reactive_graph_plugin_api::serde_json::from_str(asset_str) {
55// Ok(parsed_entry) => {
56// let entry: <#tys as reactive_graph_graph::NamespacedTypeContainer>::Type = parsed_entry;
57// reactive_graph_graph::NamespacedTypeContainer::push(&entries, entry);
58// }
59// Err(e) => log::error!("Error in parsing JSON file {filename}: {e}"),
60// }
61// }
62// };
63// #[cfg(not(feature = "json"))]
64// let json = {
65// quote! {
66// log::error!("Failed to read type definition from {filename}: JSON is not a supported file format!");
67// }
68// };
69//
70// #[cfg(feature = "json5")]
71// let json5 = {
72// quote! {
73// match reactive_graph_plugin_api::json5::from_str(asset_str) {
74// Ok(parsed_entry) => {
75// let entry: <#tys as reactive_graph_graph::NamespacedTypeContainer>::Type = parsed_entry;
76// reactive_graph_graph::NamespacedTypeContainer::push(&entries, entry);
77// }
78// Err(e) => log::error!("Error in parsing JSON5 file {filename}: {e}"),
79// }
80// }
81// };
82// #[cfg(not(feature = "json5"))]
83// let json5 = {
84// quote! {
85// log::error!("Failed to read type definition from {filename}: JSON5 is not a supported file format!");
86// }
87// };
88//
89// #[cfg(feature = "toml")]
90// let toml = {
91// quote! {
92// match reactive_graph_plugin_api::toml::from_str(asset_str) {
93// Ok(parsed_entry) => {
94// let entry: <#tys as reactive_graph_graph::NamespacedTypeContainer>::Type = parsed_entry;
95// reactive_graph_graph::NamespacedTypeContainer::push(&entries, entry);
96// }
97// Err(e) => log::error!("Error in parsing TOML file {filename}: {e}"),
98// }
99// }
100// };
101// #[cfg(not(feature = "toml"))]
102// let toml = {
103// quote! {
104// log::error!("Failed to read type definition from {filename}: TOML is not a supported file format!");
105// }
106// };
107//
108// let expanded = quote! {
109// #[derive(rust_embed::RustEmbed)]
110// #[folder = #path]
111// struct #ident_assets;
112//
113// #[automatically_derived]
114// #component_alias
115// impl reactive_graph_plugin_api::TypeProvider<#tys> for #ident {
116// fn id<'a>(&self) -> &'a str {
117// #type_provider_id
118// }
119// fn get_types(&self) -> #tys {
120// let mut entries = <#tys as reactive_graph_graph::NamespacedTypeContainer>::new();
121// for file in #ident_assets::iter() {
122// let filename = file.as_ref();
123// if filename.starts_with(".") {
124// // do nothing
125// continue;
126// }
127// log::debug!("Loading resource {}", filename);
128// match #ident_assets::get(filename) {
129// Some(asset) => match std::str::from_utf8(asset.data.as_ref()) {
130// Ok(asset_str) => {
131// if filename.ends_with(".json") {
132// #json
133// } else if filename.ends_with(".json5") {
134// #json5
135// } else if filename.ends_with(".toml") {
136// #toml
137// } else {
138// log::error!("Can't read type definition {}: Only JSON, JSON5 and TOML are supported.", filename);
139// }
140// }
141// Err(e) => log::error!("Error in decoding file to UTF-8 {}: {}", filename, e),
142// },
143// None => {}
144// }
145// }
146// entries
147// }
148// }
149// };
150// TokenStream::from(expanded)
151// }