Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ if_rust_version = "1.0"
konst = "0.3.0" # old one for for rust 1.75
toml = "0.9.5"
rand = "0.9.2"
target-lexicon = "0.13.2"

[patch]

Expand Down
4 changes: 2 additions & 2 deletions prebindgen-proc-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ fn get_prebindgen_jsonl_path(group: &str) -> std::path::PathBuf {
};
let mut random_value = None;
// Try to really create file and repeat until success
// to avoid collisions in extremely rare case when two threads got
// to avoid collisions in extremely rare case when two threads got
// the same random value
let new_path = loop {
let postfix = if let Some(rv) = random_value {
Expand Down Expand Up @@ -271,7 +271,7 @@ pub fn prebindgen(args: TokenStream, input: TokenStream) -> TokenStream {

// Get the full path to the JSONL file
let file_path = get_prebindgen_jsonl_path(&group);
if let Err(_) = prebindgen::write_to_jsonl_file(&file_path, &[&new_record]) {
if let Err(_) = prebindgen::utils::write_to_jsonl_file(&file_path, &[&new_record]) {
return TokenStream::from(quote! {
compile_error!("Failed to write prebindgen record");
});
Expand Down
1 change: 1 addition & 0 deletions prebindgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ if_rust_version = { workspace = true }
konst = { workspace = true, features = ["cmp"] }
itertools = { workspace = true }
toml = { workspace = true }
target-lexicon = { workspace = true }

[features]
debug = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ use roxygen::roxygen;

use crate::{api::record::SourceLocation, codegen::process_features::process_item_features};

/// Builder for configuring FeatureFilter instances
/// Builder for configuring CfgFilter instances
///
/// Configures how feature flags in `#[cfg(feature="...")]` attributes
/// Configures how flags in `#[cfg(...)]` attributes
/// are processed when generating FFI bindings.
/// Supports features and target architecture filtering.
///
/// This filter is usually not necessary: the `Source` by default automatically reads
/// features enabled in the crate and removes any code guarded by disabled features.
///
/// But if necessary this option can be disabled (see and FeatureFilter can be applied
/// explicitly.
/// But if necessary this filtering on `Source` level can be disabled and CfgFilter
/// can be applied explicitly.
///
/// # Example
///
/// ```
/// let builder = prebindgen::batching::feature_filter::Builder::new()
/// let builder = prebindgen::batching::cfg_filter::Builder::new()
/// .disable_feature("unstable")
/// .enable_feature("std")
/// .match_feature("internal", "public")
Expand All @@ -32,15 +33,20 @@ pub struct Builder {
pub(crate) disable_unknown_features: bool,
// Source crate features constant name and features list in format "crate/f1 crate/f2"
pub(crate) features_assert: Option<(String, String)>,
// Selected target configuration parameters. When Some, only the selected value is enabled and others are disabled.
pub(crate) enabled_target_arch: Option<String>,
pub(crate) enabled_target_vendor: Option<String>,
pub(crate) enabled_target_os: Option<String>,
pub(crate) enabled_target_env: Option<String>,
}

impl Builder {
/// Create a new Builder for configuring FeatureFilter
/// Create a new Builder for configuring CfgFilter
///
/// # Example
///
/// ```
/// let builder = prebindgen::batching::feature_filter::Builder::new();
/// let builder = prebindgen::batching::cfg_filter::Builder::new();
/// ```
pub fn new() -> Self {
Self {
Expand All @@ -49,6 +55,10 @@ impl Builder {
feature_mappings: HashMap::new(),
disable_unknown_features: false,
features_assert: None,
enabled_target_arch: None,
enabled_target_vendor: None,
enabled_target_os: None,
enabled_target_env: None,
}
}

Expand All @@ -60,7 +70,7 @@ impl Builder {
/// # Example
///
/// ```
/// let builder = prebindgen::batching::feature_filter::Builder::new()
/// let builder = prebindgen::batching::cfg_filter::Builder::new()
/// .disable_feature("experimental")
/// .disable_feature("deprecated");
/// ```
Expand All @@ -83,7 +93,7 @@ impl Builder {
/// # Example
///
/// ```
/// let builder = prebindgen::batching::feature_filter::Builder::new()
/// let builder = prebindgen::batching::cfg_filter::Builder::new()
/// .enable_feature("experimental");
/// ```
#[roxygen]
Expand All @@ -95,6 +105,65 @@ impl Builder {
self.enabled_features.insert(feature.into());
self
}

/// Enable a specific target architecture. All other architectures are treated as disabled.
///
/// Only one architecture can be enabled. Calling this again overwrites the previous choice.
///
/// # Example
///
/// ```
/// let builder = prebindgen::batching::cfg_filter::Builder::new()
/// .enable_target_arch("x86_64");
/// ```
#[roxygen]
pub fn enable_target_arch<S: Into<String>>(
mut self,
/// The target architecture value to enable (e.g., "x86_64", "aarch64")
arch: S,
) -> Self {
self.enabled_target_arch = Some(arch.into());
self
}

/// Enable a specific target vendor. All other vendors are treated as disabled.
///
/// Only one vendor can be enabled. Calling this again overwrites the previous choice.
#[roxygen]
pub fn enable_target_vendor<S: Into<String>>(
mut self,
/// The target vendor value to enable (e.g., "apple", "pc")
vendor: S,
) -> Self {
self.enabled_target_vendor = Some(vendor.into());
self
}

/// Enable a specific target operating system. All other OS values are treated as disabled.
///
/// Only one OS can be enabled. Calling this again overwrites the previous choice.
#[roxygen]
pub fn enable_target_os<S: Into<String>>(
mut self,
/// The target operating system to enable (e.g., "macos", "linux", "windows")
os: S,
) -> Self {
self.enabled_target_os = Some(os.into());
self
}

/// Enable a specific target environment. All other environments are treated as disabled.
///
/// Only one environment can be enabled. Calling this again overwrites the previous choice.
#[roxygen]
pub fn enable_target_env<S: Into<String>>(
mut self,
/// The target environment to enable (e.g., "gnu", "musl", "msvc")
env: S,
) -> Self {
self.enabled_target_env = Some(env.into());
self
}
/// Map a feature name to a different name in the generated code
///
/// When processing code with `#[cfg(feature="...")]` attributes, features
Expand All @@ -104,7 +173,7 @@ impl Builder {
/// # Example
///
/// ```
/// let builder = prebindgen::batching::feature_filter::Builder::new()
/// let builder = prebindgen::batching::cfg_filter::Builder::new()
/// .match_feature("unstable", "unstable")
/// .match_feature("internal", "unstable");
/// ```
Expand Down Expand Up @@ -174,22 +243,26 @@ impl Builder {
self
}

/// Build the FeatureFilter instance with the configured options
/// Build the CfgFilter instance with the configured options
///
/// # Example
///
/// ```
/// let filter = prebindgen::batching::feature_filter::Builder::new()
/// let filter = prebindgen::batching::cfg_filter::Builder::new()
/// .disable_feature("internal")
/// .build();
/// ```
pub fn build(self) -> FeatureFilter {
pub fn build(self) -> CfgFilter {
// Determine if this filter is active (i.e., not pass-through)
let active = self.features_assert.is_some()
|| self.disable_unknown_features
|| !self.disabled_features.is_empty()
|| !self.enabled_features.is_empty()
|| !self.feature_mappings.is_empty();
|| !self.feature_mappings.is_empty()
|| self.enabled_target_arch.is_some()
|| self.enabled_target_vendor.is_some()
|| self.enabled_target_os.is_some()
|| self.enabled_target_env.is_some();

// Optionally create a prelude assertion comparing FEATURES const path with expected features string
let mut prelude_item: Option<(syn::Item, SourceLocation)> = None;
Expand Down Expand Up @@ -217,7 +290,7 @@ impl Builder {
prelude_item = Some((item, SourceLocation::default()));
}

FeatureFilter {
CfgFilter {
builder: self,
prelude_item,
prelude_emitted: false,
Expand All @@ -234,7 +307,7 @@ impl Default for Builder {

/// Filters prebindgen items based on Rust feature flags
///
/// The `FeatureFilter` processes items with `#[cfg(feature="...")]` attributes,
/// The `CfgFilter` processes items with `#[cfg(feature="...")]` attributes,
/// allowing selective inclusion, exclusion, or renaming of feature-gated code
/// in the generated FFI bindings.
///
Expand All @@ -249,7 +322,7 @@ impl Default for Builder {
/// # prebindgen::Source::init_doctest_simulate();
/// let source = prebindgen::Source::new("source_ffi");
///
/// let feature_filter = prebindgen::batching::FeatureFilter::builder()
/// let cfg_filter = prebindgen::batching::CfgFilter::builder()
/// .disable_feature("unstable")
/// .disable_feature("internal")
/// .enable_feature("std")
Expand All @@ -260,24 +333,24 @@ impl Default for Builder {
/// # use itertools::Itertools;
/// let filtered_items: Vec<_> = source
/// .items_all()
/// .batching(feature_filter.into_closure())
/// .batching(cfg_filter.into_closure())
/// .take(0) // Take 0 for doctest
/// .collect();
/// ```
pub struct FeatureFilter {
pub struct CfgFilter {
builder: Builder,
prelude_item: Option<(syn::Item, SourceLocation)>,
prelude_emitted: bool,
active: bool,
}

impl FeatureFilter {
/// Create a builder for configuring a feature filter instance
impl CfgFilter {
/// Create a builder for configuring a cfg filter instance
///
/// # Example
///
/// ```
/// let filter = prebindgen::batching::FeatureFilter::builder()
/// let filter = prebindgen::batching::CfgFilter::builder()
/// .disable_feature("unstable")
/// .enable_feature("std")
/// .build();
Expand Down Expand Up @@ -312,6 +385,10 @@ impl FeatureFilter {
&self.builder.enabled_features,
&self.builder.feature_mappings,
self.builder.disable_unknown_features,
&self.builder.enabled_target_arch,
&self.builder.enabled_target_vendor,
&self.builder.enabled_target_os,
&self.builder.enabled_target_env,
&source_location,
) {
return Some((item, source_location));
Expand Down
2 changes: 1 addition & 1 deletion prebindgen/src/api/batching/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pub(crate) mod feature_filter;
pub(crate) mod cfg_filter;
pub(crate) mod ffi_converter;
1 change: 1 addition & 0 deletions prebindgen/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ pub(crate) mod filter_map;
pub(crate) mod map;
pub(crate) mod record;
pub(crate) mod source;
pub(crate) mod utils;
Loading