Skip to content

Commit e6c9c90

Browse files
committed
[Rust] Support struct type field with key attribute
- Derive `Eq` for struct types - Impl `Ord` and `PartialOrd` for struct types Fixes #8603
1 parent 5822c1c commit e6c9c90

File tree

21 files changed

+277
-21
lines changed

21 files changed

+277
-21
lines changed

samples/rust_generated/my_game/sample/vec_3_generated.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1111
use super::*;
1212
// struct Vec3, aligned to 4
1313
#[repr(transparent)]
14-
#[derive(Clone, Copy, PartialEq)]
14+
#[derive(Clone, Copy, PartialEq, Eq)]
1515
pub struct Vec3(pub [u8; 12]);
1616
impl Default for Vec3 {
1717
fn default() -> Self {
@@ -27,6 +27,18 @@ impl core::fmt::Debug for Vec3 {
2727
.finish()
2828
}
2929
}
30+
impl core::cmp::Ord for Vec3 {
31+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
32+
self.x().total_cmp(&other.x())
33+
.then(self.y().total_cmp(&other.y()))
34+
.then(self.z().total_cmp(&other.z()))
35+
}
36+
}
37+
impl core::cmp::PartialOrd for Vec3 {
38+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
39+
Some(self.cmp(other))
40+
}
41+
}
3042

3143
impl flatbuffers::SimpleToVerifyInSlice for Vec3 {}
3244
impl<'a> flatbuffers::Follow<'a> for Vec3 {

src/idl_gen_rust.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2625,7 +2625,7 @@ class RustGenerator : public BaseGenerator {
26252625
// hold for PartialOrd/Ord.
26262626
code_ += "// struct {{STRUCT_TY}}, aligned to {{ALIGN}}";
26272627
code_ += "#[repr(transparent)]";
2628-
code_ += "#[derive(Clone, Copy, PartialEq)]";
2628+
code_ += "#[derive(Clone, Copy, PartialEq, Eq)]";
26292629
code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}(pub [u8; {{STRUCT_SIZE}}]);";
26302630
code_ += "impl Default for {{STRUCT_TY}} { ";
26312631
code_ += " fn default() -> Self { ";
@@ -2646,6 +2646,30 @@ class RustGenerator : public BaseGenerator {
26462646
code_ += " .finish()";
26472647
code_ += " }";
26482648
code_ += "}";
2649+
2650+
// Ord for structs.
2651+
code_ += "impl core::cmp::Ord for {{STRUCT_TY}} {";
2652+
code_ += " fn cmp(&self, other: &Self) -> core::cmp::Ordering {";
2653+
bool first = true;
2654+
ForAllStructFields(struct_def, [&](const FieldDef &field) {
2655+
// Floating point types don't impl Ord, use `total_cmp` instead.
2656+
const auto cmp_fn =
2657+
IsFloat(field.value.type.base_type) ? "total_cmp" : "cmp";
2658+
const auto cmp_expr = "self." + namer_.Field(field) + "()." + cmp_fn +
2659+
"(&other." + namer_.Field(field) + "())";
2660+
// If we are not the first comparison, we use `then` to chain.
2661+
code_ += first ? " " + cmp_expr : " .then(" + cmp_expr + ")";
2662+
first = false;
2663+
});
2664+
code_ += " }";
2665+
code_ += "}";
2666+
2667+
// PartialOrd for structs.
2668+
code_ += "impl core::cmp::PartialOrd for {{STRUCT_TY}} {";
2669+
code_ += " fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {";
2670+
code_ += " Some(self.cmp(other))";
2671+
code_ += " }";
2672+
code_ += "}";
26492673
code_ += "";
26502674

26512675
// Generate impls for SafeSliceAccess (because all structs are endian-safe),

tests/arrays_test/my_game/example/array_struct_generated.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1111
use super::*;
1212
// struct ArrayStruct, aligned to 8
1313
#[repr(transparent)]
14-
#[derive(Clone, Copy, PartialEq)]
14+
#[derive(Clone, Copy, PartialEq, Eq)]
1515
pub struct ArrayStruct(pub [u8; 160]);
1616
impl Default for ArrayStruct {
1717
fn default() -> Self {
@@ -30,6 +30,21 @@ impl core::fmt::Debug for ArrayStruct {
3030
.finish()
3131
}
3232
}
33+
impl core::cmp::Ord for ArrayStruct {
34+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
35+
self.a().total_cmp(&other.a())
36+
.then(self.b().cmp(&other.b()))
37+
.then(self.c().cmp(&other.c()))
38+
.then(self.d().cmp(&other.d()))
39+
.then(self.e().cmp(&other.e()))
40+
.then(self.f().cmp(&other.f()))
41+
}
42+
}
43+
impl core::cmp::PartialOrd for ArrayStruct {
44+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
45+
Some(self.cmp(other))
46+
}
47+
}
3348

3449
impl flatbuffers::SimpleToVerifyInSlice for ArrayStruct {}
3550
impl<'a> flatbuffers::Follow<'a> for ArrayStruct {

tests/arrays_test/my_game/example/nested_struct_generated.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1111
use super::*;
1212
// struct NestedStruct, aligned to 8
1313
#[repr(transparent)]
14-
#[derive(Clone, Copy, PartialEq)]
14+
#[derive(Clone, Copy, PartialEq, Eq)]
1515
pub struct NestedStruct(pub [u8; 32]);
1616
impl Default for NestedStruct {
1717
fn default() -> Self {
@@ -28,6 +28,19 @@ impl core::fmt::Debug for NestedStruct {
2828
.finish()
2929
}
3030
}
31+
impl core::cmp::Ord for NestedStruct {
32+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
33+
self.a().cmp(&other.a())
34+
.then(self.b().cmp(&other.b()))
35+
.then(self.c().cmp(&other.c()))
36+
.then(self.d().cmp(&other.d()))
37+
}
38+
}
39+
impl core::cmp::PartialOrd for NestedStruct {
40+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
41+
Some(self.cmp(other))
42+
}
43+
}
3144

3245
impl flatbuffers::SimpleToVerifyInSlice for NestedStruct {}
3346
impl<'a> flatbuffers::Follow<'a> for NestedStruct {

tests/include_test1/my_game/other_name_space/unused_generated.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1111
use super::*;
1212
// struct Unused, aligned to 4
1313
#[repr(transparent)]
14-
#[derive(Clone, Copy, PartialEq)]
14+
#[derive(Clone, Copy, PartialEq, Eq)]
1515
pub struct Unused(pub [u8; 4]);
1616
impl Default for Unused {
1717
fn default() -> Self {
@@ -25,6 +25,16 @@ impl core::fmt::Debug for Unused {
2525
.finish()
2626
}
2727
}
28+
impl core::cmp::Ord for Unused {
29+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
30+
self.a().cmp(&other.a())
31+
}
32+
}
33+
impl core::cmp::PartialOrd for Unused {
34+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
35+
Some(self.cmp(other))
36+
}
37+
}
2838

2939
impl flatbuffers::SimpleToVerifyInSlice for Unused {}
3040
impl<'a> flatbuffers::Follow<'a> for Unused {

tests/include_test2/my_game/other_name_space/unused_generated.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1111
use super::*;
1212
// struct Unused, aligned to 4
1313
#[repr(transparent)]
14-
#[derive(Clone, Copy, PartialEq)]
14+
#[derive(Clone, Copy, PartialEq, Eq)]
1515
pub struct Unused(pub [u8; 4]);
1616
impl Default for Unused {
1717
fn default() -> Self {
@@ -25,6 +25,16 @@ impl core::fmt::Debug for Unused {
2525
.finish()
2626
}
2727
}
28+
impl core::cmp::Ord for Unused {
29+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
30+
self.a().cmp(&other.a())
31+
}
32+
}
33+
impl core::cmp::PartialOrd for Unused {
34+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
35+
Some(self.cmp(other))
36+
}
37+
}
2838

2939
impl flatbuffers::SimpleToVerifyInSlice for Unused {}
3040
impl<'a> flatbuffers::Follow<'a> for Unused {

tests/monster_test/my_game/example/ability_generated.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1111
use super::*;
1212
// struct Ability, aligned to 4
1313
#[repr(transparent)]
14-
#[derive(Clone, Copy, PartialEq)]
14+
#[derive(Clone, Copy, PartialEq, Eq)]
1515
pub struct Ability(pub [u8; 8]);
1616
impl Default for Ability {
1717
fn default() -> Self {
@@ -26,6 +26,17 @@ impl core::fmt::Debug for Ability {
2626
.finish()
2727
}
2828
}
29+
impl core::cmp::Ord for Ability {
30+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
31+
self.id().cmp(&other.id())
32+
.then(self.distance().cmp(&other.distance()))
33+
}
34+
}
35+
impl core::cmp::PartialOrd for Ability {
36+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
37+
Some(self.cmp(other))
38+
}
39+
}
2940

3041
impl flatbuffers::SimpleToVerifyInSlice for Ability {}
3142
impl<'a> flatbuffers::Follow<'a> for Ability {

tests/monster_test/my_game/example/struct_of_structs_generated.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1111
use super::*;
1212
// struct StructOfStructs, aligned to 4
1313
#[repr(transparent)]
14-
#[derive(Clone, Copy, PartialEq)]
14+
#[derive(Clone, Copy, PartialEq, Eq)]
1515
pub struct StructOfStructs(pub [u8; 20]);
1616
impl Default for StructOfStructs {
1717
fn default() -> Self {
@@ -27,6 +27,18 @@ impl core::fmt::Debug for StructOfStructs {
2727
.finish()
2828
}
2929
}
30+
impl core::cmp::Ord for StructOfStructs {
31+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
32+
self.a().cmp(&other.a())
33+
.then(self.b().cmp(&other.b()))
34+
.then(self.c().cmp(&other.c()))
35+
}
36+
}
37+
impl core::cmp::PartialOrd for StructOfStructs {
38+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
39+
Some(self.cmp(other))
40+
}
41+
}
3042

3143
impl flatbuffers::SimpleToVerifyInSlice for StructOfStructs {}
3244
impl<'a> flatbuffers::Follow<'a> for StructOfStructs {

tests/monster_test/my_game/example/struct_of_structs_of_structs_generated.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1111
use super::*;
1212
// struct StructOfStructsOfStructs, aligned to 4
1313
#[repr(transparent)]
14-
#[derive(Clone, Copy, PartialEq)]
14+
#[derive(Clone, Copy, PartialEq, Eq)]
1515
pub struct StructOfStructsOfStructs(pub [u8; 20]);
1616
impl Default for StructOfStructsOfStructs {
1717
fn default() -> Self {
@@ -25,6 +25,16 @@ impl core::fmt::Debug for StructOfStructsOfStructs {
2525
.finish()
2626
}
2727
}
28+
impl core::cmp::Ord for StructOfStructsOfStructs {
29+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
30+
self.a().cmp(&other.a())
31+
}
32+
}
33+
impl core::cmp::PartialOrd for StructOfStructsOfStructs {
34+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
35+
Some(self.cmp(other))
36+
}
37+
}
2838

2939
impl flatbuffers::SimpleToVerifyInSlice for StructOfStructsOfStructs {}
3040
impl<'a> flatbuffers::Follow<'a> for StructOfStructsOfStructs {

tests/monster_test/my_game/example/test_generated.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1111
use super::*;
1212
// struct Test, aligned to 2
1313
#[repr(transparent)]
14-
#[derive(Clone, Copy, PartialEq)]
14+
#[derive(Clone, Copy, PartialEq, Eq)]
1515
pub struct Test(pub [u8; 4]);
1616
impl Default for Test {
1717
fn default() -> Self {
@@ -26,6 +26,17 @@ impl core::fmt::Debug for Test {
2626
.finish()
2727
}
2828
}
29+
impl core::cmp::Ord for Test {
30+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
31+
self.a().cmp(&other.a())
32+
.then(self.b().cmp(&other.b()))
33+
}
34+
}
35+
impl core::cmp::PartialOrd for Test {
36+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
37+
Some(self.cmp(other))
38+
}
39+
}
2940

3041
impl flatbuffers::SimpleToVerifyInSlice for Test {}
3142
impl<'a> flatbuffers::Follow<'a> for Test {

tests/monster_test/my_game/example/vec_3_generated.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1111
use super::*;
1212
// struct Vec3, aligned to 8
1313
#[repr(transparent)]
14-
#[derive(Clone, Copy, PartialEq)]
14+
#[derive(Clone, Copy, PartialEq, Eq)]
1515
pub struct Vec3(pub [u8; 32]);
1616
impl Default for Vec3 {
1717
fn default() -> Self {
@@ -30,6 +30,21 @@ impl core::fmt::Debug for Vec3 {
3030
.finish()
3131
}
3232
}
33+
impl core::cmp::Ord for Vec3 {
34+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
35+
self.x().total_cmp(&other.x())
36+
.then(self.y().total_cmp(&other.y()))
37+
.then(self.z().total_cmp(&other.z()))
38+
.then(self.test1().total_cmp(&other.test1()))
39+
.then(self.test2().cmp(&other.test2()))
40+
.then(self.test3().cmp(&other.test3()))
41+
}
42+
}
43+
impl core::cmp::PartialOrd for Vec3 {
44+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
45+
Some(self.cmp(other))
46+
}
47+
}
3348

3449
impl flatbuffers::SimpleToVerifyInSlice for Vec3 {}
3550
impl<'a> flatbuffers::Follow<'a> for Vec3 {

tests/monster_test/my_game/other_name_space/unused_generated.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1111
use super::*;
1212
// struct Unused, aligned to 4
1313
#[repr(transparent)]
14-
#[derive(Clone, Copy, PartialEq)]
14+
#[derive(Clone, Copy, PartialEq, Eq)]
1515
pub struct Unused(pub [u8; 4]);
1616
impl Default for Unused {
1717
fn default() -> Self {
@@ -25,6 +25,16 @@ impl core::fmt::Debug for Unused {
2525
.finish()
2626
}
2727
}
28+
impl core::cmp::Ord for Unused {
29+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
30+
self.a().cmp(&other.a())
31+
}
32+
}
33+
impl core::cmp::PartialOrd for Unused {
34+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
35+
Some(self.cmp(other))
36+
}
37+
}
2838

2939
impl flatbuffers::SimpleToVerifyInSlice for Unused {}
3040
impl<'a> flatbuffers::Follow<'a> for Unused {

tests/monster_test_serialize/my_game/example/ability_generated.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1313
use super::*;
1414
// struct Ability, aligned to 4
1515
#[repr(transparent)]
16-
#[derive(Clone, Copy, PartialEq)]
16+
#[derive(Clone, Copy, PartialEq, Eq)]
1717
pub struct Ability(pub [u8; 8]);
1818
impl Default for Ability {
1919
fn default() -> Self {
@@ -28,6 +28,17 @@ impl core::fmt::Debug for Ability {
2828
.finish()
2929
}
3030
}
31+
impl core::cmp::Ord for Ability {
32+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
33+
self.id().cmp(&other.id())
34+
.then(self.distance().cmp(&other.distance()))
35+
}
36+
}
37+
impl core::cmp::PartialOrd for Ability {
38+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
39+
Some(self.cmp(other))
40+
}
41+
}
3142

3243
impl flatbuffers::SimpleToVerifyInSlice for Ability {}
3344
impl<'a> flatbuffers::Follow<'a> for Ability {

tests/monster_test_serialize/my_game/example/struct_of_structs_generated.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use self::flatbuffers::{EndianScalar, Follow};
1313
use super::*;
1414
// struct StructOfStructs, aligned to 4
1515
#[repr(transparent)]
16-
#[derive(Clone, Copy, PartialEq)]
16+
#[derive(Clone, Copy, PartialEq, Eq)]
1717
pub struct StructOfStructs(pub [u8; 20]);
1818
impl Default for StructOfStructs {
1919
fn default() -> Self {
@@ -29,6 +29,18 @@ impl core::fmt::Debug for StructOfStructs {
2929
.finish()
3030
}
3131
}
32+
impl core::cmp::Ord for StructOfStructs {
33+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
34+
self.a().cmp(&other.a())
35+
.then(self.b().cmp(&other.b()))
36+
.then(self.c().cmp(&other.c()))
37+
}
38+
}
39+
impl core::cmp::PartialOrd for StructOfStructs {
40+
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
41+
Some(self.cmp(other))
42+
}
43+
}
3244

3345
impl flatbuffers::SimpleToVerifyInSlice for StructOfStructs {}
3446
impl<'a> flatbuffers::Follow<'a> for StructOfStructs {

0 commit comments

Comments
 (0)