Loading openssl-sys/src/asn1.rs +3 −9 Original line number Diff line number Diff line Loading @@ -61,14 +61,8 @@ extern "C" { pub fn ASN1_TIME_set_string_X509(s: *mut ASN1_TIME, str: *const c_char) -> c_int; } cfg_if! { if #[cfg(any(ossl110, libressl280))] { const_ptr_api! { extern "C" { pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *const ASN1_STRING) -> c_int; } } else { extern "C" { pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *mut ASN1_STRING) -> c_int; } pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int; } } openssl-sys/src/bio.rs +8 −31 Original line number Diff line number Diff line Loading @@ -60,17 +60,10 @@ pub unsafe fn BIO_get_mem_data(b: *mut BIO, pp: *mut *mut c_char) -> c_long { BIO_ctrl(b, BIO_CTRL_INFO, 0, pp as *mut c_void) } cfg_if! { if #[cfg(any(ossl110, libressl280))] { extern "C" { pub fn BIO_s_file() -> *const BIO_METHOD; pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; } } else { const_ptr_api! { extern "C" { pub fn BIO_s_file() -> *mut BIO_METHOD; pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; } pub fn BIO_s_file() -> #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD; pub fn BIO_new(type_: #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD) -> *mut BIO; } } extern "C" { Loading @@ -88,26 +81,10 @@ extern "C" { pub fn BIO_free_all(b: *mut BIO); } cfg_if! { if #[cfg(any(ossl110, libressl280))] { extern "C" { pub fn BIO_s_mem() -> *const BIO_METHOD; } } else { extern "C" { pub fn BIO_s_mem() -> *mut BIO_METHOD; } } } cfg_if! { if #[cfg(any(ossl102, libressl280))] { const_ptr_api! { extern "C" { pub fn BIO_new_mem_buf(buf: *const c_void, len: c_int) -> *mut BIO; } } else { extern "C" { pub fn BIO_new_mem_buf(buf: *mut c_void, len: c_int) -> *mut BIO; } pub fn BIO_s_mem() -> #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD; pub fn BIO_new_mem_buf(buf: #[const_ptr_if(any(ossl102, libressl280))] c_void, len: c_int) -> *mut BIO; } } Loading openssl-sys/src/evp.rs +16 −44 Original line number Diff line number Diff line Loading @@ -174,15 +174,9 @@ extern "C" { outl: *mut c_int, ) -> c_int; } cfg_if! { if #[cfg(any(ossl111b, libressl280))] { extern "C" { pub fn EVP_PKEY_size(pkey: *const EVP_PKEY) -> c_int; } } else { const_ptr_api! { extern "C" { pub fn EVP_PKEY_size(pkey: *mut EVP_PKEY) -> c_int; } pub fn EVP_PKEY_size(pkey: #[const_ptr_if(any(ossl111b, libressl280))] EVP_PKEY) -> c_int; } } cfg_if! { Loading @@ -206,25 +200,15 @@ cfg_if! { } } } cfg_if! { if #[cfg(any(ossl102, libressl280))] { extern "C" { pub fn EVP_DigestVerifyFinal( ctx: *mut EVP_MD_CTX, sigret: *const c_uchar, siglen: size_t, ) -> c_int; } } else { const_ptr_api! { extern "C" { pub fn EVP_DigestVerifyFinal( ctx: *mut EVP_MD_CTX, sigret: *mut c_uchar, sigret: #[const_ptr_if(any(ossl102, libressl280))] c_uchar, siglen: size_t, ) -> c_int; } } } extern "C" { pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX; Loading Loading @@ -317,15 +301,9 @@ extern "C" { pub fn EVP_PKEY_id(pkey: *const EVP_PKEY) -> c_int; } cfg_if! { if #[cfg(any(ossl110, libressl280))] { extern "C" { pub fn EVP_PKEY_bits(key: *const EVP_PKEY) -> c_int; } } else { const_ptr_api! { extern "C" { pub fn EVP_PKEY_bits(key: *mut EVP_PKEY) -> c_int; } pub fn EVP_PKEY_bits(key: #[const_ptr_if(any(ossl110, libressl280))] EVP_PKEY) -> c_int; } } extern "C" { Loading Loading @@ -456,15 +434,9 @@ extern "C" { ) -> c_int; } cfg_if! { if #[cfg(any(ossl110, libressl280))] { extern "C" { pub fn EVP_PKCS82PKEY(p8: *const PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY; } } else { const_ptr_api! { extern "C" { pub fn EVP_PKCS82PKEY(p8: *mut PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY; } pub fn EVP_PKCS82PKEY(p8: #[const_ptr_if(any(ossl110, libressl280))] PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY; } } Loading openssl-sys/src/lib.rs +1 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ unused_imports )] #![doc(html_root_url = "https://docs.rs/openssl-sys/0.9")] #![recursion_limit = "128"] // configure fixed limit across all rust versions extern crate libc; Loading openssl-sys/src/macros.rs +209 −0 Original line number Diff line number Diff line Loading @@ -85,3 +85,212 @@ macro_rules! const_fn { )* } } // openssl changes `*mut` to `*const` in certain parameters in certain versions; // in C this is ABI and (mostly) API compatible. // // We need to handle this explicitly, and this macro helps annotate which // parameter got converted in which version. // // Input is: // extern "C" { // #[attributes...] // pub fn name(args) -> rettype; // `-> rettype` optional // // more functions... // } // // This macro replaces `#[const_ptr_if(...)]` in types with `*const` or `*mut` // (depending on the inner cfg flags) // // Walks through all argument and return types, but only finds inner types of // `*const` and `*mut`; doesn't walk arrays or generics. // // NOTE: can't abstract `pub` as `$fn_vis:vis`, as ctest macro handling doesn't // support it (old syntax crate). But we really only need `pub` anyway. // // NOTE: ctest seams to simply ignore macros it can't expand (whatever the // reason) macro_rules! const_ptr_api { // ---------------------------------------------------------------- // (partialarg): partial argument, waiting for "final" argument type // MAGIC PART 1: hande conditional const ptr in argument type ( (partialarg) { $(#[$fn_attr:meta])* pub fn $fn_name:ident } $args_packed:tt [ $($part_arg:tt)* ] [ #[const_ptr_if( $($cfg:tt)* )] $($arg_rem:tt)* ] $ret_packed:tt ) => { const_ptr_api!( (partialarg) { #[cfg($($cfg)*)] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_arg)* *const ] [ $($arg_rem)* ] $ret_packed ); const_ptr_api!( (partialarg) { #[cfg(not($($cfg)*))] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_arg)* *mut ] [ $($arg_rem)* ] $ret_packed ); }; // continue partial argument with `*mut` pointer (might need special const handling in inner type) ( (partialarg) $def_packed:tt $args_packed:tt [ $($part_arg:tt)* ] [ *mut $($arg_rem:tt)* ] $ret_packed:tt ) => { const_ptr_api!( (partialarg) $def_packed $args_packed [ $($part_arg)* *mut ] [ $($arg_rem)* ] $ret_packed ); }; // continue partial argument with `*const` pointer (might need special const handling in inner type) ( (partialarg) $def_packed:tt $args_packed:tt [ $($part_arg:tt)* ] [ *const $($arg_rem:tt)* ] $ret_packed:tt ) => { const_ptr_api!( (partialarg) $def_packed $args_packed [ $($part_arg)* *const ] [ $($arg_rem)* ] $ret_packed ); }; // finish partial argument with trailing comma ( (partialarg) $def_packed:tt { $($args_tt:tt)* } [ $($part_arg:tt)* ] [ $arg_ty:ty, $($arg_rem:tt)* ] $ret_packed:tt ) => { const_ptr_api!( (parseargs) $def_packed { $($args_tt)* { $($part_arg)* $arg_ty } } [ $($arg_rem)* ] $ret_packed ); }; // finish final partial argument (no trailing comma) ( (partialarg) $def_packed:tt { $($args_tt:tt)* } [ $($part_arg:tt)* ] [ $arg_ty:ty ] $ret_packed:tt ) => { const_ptr_api!( (parseargs) $def_packed { $($args_tt)* { $($part_arg)* $arg_ty } } [ ] $ret_packed ); }; // ---------------------------------------------------------------- // (parseargs): parsing arguments // start next argument ( (parseargs) $def_packed:tt $args_packed:tt [ $arg_name:ident : $($arg_rem:tt)* ] $ret_packed:tt ) => { const_ptr_api!( (partialarg) $def_packed $args_packed [ $arg_name: ] [ $($arg_rem)* ] $ret_packed ); }; // end of arguments, there is a return type; start parsing it ( (parseargs) $def_packed:tt $args_packed:tt [ ] [ -> $($rem:tt)* ] ) => { const_ptr_api!( (partialret) $def_packed $args_packed [] [ $($rem)* ] ); }; // end of arguments, no return type ( (parseargs) $def_packed:tt $args_packed:tt [ ] [ ] ) => { const_ptr_api!( (generate) $def_packed $args_packed { () } ); }; // ---------------------------------------------------------------- // (partialret): have partial return type, waiting for final return type // MAGIC PART 2: hande conditional const ptr in return type ( (partialret) { $(#[$fn_attr:meta])* pub fn $fn_name:ident } $args_packed:tt [ $($part_ret:tt)* ] [ #[const_ptr_if( $($cfg:tt)* )] $($rem:tt)* ] ) => { const_ptr_api!( (partialret) { #[cfg($($cfg)*)] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_ret)* *const ] [ $($rem)* ] ); const_ptr_api!( (partialret) { #[cfg(not($($cfg)*))] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_ret)* *mut ] [ $($rem)* ] ); }; // `* mut` part in return type; continue parsing to find inner conditional const ptr ( (partialret) $def_packed:tt $args_packed:tt [ $($part_ret:tt)* ] [ *mut $($rem:tt)* ] ) => { const_ptr_api!( (partialret) $def_packed $args_packed [ $($part_ret)* *mut ] [ $($rem)* ] ); }; // `* const` part in return type; continue parsing to find inner conditional const ptr ( (partialret) $def_packed:tt $args_packed:tt [ $($part_ret:tt)* ] [ *const $($rem:tt)* ] ) => { const_ptr_api!( (partialret) $def_packed $args_packed [ $($part_ret)* *const ] [ $($rem)* ] ); }; // final part of return type ( (partialret) $def_packed:tt $args_packed:tt [ $($part_ret:tt)* ] [ $ret_ty:ty ] ) => { const_ptr_api!( (generate) $def_packed $args_packed { $($part_ret)* $ret_ty } ); }; // ---------------------------------------------------------------- // generate ( (generate) { $(#[$fn_attr:meta])* pub fn $fn_name:ident } { $({ $arg_name:ident: $($arg_ty:tt)* })* } { $ret_ty:ty } ) => { extern "C" { $(#[$fn_attr])* pub fn $fn_name( $( $arg_name: $($arg_ty)* ),* ) -> $ret_ty; } }; // ---------------------------------------------------------------- // (fn): gather tokens for return type until ";" // found end; start parsing current function, and parse remaining functions ( (fn) $def_packed:tt $arg_tts_packed:tt $ret_packed:tt [ ; $($rem:tt)* ] ) => { const_ptr_api!( (parseargs) $def_packed {} $arg_tts_packed $ret_packed ); const_ptr_api!( (extern) [ $($rem)* ] ); }; // not ";" - all other tokens are part of the return type. // don't expand return type yet; otherwise we'd have to remember in which branch `rem` needs // to be used to parse further functions. ( (fn) $def_packed:tt $arg_tts_packed:tt [ $($ret_tt:tt)* ] [ $tt:tt $($rem:tt)* ] ) => { const_ptr_api!( (fn) $def_packed $arg_tts_packed [ $($ret_tt)* $tt ] [ $($rem)* ] ); }; // ---------------------------------------------------------------- // (extern): in extern block, find next function // try to split into functions as fast as possible to reduce recursion depth ( (extern) [ $(#[$fn_attr:meta])* pub fn $fn_name:ident( $($arg_rem:tt)* ) $($rem:tt)* ] ) => { const_ptr_api!( (fn) { $(#[$fn_attr])* pub fn $fn_name } [ $($arg_rem)* ] [] [ $($rem)* ] ); }; // end of extern block ( (extern) [] ) => {}; // ---------------------------------------------------------------- // macro start; find extern block ( extern "C" { $($rem:tt)* } ) => { const_ptr_api!( (extern) [ $($rem)* ] ); }; } Loading
openssl-sys/src/asn1.rs +3 −9 Original line number Diff line number Diff line Loading @@ -61,14 +61,8 @@ extern "C" { pub fn ASN1_TIME_set_string_X509(s: *mut ASN1_TIME, str: *const c_char) -> c_int; } cfg_if! { if #[cfg(any(ossl110, libressl280))] { const_ptr_api! { extern "C" { pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *const ASN1_STRING) -> c_int; } } else { extern "C" { pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *mut ASN1_STRING) -> c_int; } pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int; } }
openssl-sys/src/bio.rs +8 −31 Original line number Diff line number Diff line Loading @@ -60,17 +60,10 @@ pub unsafe fn BIO_get_mem_data(b: *mut BIO, pp: *mut *mut c_char) -> c_long { BIO_ctrl(b, BIO_CTRL_INFO, 0, pp as *mut c_void) } cfg_if! { if #[cfg(any(ossl110, libressl280))] { extern "C" { pub fn BIO_s_file() -> *const BIO_METHOD; pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; } } else { const_ptr_api! { extern "C" { pub fn BIO_s_file() -> *mut BIO_METHOD; pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; } pub fn BIO_s_file() -> #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD; pub fn BIO_new(type_: #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD) -> *mut BIO; } } extern "C" { Loading @@ -88,26 +81,10 @@ extern "C" { pub fn BIO_free_all(b: *mut BIO); } cfg_if! { if #[cfg(any(ossl110, libressl280))] { extern "C" { pub fn BIO_s_mem() -> *const BIO_METHOD; } } else { extern "C" { pub fn BIO_s_mem() -> *mut BIO_METHOD; } } } cfg_if! { if #[cfg(any(ossl102, libressl280))] { const_ptr_api! { extern "C" { pub fn BIO_new_mem_buf(buf: *const c_void, len: c_int) -> *mut BIO; } } else { extern "C" { pub fn BIO_new_mem_buf(buf: *mut c_void, len: c_int) -> *mut BIO; } pub fn BIO_s_mem() -> #[const_ptr_if(any(ossl110, libressl280))] BIO_METHOD; pub fn BIO_new_mem_buf(buf: #[const_ptr_if(any(ossl102, libressl280))] c_void, len: c_int) -> *mut BIO; } } Loading
openssl-sys/src/evp.rs +16 −44 Original line number Diff line number Diff line Loading @@ -174,15 +174,9 @@ extern "C" { outl: *mut c_int, ) -> c_int; } cfg_if! { if #[cfg(any(ossl111b, libressl280))] { extern "C" { pub fn EVP_PKEY_size(pkey: *const EVP_PKEY) -> c_int; } } else { const_ptr_api! { extern "C" { pub fn EVP_PKEY_size(pkey: *mut EVP_PKEY) -> c_int; } pub fn EVP_PKEY_size(pkey: #[const_ptr_if(any(ossl111b, libressl280))] EVP_PKEY) -> c_int; } } cfg_if! { Loading @@ -206,25 +200,15 @@ cfg_if! { } } } cfg_if! { if #[cfg(any(ossl102, libressl280))] { extern "C" { pub fn EVP_DigestVerifyFinal( ctx: *mut EVP_MD_CTX, sigret: *const c_uchar, siglen: size_t, ) -> c_int; } } else { const_ptr_api! { extern "C" { pub fn EVP_DigestVerifyFinal( ctx: *mut EVP_MD_CTX, sigret: *mut c_uchar, sigret: #[const_ptr_if(any(ossl102, libressl280))] c_uchar, siglen: size_t, ) -> c_int; } } } extern "C" { pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX; Loading Loading @@ -317,15 +301,9 @@ extern "C" { pub fn EVP_PKEY_id(pkey: *const EVP_PKEY) -> c_int; } cfg_if! { if #[cfg(any(ossl110, libressl280))] { extern "C" { pub fn EVP_PKEY_bits(key: *const EVP_PKEY) -> c_int; } } else { const_ptr_api! { extern "C" { pub fn EVP_PKEY_bits(key: *mut EVP_PKEY) -> c_int; } pub fn EVP_PKEY_bits(key: #[const_ptr_if(any(ossl110, libressl280))] EVP_PKEY) -> c_int; } } extern "C" { Loading Loading @@ -456,15 +434,9 @@ extern "C" { ) -> c_int; } cfg_if! { if #[cfg(any(ossl110, libressl280))] { extern "C" { pub fn EVP_PKCS82PKEY(p8: *const PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY; } } else { const_ptr_api! { extern "C" { pub fn EVP_PKCS82PKEY(p8: *mut PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY; } pub fn EVP_PKCS82PKEY(p8: #[const_ptr_if(any(ossl110, libressl280))] PKCS8_PRIV_KEY_INFO) -> *mut EVP_PKEY; } } Loading
openssl-sys/src/lib.rs +1 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ unused_imports )] #![doc(html_root_url = "https://docs.rs/openssl-sys/0.9")] #![recursion_limit = "128"] // configure fixed limit across all rust versions extern crate libc; Loading
openssl-sys/src/macros.rs +209 −0 Original line number Diff line number Diff line Loading @@ -85,3 +85,212 @@ macro_rules! const_fn { )* } } // openssl changes `*mut` to `*const` in certain parameters in certain versions; // in C this is ABI and (mostly) API compatible. // // We need to handle this explicitly, and this macro helps annotate which // parameter got converted in which version. // // Input is: // extern "C" { // #[attributes...] // pub fn name(args) -> rettype; // `-> rettype` optional // // more functions... // } // // This macro replaces `#[const_ptr_if(...)]` in types with `*const` or `*mut` // (depending on the inner cfg flags) // // Walks through all argument and return types, but only finds inner types of // `*const` and `*mut`; doesn't walk arrays or generics. // // NOTE: can't abstract `pub` as `$fn_vis:vis`, as ctest macro handling doesn't // support it (old syntax crate). But we really only need `pub` anyway. // // NOTE: ctest seams to simply ignore macros it can't expand (whatever the // reason) macro_rules! const_ptr_api { // ---------------------------------------------------------------- // (partialarg): partial argument, waiting for "final" argument type // MAGIC PART 1: hande conditional const ptr in argument type ( (partialarg) { $(#[$fn_attr:meta])* pub fn $fn_name:ident } $args_packed:tt [ $($part_arg:tt)* ] [ #[const_ptr_if( $($cfg:tt)* )] $($arg_rem:tt)* ] $ret_packed:tt ) => { const_ptr_api!( (partialarg) { #[cfg($($cfg)*)] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_arg)* *const ] [ $($arg_rem)* ] $ret_packed ); const_ptr_api!( (partialarg) { #[cfg(not($($cfg)*))] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_arg)* *mut ] [ $($arg_rem)* ] $ret_packed ); }; // continue partial argument with `*mut` pointer (might need special const handling in inner type) ( (partialarg) $def_packed:tt $args_packed:tt [ $($part_arg:tt)* ] [ *mut $($arg_rem:tt)* ] $ret_packed:tt ) => { const_ptr_api!( (partialarg) $def_packed $args_packed [ $($part_arg)* *mut ] [ $($arg_rem)* ] $ret_packed ); }; // continue partial argument with `*const` pointer (might need special const handling in inner type) ( (partialarg) $def_packed:tt $args_packed:tt [ $($part_arg:tt)* ] [ *const $($arg_rem:tt)* ] $ret_packed:tt ) => { const_ptr_api!( (partialarg) $def_packed $args_packed [ $($part_arg)* *const ] [ $($arg_rem)* ] $ret_packed ); }; // finish partial argument with trailing comma ( (partialarg) $def_packed:tt { $($args_tt:tt)* } [ $($part_arg:tt)* ] [ $arg_ty:ty, $($arg_rem:tt)* ] $ret_packed:tt ) => { const_ptr_api!( (parseargs) $def_packed { $($args_tt)* { $($part_arg)* $arg_ty } } [ $($arg_rem)* ] $ret_packed ); }; // finish final partial argument (no trailing comma) ( (partialarg) $def_packed:tt { $($args_tt:tt)* } [ $($part_arg:tt)* ] [ $arg_ty:ty ] $ret_packed:tt ) => { const_ptr_api!( (parseargs) $def_packed { $($args_tt)* { $($part_arg)* $arg_ty } } [ ] $ret_packed ); }; // ---------------------------------------------------------------- // (parseargs): parsing arguments // start next argument ( (parseargs) $def_packed:tt $args_packed:tt [ $arg_name:ident : $($arg_rem:tt)* ] $ret_packed:tt ) => { const_ptr_api!( (partialarg) $def_packed $args_packed [ $arg_name: ] [ $($arg_rem)* ] $ret_packed ); }; // end of arguments, there is a return type; start parsing it ( (parseargs) $def_packed:tt $args_packed:tt [ ] [ -> $($rem:tt)* ] ) => { const_ptr_api!( (partialret) $def_packed $args_packed [] [ $($rem)* ] ); }; // end of arguments, no return type ( (parseargs) $def_packed:tt $args_packed:tt [ ] [ ] ) => { const_ptr_api!( (generate) $def_packed $args_packed { () } ); }; // ---------------------------------------------------------------- // (partialret): have partial return type, waiting for final return type // MAGIC PART 2: hande conditional const ptr in return type ( (partialret) { $(#[$fn_attr:meta])* pub fn $fn_name:ident } $args_packed:tt [ $($part_ret:tt)* ] [ #[const_ptr_if( $($cfg:tt)* )] $($rem:tt)* ] ) => { const_ptr_api!( (partialret) { #[cfg($($cfg)*)] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_ret)* *const ] [ $($rem)* ] ); const_ptr_api!( (partialret) { #[cfg(not($($cfg)*))] $(#[$fn_attr])* pub fn $fn_name } $args_packed [ $($part_ret)* *mut ] [ $($rem)* ] ); }; // `* mut` part in return type; continue parsing to find inner conditional const ptr ( (partialret) $def_packed:tt $args_packed:tt [ $($part_ret:tt)* ] [ *mut $($rem:tt)* ] ) => { const_ptr_api!( (partialret) $def_packed $args_packed [ $($part_ret)* *mut ] [ $($rem)* ] ); }; // `* const` part in return type; continue parsing to find inner conditional const ptr ( (partialret) $def_packed:tt $args_packed:tt [ $($part_ret:tt)* ] [ *const $($rem:tt)* ] ) => { const_ptr_api!( (partialret) $def_packed $args_packed [ $($part_ret)* *const ] [ $($rem)* ] ); }; // final part of return type ( (partialret) $def_packed:tt $args_packed:tt [ $($part_ret:tt)* ] [ $ret_ty:ty ] ) => { const_ptr_api!( (generate) $def_packed $args_packed { $($part_ret)* $ret_ty } ); }; // ---------------------------------------------------------------- // generate ( (generate) { $(#[$fn_attr:meta])* pub fn $fn_name:ident } { $({ $arg_name:ident: $($arg_ty:tt)* })* } { $ret_ty:ty } ) => { extern "C" { $(#[$fn_attr])* pub fn $fn_name( $( $arg_name: $($arg_ty)* ),* ) -> $ret_ty; } }; // ---------------------------------------------------------------- // (fn): gather tokens for return type until ";" // found end; start parsing current function, and parse remaining functions ( (fn) $def_packed:tt $arg_tts_packed:tt $ret_packed:tt [ ; $($rem:tt)* ] ) => { const_ptr_api!( (parseargs) $def_packed {} $arg_tts_packed $ret_packed ); const_ptr_api!( (extern) [ $($rem)* ] ); }; // not ";" - all other tokens are part of the return type. // don't expand return type yet; otherwise we'd have to remember in which branch `rem` needs // to be used to parse further functions. ( (fn) $def_packed:tt $arg_tts_packed:tt [ $($ret_tt:tt)* ] [ $tt:tt $($rem:tt)* ] ) => { const_ptr_api!( (fn) $def_packed $arg_tts_packed [ $($ret_tt)* $tt ] [ $($rem)* ] ); }; // ---------------------------------------------------------------- // (extern): in extern block, find next function // try to split into functions as fast as possible to reduce recursion depth ( (extern) [ $(#[$fn_attr:meta])* pub fn $fn_name:ident( $($arg_rem:tt)* ) $($rem:tt)* ] ) => { const_ptr_api!( (fn) { $(#[$fn_attr])* pub fn $fn_name } [ $($arg_rem)* ] [] [ $($rem)* ] ); }; // end of extern block ( (extern) [] ) => {}; // ---------------------------------------------------------------- // macro start; find extern block ( extern "C" { $($rem:tt)* } ) => { const_ptr_api!( (extern) [ $($rem)* ] ); }; }