tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

lib.rs (2882B)


      1 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
      2 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
      3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
      4 // option. This file may not be copied, modified, or distributed
      5 // except according to those terms.
      6 
      7 use proc_macro::TokenStream;
      8 use quote::quote;
      9 use syn::parse::{Parse, ParseStream, Result};
     10 use syn::{parse_macro_input, Attribute, LitStr, Signature};
     11 
     12 /* Proc macro equivalent to the following rust macro:
     13 * ```
     14 * macro_rules! link {
     15 *    ($library:literal $abi:literal $($link_name:literal)? $(#[$($doc:tt)*])* fn $name:ident($($arg:ident: $argty:ty),*)->$ret:ty) => (
     16 *        extern $abi {
     17 *            #[link(name = $library)]
     18 *            $(#[link_name=$link_name])?
     19 *            pub fn $name($($arg: $argty),*) -> $ret;
     20 *        }
     21 *     )
     22 * }
     23 * ```
     24 * with the additional feature of removing ".dll" from the $library literal.
     25 *
     26 * The macro is derived from the equivalent macro in the real windows-targets crate,
     27 * with the difference that it uses #[link] with the name of the library rather than
     28 * a single "windows.$version" library, so as to avoid having to vendor all the fake
     29 * "windows.$version" import libraries. We can do that because we also require MSVC
     30 * to build, so we do have the real import libraries available.
     31 *
     32 * As the library name is there in the original for raw-dylib support, it contains
     33 * a suffixed name, but plain #[link] expects a non-suffixed name, which is why we
     34 * remove the suffix (and why this had to be a proc-macro).
     35 *
     36 * Once raw-dylib is more widely available and tested, we'll be able to use the
     37 * raw-dylib variants directly.
     38 */
     39 
     40 struct LinkMacroInput {
     41    library: LitStr,
     42    abi: LitStr,
     43    link_name: Option<LitStr>,
     44    function: Signature,
     45 }
     46 
     47 impl Parse for LinkMacroInput {
     48    fn parse(input: ParseStream) -> Result<Self> {
     49        let library: LitStr = input.parse()?;
     50        let abi: LitStr = input.parse()?;
     51        let link_name: Option<LitStr> = input.parse().ok();
     52        let _doc_comments = Attribute::parse_outer(input)?;
     53        let function: Signature = input.parse()?;
     54        Ok(LinkMacroInput {
     55            library,
     56            abi,
     57            link_name,
     58            function,
     59        })
     60    }
     61 }
     62 
     63 #[proc_macro]
     64 pub fn link(input: TokenStream) -> TokenStream {
     65    let LinkMacroInput {
     66        library,
     67        abi,
     68        link_name,
     69        function,
     70    } = parse_macro_input!(input as LinkMacroInput);
     71 
     72    let link_name_attr = link_name.map(|lit| quote! { #[link_name = #lit] });
     73 
     74    let library = library.value();
     75    let library = library.strip_suffix(".dll").unwrap_or(&library);
     76 
     77    let generated = quote! {
     78        extern #abi {
     79            #[link(name = #library)]
     80            #link_name_attr
     81            pub #function;
     82        }
     83    };
     84 
     85    TokenStream::from(generated)
     86 }