diff --git a/Cargo.lock b/Cargo.lock index bfa0d5f..36cc203 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + [[package]] name = "bitflags" version = "1.2.1" @@ -32,6 +38,7 @@ version = "0.14.6" dependencies = [ "clap", "heck", + "indexmap", "log", "proc-macro2", "quote", @@ -74,6 +81,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + [[package]] name = "heck" version = "0.3.1" @@ -92,6 +105,16 @@ dependencies = [ "libc", ] +[[package]] +name = "indexmap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "itoa" version = "0.4.6" diff --git a/Cargo.toml b/Cargo.toml index 87eb387..069f091 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ travis-ci = { repository = "eqrion/cbindgen" } [dependencies] clap = { version = "2", optional = true } +indexmap = "1" log = "0.4" serde = { version = "1.0.103", default-features = false, features = ["derive"]} serde_json = "1.0" diff --git a/docs.md b/docs.md index cc2176a..4636768 100644 --- a/docs.md +++ b/docs.md @@ -683,7 +683,7 @@ swift_name_macro = "CF_SWIFT_NAME" # default: "None" rename_args = "PascalCase" -# This rule specifies if the order of functions will be sorted in some way. +# This rule specifies the order in which functions will be sorted. # # "Name": sort by the name of the function # "None": keep order in which the functions have been parsed @@ -885,6 +885,13 @@ allow_static_const = true # default: false allow_constexpr = false +# This rule specifies the order in which constants will be sorted. +# +# "Name": sort by the name of the constant +# "None": keep order in which the constants have been parsed +# +# default: "Name" +sort_by = "None" diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index fcbdf9a..a17e207 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -255,7 +255,7 @@ impl FromStr for ItemType { deserialize_enum_str!(ItemType); /// Type which specifies the sort order of functions -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum SortKey { Name, None, @@ -382,8 +382,8 @@ pub struct FunctionConfig { pub rename_args: RenameRule, /// An optional macro to use when generating Swift function name attributes pub swift_name_macro: Option, - /// Sort key for function names - pub sort_by: SortKey, + /// Sort key for functions + pub sort_by: Option, /// Optional text to output after functions which return `!`. pub no_return: Option, } @@ -397,7 +397,7 @@ impl Default for FunctionConfig { args: Layout::Auto, rename_args: RenameRule::None, swift_name_macro: None, - sort_by: SortKey::Name, + sort_by: None, no_return: None, } } @@ -644,6 +644,8 @@ pub struct ConstantConfig { pub allow_static_const: bool, /// Whether a generated constant should be constexpr in C++ mode. pub allow_constexpr: bool, + /// Sort key for constants + pub sort_by: Option, } impl Default for ConstantConfig { @@ -651,6 +653,7 @@ impl Default for ConstantConfig { ConstantConfig { allow_static_const: true, allow_constexpr: false, + sort_by: None, } } } @@ -835,6 +838,8 @@ pub struct Config { pub cpp_compat: bool, /// The style to declare structs, enums and unions in for C pub style: Style, + /// Default sort key for functions and constants. + pub sort_by: SortKey, /// The configuration options for parsing pub parse: ParseConfig, /// The configuration options for exporting @@ -889,6 +894,7 @@ impl Default for Config { language: Language::Cxx, cpp_compat: false, style: Style::Type, + sort_by: SortKey::Name, macro_expansion: Default::default(), parse: ParseConfig::default(), export: ExportConfig::default(), diff --git a/src/bindgen/ir/item.rs b/src/bindgen/ir/item.rs index 73915a6..57ac7fc 100644 --- a/src/bindgen/ir/item.rs +++ b/src/bindgen/ir/item.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use std::collections::BTreeMap; +use indexmap::IndexMap; use std::mem; use crate::bindgen::config::Config; @@ -75,13 +75,13 @@ pub enum ItemValue { #[derive(Debug, Clone)] pub struct ItemMap { - data: BTreeMap>, + data: IndexMap>, } impl ItemMap { pub fn default() -> ItemMap { ItemMap { - data: BTreeMap::new(), + data: Default::default(), } } @@ -150,7 +150,7 @@ impl ItemMap { where F: Fn(&T) -> bool, { - let data = mem::replace(&mut self.data, BTreeMap::new()); + let data = mem::replace(&mut self.data, Default::default()); for (name, container) in data { match container { diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index fdd6e17..fc0c44d 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::collections::HashMap; -use std::mem; use crate::bindgen::bindings::Bindings; use crate::bindgen::config::{Config, Language, SortKey}; @@ -58,10 +57,8 @@ impl Library { self.transfer_annotations(); self.simplify_standard_types(); - match self.config.function.sort_by { - SortKey::Name => { - self.functions.sort_by(|x, y| x.path.cmp(&y.path)); - } + match self.config.function.sort_by.unwrap_or(self.config.sort_by) { + SortKey::Name => self.functions.sort_by(|x, y| x.path.cmp(&y.path)), SortKey::None => { /* keep input order */ } } @@ -104,18 +101,28 @@ impl Library { let items = dependencies.order; let constants = if self.config.export.should_generate(ItemType::Constants) { - self.constants.to_vec() + let mut constants = self.constants.to_vec(); + match self.config.constant.sort_by.unwrap_or(self.config.sort_by) { + SortKey::Name => constants.sort_by(|x, y| x.path.cmp(&y.path)), + SortKey::None => { /* keep input order */ } + } + constants } else { vec![] }; let globals = if self.config.export.should_generate(ItemType::Globals) { - self.globals.to_vec() + let mut globals = self.globals.to_vec(); + match self.config.constant.sort_by.unwrap_or(self.config.sort_by) { + SortKey::Name => globals.sort_by(|x, y| x.path.cmp(&y.path)), + SortKey::None => { /* keep input order */ } + } + globals } else { vec![] }; let functions = if self.config.export.should_generate(ItemType::Functions) { - mem::replace(&mut self.functions, vec![]) + self.functions } else { vec![] }; diff --git a/template.toml b/template.toml index 0e515fd..e997f2d 100644 --- a/template.toml +++ b/template.toml @@ -43,6 +43,7 @@ line-endings = "LF" # also "CR", "CRLF", "Native" ############################# Codegen Options ################################## style = "both" +sort_by = "Name" # default for `fn.sort_by` and `const.sort_by` @@ -117,6 +118,7 @@ private_default_tagged_enum_constructor = false [const] allow_static_const = true allow_constexpr = false +sort_by = "Name" @@ -145,8 +147,3 @@ crates = [] all_features = false default_features = true features = [] - - - - - diff --git a/tests/expectations/both/constant_sort_name.c b/tests/expectations/both/constant_sort_name.c new file mode 100644 index 0000000..0ae1d49 --- /dev/null +++ b/tests/expectations/both/constant_sort_name.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +#define A 0 + +#define B 0 + +extern const uint8_t C; + +extern const uint8_t D; diff --git a/tests/expectations/both/constant_sort_name.compat.c b/tests/expectations/both/constant_sort_name.compat.c new file mode 100644 index 0000000..1b9032a --- /dev/null +++ b/tests/expectations/both/constant_sort_name.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#define A 0 + +#define B 0 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern const uint8_t C; + +extern const uint8_t D; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/both/constant_sort_none.c b/tests/expectations/both/constant_sort_none.c new file mode 100644 index 0000000..2ec6a14 --- /dev/null +++ b/tests/expectations/both/constant_sort_none.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +#define B 0 + +#define A 0 + +extern const uint8_t D; + +extern const uint8_t C; diff --git a/tests/expectations/both/constant_sort_none.compat.c b/tests/expectations/both/constant_sort_none.compat.c new file mode 100644 index 0000000..c9c7445 --- /dev/null +++ b/tests/expectations/both/constant_sort_none.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#define B 0 + +#define A 0 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern const uint8_t D; + +extern const uint8_t C; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/constant_sort_name.c b/tests/expectations/constant_sort_name.c new file mode 100644 index 0000000..0ae1d49 --- /dev/null +++ b/tests/expectations/constant_sort_name.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +#define A 0 + +#define B 0 + +extern const uint8_t C; + +extern const uint8_t D; diff --git a/tests/expectations/constant_sort_name.compat.c b/tests/expectations/constant_sort_name.compat.c new file mode 100644 index 0000000..1b9032a --- /dev/null +++ b/tests/expectations/constant_sort_name.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#define A 0 + +#define B 0 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern const uint8_t C; + +extern const uint8_t D; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/constant_sort_name.cpp b/tests/expectations/constant_sort_name.cpp new file mode 100644 index 0000000..6de3dda --- /dev/null +++ b/tests/expectations/constant_sort_name.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include + +static const uint8_t A = 0; + +static const uint8_t B = 0; + +extern "C" { + +extern const uint8_t C; + +extern const uint8_t D; + +} // extern "C" diff --git a/tests/expectations/constant_sort_none.c b/tests/expectations/constant_sort_none.c new file mode 100644 index 0000000..2ec6a14 --- /dev/null +++ b/tests/expectations/constant_sort_none.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +#define B 0 + +#define A 0 + +extern const uint8_t D; + +extern const uint8_t C; diff --git a/tests/expectations/constant_sort_none.compat.c b/tests/expectations/constant_sort_none.compat.c new file mode 100644 index 0000000..c9c7445 --- /dev/null +++ b/tests/expectations/constant_sort_none.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#define B 0 + +#define A 0 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern const uint8_t D; + +extern const uint8_t C; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/constant_sort_none.cpp b/tests/expectations/constant_sort_none.cpp new file mode 100644 index 0000000..6e7360b --- /dev/null +++ b/tests/expectations/constant_sort_none.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include + +static const uint8_t B = 0; + +static const uint8_t A = 0; + +extern "C" { + +extern const uint8_t D; + +extern const uint8_t C; + +} // extern "C" diff --git a/tests/expectations/tag/constant_sort_name.c b/tests/expectations/tag/constant_sort_name.c new file mode 100644 index 0000000..0ae1d49 --- /dev/null +++ b/tests/expectations/tag/constant_sort_name.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +#define A 0 + +#define B 0 + +extern const uint8_t C; + +extern const uint8_t D; diff --git a/tests/expectations/tag/constant_sort_name.compat.c b/tests/expectations/tag/constant_sort_name.compat.c new file mode 100644 index 0000000..1b9032a --- /dev/null +++ b/tests/expectations/tag/constant_sort_name.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#define A 0 + +#define B 0 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern const uint8_t C; + +extern const uint8_t D; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/tag/constant_sort_none.c b/tests/expectations/tag/constant_sort_none.c new file mode 100644 index 0000000..2ec6a14 --- /dev/null +++ b/tests/expectations/tag/constant_sort_none.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +#define B 0 + +#define A 0 + +extern const uint8_t D; + +extern const uint8_t C; diff --git a/tests/expectations/tag/constant_sort_none.compat.c b/tests/expectations/tag/constant_sort_none.compat.c new file mode 100644 index 0000000..c9c7445 --- /dev/null +++ b/tests/expectations/tag/constant_sort_none.compat.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#define B 0 + +#define A 0 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern const uint8_t D; + +extern const uint8_t C; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/rust/constant_sort_name.rs b/tests/rust/constant_sort_name.rs new file mode 100644 index 0000000..96c1185 --- /dev/null +++ b/tests/rust/constant_sort_name.rs @@ -0,0 +1,7 @@ +pub const B: u8 = 0; +pub const A: u8 = 0; + +#[no_mangle] +pub static D: u8 = 0; +#[no_mangle] +pub static C: u8 = 0; diff --git a/tests/rust/constant_sort_none.rs b/tests/rust/constant_sort_none.rs new file mode 100644 index 0000000..96c1185 --- /dev/null +++ b/tests/rust/constant_sort_none.rs @@ -0,0 +1,7 @@ +pub const B: u8 = 0; +pub const A: u8 = 0; + +#[no_mangle] +pub static D: u8 = 0; +#[no_mangle] +pub static C: u8 = 0; diff --git a/tests/rust/constant_sort_none.toml b/tests/rust/constant_sort_none.toml new file mode 100644 index 0000000..182d0d4 --- /dev/null +++ b/tests/rust/constant_sort_none.toml @@ -0,0 +1,2 @@ +[const] +sort_by = "None"