Skip to content

Commit a277f97

Browse files
committed
Fix non-deterministic ordering of generated enum constants
1 parent 40d8071 commit a277f97

File tree

1 file changed

+26
-20
lines changed

1 file changed

+26
-20
lines changed

bindings_generator/src/classes.rs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ pub(crate) fn generate_class_constants(class: &GodotClass) -> TokenStream {
6767

6868
let mut class_constants: Vec<(&ConstantName, &ConstantValue)> =
6969
class.constants.iter().collect();
70-
class_constants.sort_by(|a, b| a.0.cmp(b.0));
70+
class_constants.sort_by(constant_sorter);
7171

7272
for (name, value) in &class_constants {
7373
let name = format_ident!("{}", name);
@@ -88,33 +88,18 @@ pub(crate) fn generate_class_constants(class: &GodotClass) -> TokenStream {
8888
}
8989
}
9090

91-
fn generate_enum_name(class_name: &str, enum_name: &str) -> String {
92-
// In order to not pollute the API with more Result types,
93-
// rename the Result enum used by Search to SearchResult
94-
// to_camel_case() is used to make the enums more Rust like.
95-
// DOFBlurQuality => DofBlurQuality
96-
match enum_name {
97-
"Result" => {
98-
let mut res = String::from(class_name);
99-
res.push_str(enum_name);
100-
res.to_camel_case()
101-
}
102-
_ => enum_name.to_camel_case(),
103-
}
104-
}
105-
10691
pub(crate) fn generate_enums(class: &GodotClass) -> TokenStream {
107-
// TODO: check whether the start of the variant name is
108-
// equal to the end of the enum name and if so don't repeat it
109-
// it. For example ImageFormat::Rgb8 instead of ImageFormat::FormatRgb8.
92+
// TODO: check whether the start of the variant name is equal to the end of the enum name and if so, don't repeat it.
93+
// For example ImageFormat::Rgb8 instead of ImageFormat::FormatRgb8.
94+
11095
let mut enums: Vec<&Enum> = class.enums.iter().collect();
11196
enums.sort();
11297
let enums = enums.iter().map(|e| {
11398
let enum_name = generate_enum_name(&class.name, &e.name);
11499
let typ_name = format_ident!("{}", enum_name);
115100

116101
let mut values: Vec<_> = e.values.iter().collect();
117-
values.sort_by(|a, b| a.1.cmp(b.1));
102+
values.sort_by(constant_sorter);
118103

119104
let consts = values.iter().map(|(key, val)| {
120105
let key = key.to_uppercase();
@@ -150,3 +135,24 @@ pub(crate) fn generate_enums(class: &GodotClass) -> TokenStream {
150135
#(#enums)*
151136
}
152137
}
138+
139+
fn generate_enum_name(class_name: &str, enum_name: &str) -> String {
140+
// In order to not pollute the API with more Result types,
141+
// rename the Result enum used by Search to SearchResult
142+
// to_camel_case() is used to make the enums more Rust like.
143+
// DOFBlurQuality => DofBlurQuality
144+
match enum_name {
145+
"Result" => {
146+
let mut res = String::from(class_name);
147+
res.push_str(enum_name);
148+
res.to_camel_case()
149+
}
150+
_ => enum_name.to_camel_case(),
151+
}
152+
}
153+
154+
// Ensures deterministic order of constants, not dependent on inner hash-map or sort workings
155+
fn constant_sorter(a: &(&String, &i64), b: &(&String, &i64)) -> std::cmp::Ordering {
156+
Ord::cmp(a.1, b.1) // first, sort by integer value
157+
.then(Ord::cmp(a.0, b.0)) // and if equal, by name
158+
}

0 commit comments

Comments
 (0)