freeswitch_rs_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::meta::ParseNestedMeta;
4use syn::parse::Parser;
5use syn::{parse_macro_input, LitStr};
6
7#[proc_macro_attribute]
8pub fn switch_module_define(attr: TokenStream, item: TokenStream) -> TokenStream {
9    let mod_struct = syn::parse_macro_input!(item as syn::ItemStruct);
10    let args = syn::punctuated::Punctuated::<syn::Path, syn::Token![,]>::parse_terminated
11        .parse2(attr.into())
12        .unwrap();
13
14    let mod_name = args
15        .get(0)
16        .and_then(|p| p.get_ident())
17        .unwrap_or(&mod_struct.ident);
18    impl_switch_module_define(&mod_struct, &mod_name)
19}
20
21fn impl_switch_module_define(ast: &syn::ItemStruct, mod_name: &syn::Ident) -> TokenStream {
22    let struct_name = &ast.ident;
23    let mod_interface_ident = format_ident!("{}_module_interface", mod_name);
24    let mod_name_string = mod_name.to_string().to_owned();
25
26    let output = quote! {
27        // Wrap Load function
28        use std::io::Write;
29
30        #ast
31
32        impl #struct_name {
33            unsafe extern "C" fn load_wrapper (
34                module_interface: *mut *mut freeswitch_rs::types::switch_loadable_module_interface_t,
35                pool: *mut freeswitch_rs::types::switch_memory_pool_t,
36            ) -> freeswitch_rs::types::switch_status_t
37            {
38                let _ = freeswitch_rs::log::set_logger(&freeswitch_rs::fslog::FSLogger);
39                freeswitch_rs::log::set_max_level(freeswitch_rs::log::LevelFilter::Debug);
40
41                let ptr = freeswitch_rs::FSModuleInterface::create(#mod_name_string, pool);
42                if ptr.is_null() { panic!("Module Creation Failed") }
43                *module_interface = *(&ptr);
44
45                let pool = freeswitch_rs::FSModulePool(pool);
46                let module = freeswitch_rs::FSModuleInterface(module_interface);
47                #struct_name::load(module,pool)
48            }
49
50            unsafe extern "C" fn shutdown_wrapper() -> freeswitch_rs::types::switch_status_t
51            {
52                #struct_name::shutdown()
53            }
54        }
55
56        // Module Table
57        #[no_mangle]
58        #[allow(non_upper_case_globals)]
59        pub static mut #mod_interface_ident: freeswitch_rs::types::switch_loadable_module_function_table = freeswitch_rs::types::switch_loadable_module_function_table {
60            switch_api_version: 5,
61            load: Some(#struct_name::load_wrapper),
62            shutdown: Some(#struct_name::shutdown_wrapper),
63            runtime: None,
64            flags: 0,
65        };
66    };
67    //eprintln!("TOKENS: {}", output);
68    TokenStream::from(output)
69}
70
71#[derive(Default)]
72struct ApiAttributes {
73    name: Option<LitStr>,
74    desc: Option<LitStr>,
75}
76
77impl ApiAttributes {
78    fn parse(&mut self, meta: ParseNestedMeta) -> syn::parse::Result<()> {
79        if meta.path.is_ident("name") {
80            self.name = Some(meta.value()?.parse()?);
81            Ok(())
82        } else if meta.path.is_ident("desc") {
83            self.desc = Some(meta.value()?.parse()?);
84            Ok(())
85        } else {
86            Err(meta.error("unsupported property"))
87        }
88    }
89}
90
91#[proc_macro_attribute]
92pub fn switch_api_define(attr: TokenStream, item: TokenStream) -> TokenStream {
93    let ast = syn::parse_macro_input!(item as syn::ItemFn);
94    let mut attrs = ApiAttributes::default();
95    let parser = syn::meta::parser(|meta| attrs.parse(meta));
96    parse_macro_input!(attr with parser);
97    impl_switch_api_define(&ast, attrs)
98}
99
100fn impl_switch_api_define(ast: &syn::ItemFn, attrs: ApiAttributes) -> TokenStream {
101    let syn::ItemFn { sig, block, .. } = ast;
102
103    let name = &sig.ident;
104    let fs_name = attrs.name.map(|ls| ls.value()).unwrap_or(name.to_string());
105    let fs_desc = attrs.desc.map(|ls| ls.value()).unwrap_or("".to_string());
106
107    let output = quote! {
108        #[allow(non_camel_case_types)]
109        struct #name;
110        impl #name {
111            #ast
112        }
113
114        impl freeswitch_rs::ApiInterface for #name {
115            const NAME:&'static str = #fs_name;
116            const DESC:&'static str = #fs_desc;
117            fn api_fn(cmd:&str, session:Option<&freeswitch_rs::core::Session>, stream:freeswitch_rs::StreamHandle) -> freeswitch_rs::types::switch_status_t {
118                #name::#name(cmd,session,stream)
119            }
120            unsafe extern "C" fn api_fn_raw(
121                cmd: *const ::std::os::raw::c_char,
122                session: *mut freeswitch_rs::types::switch_core_session_t,
123                stream: *mut freeswitch_rs::types::switch_stream_handle_t,
124            ) -> freeswitch_rs::types::switch_status_t {
125                let cstr = std::ffi::CStr::from_ptr(cmd);
126                let session = None;
127                let stream = freeswitch_rs::StreamHandle(stream);
128                #name::api_fn(cstr.to_str().unwrap(),session,stream)
129            }
130        }
131    };
132
133    //eprintln!("TOKENS1: {}", sig.ident);
134    //eprintln!("TOKENS: {}", output);
135    TokenStream::from(output)
136}
137
138#[proc_macro_attribute]
139pub fn switch_state_handler(_: TokenStream, item: TokenStream) -> TokenStream {
140    let ast = syn::parse_macro_input!(item as syn::ItemFn);
141    impl_switch_state_handler(&ast)
142}
143
144fn impl_switch_state_handler(ast: &syn::ItemFn) -> TokenStream {
145    let syn::ItemFn { sig, .. } = ast;
146    let name = &sig.ident;
147    let output = quote! {
148        mod #name {
149            use freeswitch_rs::core::Session;
150            use freeswitch_sys::types::switch_status_t;
151            use crate::*;
152            use super::*;
153            #ast
154        }
155
156        unsafe extern "C" fn #name(session: *mut freeswitch_rs::types::switch_core_session_t) -> freeswitch_rs::switch_status_t{
157            let s= freeswitch_rs::Session(session);
158            #name::#name(&s)
159        }
160    };
161    TokenStream::from(output)
162}