1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#[cfg(windows)]
macro_rules! generate {
  (extern "C" {
      $(fn $name:ident($($param:ident: $ptype:ty$(,)?)*)$( -> $rtype:ty)?;)+
  }) => {
      struct Napi {
          $(
              $name: unsafe extern "C" fn(
                  $($param: $ptype,)*
              )$( -> $rtype)*,
          )*
      }

      #[inline(never)]
      fn panic_load<T>() -> T {
          panic!("Must load N-API bindings")
      }

      static mut NAPI: Napi = {
          $(
              unsafe extern "C" fn $name($(_: $ptype,)*)$( -> $rtype)* {
                  panic_load()
              }
          )*

          Napi {
              $(
                  $name,
              )*
          }
      };

      pub unsafe fn load(
          host: &libloading::Library,
      ) -> Result<(), libloading::Error> {
          NAPI = Napi {
              $(
                  $name: {
                    let symbol: Result<libloading::Symbol<unsafe extern "C" fn ($(_: $ptype,)*)$( -> $rtype)*>, libloading::Error> = host.get(stringify!($name).as_bytes());
                    match symbol {
                      Ok(f) => *f,
                      Err(e) => {
                        debug_assert!({
                          println!("Load Node-API [{}] from host runtime failed: {}", stringify!($name), e);
                          true
                        });
                        return Ok(());
                      }
                    }
                  },
              )*
          };

          Ok(())
      }

      $(
          #[inline]
          #[allow(clippy::missing_safety_doc)]
          pub unsafe fn $name($($param: $ptype,)*)$( -> $rtype)* {
              (NAPI.$name)($($param,)*)
          }
      )*
  };
}

#[cfg(not(windows))]
macro_rules! generate {
  (extern "C" {
    $(fn $name:ident($($param:ident: $ptype:ty$(,)?)*)$( -> $rtype:ty)?;)+
  }) => {
    extern "C" {
      $(
        pub fn $name($($param: $ptype,)*)$( -> $rtype)*;
      ) *
    }
  };
}

#[cfg(windows)]
use std::sync::Once;

mod functions;
mod types;

pub use functions::*;
pub use types::*;

#[cfg(windows)]
static SETUP: Once = Once::new();

/// Loads N-API symbols from host process.
/// Must be called at least once before using any functions in bindings or
/// they will panic.
/// Safety: `env` must be a valid `napi_env` for the current thread
#[cfg(windows)]
#[allow(clippy::missing_safety_doc)]
pub unsafe fn setup() {
  SETUP.call_once(|| {
    if let Err(err) = load() {
      panic!("{}", err);
    }
  });
}