freeswitch_rs_macros/
lib.rs1use 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 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 #[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 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 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}