veecle_osal_std_macros/
lib.rs

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