Skip to main content

veecle_osal_std_macros/
lib.rs

1//! `veecle-osal-std` macros.
2
3mod main_impl;
4
5use proc_macro::TokenStream;
6
7/// Marks an async `main` function as the entrypoint to a Veecle OS application.
8///
9/// Sets up async support through [`tokio`](https://crates.io/crates/tokio) and
10/// optionally initializes `veecle_os::telemetry`.
11///
12/// ```
13/// #[veecle_os::osal::std::main]
14/// async fn main() {
15///     //...
16/// }
17/// ```
18///
19/// # Telemetry
20///
21/// Telemetry setup can be enabled by setting the `telemetry` argument to `true`.
22/// By default, telemetry is disabled (`false`).
23///
24/// ```
25/// #[veecle_os::osal::std::main(telemetry = true)]
26/// async fn main() {
27///     //...
28/// }
29/// ```
30#[proc_macro_attribute]
31pub fn main(attributes: TokenStream, input: TokenStream) -> TokenStream {
32    main_impl::main2(attributes.into(), input.into()).into()
33}
34
35/// Returns a path to the `crate_name` crate.
36///
37/// Takes the import name and path within the `veecle-os` crate as additional parameters.
38fn crate_path(
39    crate_name: &str,
40    import_name: &str,
41    veecle_os_path: &[&str],
42) -> darling::Result<syn::Path> {
43    proc_macro_crate::crate_name(crate_name)
44        .map(|found| match found {
45            proc_macro_crate::FoundCrate::Itself => {
46                let ident = syn::Ident::new(import_name, proc_macro2::Span::call_site());
47                syn::parse_quote!(::#ident)
48            }
49            proc_macro_crate::FoundCrate::Name(name) => {
50                let ident = syn::Ident::new(&name, proc_macro2::Span::call_site());
51                syn::parse_quote!(::#ident)
52            }
53        })
54        .or_else(|_| {
55            proc_macro_crate::crate_name("veecle-os").map(|found| match found {
56                proc_macro_crate::FoundCrate::Itself => {
57                    todo!("unused currently, not sure what behavior will be wanted")
58                }
59                proc_macro_crate::FoundCrate::Name(name) => {
60                    let ident = syn::Ident::new(&name, proc_macro2::Span::call_site());
61                    let veecle_os_path: Vec<syn::Ident> = veecle_os_path
62                        .iter()
63                        .map(|fragment| syn::Ident::new(fragment, proc_macro2::Span::call_site()))
64                        .collect();
65                    syn::parse_quote!(::#ident::#(#veecle_os_path)::*)
66                }
67            })
68        })
69        .map_err(|_| {
70            darling::Error::custom(format!(
71                "could not find `{crate_name}` or `veecle-os` crate"
72            ))
73        })
74}
75
76#[cfg(test)]
77mod tests {
78    use std::fs::File;
79
80    use crate::main_impl;
81
82    #[test]
83    fn test_for_code_coverage() -> Result<(), Box<dyn std::error::Error>> {
84        for entry in walkdir::WalkDir::new("tests/ui") {
85            let entry = entry?;
86            if entry.path().extension().unwrap_or_default() == "rs" {
87                runtime_macros::emulate_attributelike_macro_expansion(
88                    File::open(entry.path())?,
89                    &[
90                        ("main", main_impl::main2),
91                        ("veecle_osal_std_macros::main", main_impl::main2),
92                    ],
93                )?;
94            }
95        }
96
97        Ok(())
98    }
99}