Description
Our bindgen configuration does not filter the types and as a result we pollute nginx_sys
with all the symbols from libc, pcre2 and OpenSSL.
At the very least, we should limit output to the nginx symbols and required dependencies:
let bindings = bindgen::Builder::default()
.allowlist_function("ngx_.*")
.allowlist_type("ngx_.*")
.allowlist_var("(NGX|NGINX|ngx|nginx)_.*")
but here's another annoying problem: nginx_sys::SSL
is not the same type as openssl_sys::SSL
and cannot be used interchangeably. Even though it's generated from the same header with the same layout, Rust compiler does not use structural typing and cannot infer the equivalence.
In practice that results in an extra noise and unsafety when using a high-level OpenSSL bindings. Whenever we need to call openssl::something
, we'll have to cast nginx_sys::
types to openssl_sys::
and vice versa.
The same issue applies to pcre2
, libc
and likely windows-sys
.
This could be solved by telling bindgen to skip the types and add imports from the correct crate:
.blocklist_type("SSL|SSL_CTX|SESSION")
.raw_line("use openssl_sys::{SSL,SSL_CTX,SSL_SESSION};")
The last remaining issue is that we lose all the automagically derived traits, as bindgen is no longer able to verify that the blocklisted struct field type implements Copy
, Clone
or Debug
. This requires more advanced workarounds, such as providing our ParseCallbacks
implementation:
use bindgen::callbacks::{DeriveTrait, ImplementsTrait};
struct NgxExternalTypes;
impl bindgen::callbacks::ParseCallbacks for NgxExternalTypes {
fn blocklisted_type_implements_trait(&self, name: &str, derive_trait: DeriveTrait) -> Option<ImplementsTrait> {
// name is not preprocessed and could be `struct x`, `const x`, `const struct x` etc.
match name.split_ascii_whitespace().last()? {
"in_addr" => Some(match derive_trait {
DeriveTrait::Copy => ImplementsTrait::Yes,
DeriveTrait::Debug => ImplementsTrait::Yes,
DeriveTrait::Hash => ImplementsTrait::Yes,
DeriveTrait::PartialEqOrPartialOrd => ImplementsTrait::Yes,
_ => ImplementsTrait::No,
}),
"in6_addr" => Some(match derive_trait {
DeriveTrait::Copy => ImplementsTrait::Yes,
DeriveTrait::Hash => ImplementsTrait::Yes,
DeriveTrait::PartialEqOrPartialOrd => ImplementsTrait::Yes,
_ => ImplementsTrait::No,
}),
_ => None,
}
}
}