diff --git a/aptos-move/e2e-move-tests/src/tests/code_publishing.data/pack_stdlib/sources/cmp.move b/aptos-move/e2e-move-tests/src/tests/code_publishing.data/pack_stdlib/sources/cmp.move
new file mode 120000
index 00000000000000..638cf924ea5a89
--- /dev/null
+++ b/aptos-move/e2e-move-tests/src/tests/code_publishing.data/pack_stdlib/sources/cmp.move
@@ -0,0 +1 @@
+../../../../../../framework/move-stdlib/sources/cmp.move
\ No newline at end of file
diff --git a/aptos-move/e2e-move-tests/src/tests/code_publishing.data/pack_stdlib_incompat/sources/cmp.move b/aptos-move/e2e-move-tests/src/tests/code_publishing.data/pack_stdlib_incompat/sources/cmp.move
new file mode 120000
index 00000000000000..638cf924ea5a89
--- /dev/null
+++ b/aptos-move/e2e-move-tests/src/tests/code_publishing.data/pack_stdlib_incompat/sources/cmp.move
@@ -0,0 +1 @@
+../../../../../../framework/move-stdlib/sources/cmp.move
\ No newline at end of file
diff --git a/aptos-move/framework/move-stdlib/doc/cmp.md b/aptos-move/framework/move-stdlib/doc/cmp.md
new file mode 100644
index 00000000000000..5190e70a57acee
--- /dev/null
+++ b/aptos-move/framework/move-stdlib/doc/cmp.md
@@ -0,0 +1,260 @@
+
+
+
+# Module `0x1::cmp`
+
+
+
+- [Enum `Ordering`](#0x1_cmp_Ordering)
+- [Function `compare`](#0x1_cmp_compare)
+- [Function `is_eq`](#0x1_cmp_is_eq)
+- [Function `is_ne`](#0x1_cmp_is_ne)
+- [Function `is_lt`](#0x1_cmp_is_lt)
+- [Function `is_le`](#0x1_cmp_is_le)
+- [Function `is_gt`](#0x1_cmp_is_gt)
+- [Function `is_ge`](#0x1_cmp_is_ge)
+
+
+
+
+
+
+
+
+## Enum `Ordering`
+
+
+
+enum Ordering has copy, drop
+
+
+
+
+
+Variants
+
+
+
+Less
+
+
+
+Fields
+
+
+
+
+
+
+
+
+
+
+
+Equal
+
+
+
+Fields
+
+
+
+
+
+
+
+
+
+
+
+Greater
+
+
+
+Fields
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## Function `compare`
+
+Compares two values with the natural ordering:
+- native types are compared identically to <
and other operators
+- complex types
+- Structs and vectors - are compared lexicographically - first field/element is compared first,
+and if equal we proceed to the next.
+- enum's are compared first by their variant, and if equal - they are compared as structs are.
+
+
+public(friend) fun compare<T>(first: &T, second: &T): cmp::Ordering
+
+
+
+
+
+Implementation
+
+
+native public(friend) fun compare<T>(first: &T, second: &T): Ordering;
+
+
+
+
+
+
+
+
+## Function `is_eq`
+
+
+
+public fun is_eq(self: &cmp::Ordering): bool
+
+
+
+
+
+Implementation
+
+
+public fun is_eq(self: &Ordering): bool {
+ self is Ordering::Equal
+}
+
+
+
+
+
+
+
+
+## Function `is_ne`
+
+
+
+public fun is_ne(self: &cmp::Ordering): bool
+
+
+
+
+
+Implementation
+
+
+public fun is_ne(self: &Ordering): bool {
+ !(self is Ordering::Equal)
+}
+
+
+
+
+
+
+
+
+## Function `is_lt`
+
+
+
+public fun is_lt(self: &cmp::Ordering): bool
+
+
+
+
+
+Implementation
+
+
+public fun is_lt(self: &Ordering): bool {
+ self is Ordering::Less
+}
+
+
+
+
+
+
+
+
+## Function `is_le`
+
+
+
+public fun is_le(self: &cmp::Ordering): bool
+
+
+
+
+
+Implementation
+
+
+public fun is_le(self: &Ordering): bool {
+ !(self is Ordering::Greater)
+}
+
+
+
+
+
+
+
+
+## Function `is_gt`
+
+
+
+public fun is_gt(self: &cmp::Ordering): bool
+
+
+
+
+
+Implementation
+
+
+public fun is_gt(self: &Ordering): bool {
+ self is Ordering::Greater
+}
+
+
+
+
+
+
+
+
+## Function `is_ge`
+
+
+
+public fun is_ge(self: &cmp::Ordering): bool
+
+
+
+
+
+Implementation
+
+
+public fun is_ge(self: &Ordering): bool {
+ !(self is Ordering::Less)
+}
+
+
+
+
+
+
+
+[move-book]: https://aptos.dev/move/book/SUMMARY
diff --git a/aptos-move/framework/move-stdlib/doc/overview.md b/aptos-move/framework/move-stdlib/doc/overview.md
index 649873e8ab2f5f..3c93f83875d107 100644
--- a/aptos-move/framework/move-stdlib/doc/overview.md
+++ b/aptos-move/framework/move-stdlib/doc/overview.md
@@ -16,6 +16,7 @@ For on overview of the Move language, see the [Move Book][move-book].
- [`0x1::acl`](acl.md#0x1_acl)
- [`0x1::bcs`](bcs.md#0x1_bcs)
- [`0x1::bit_vector`](bit_vector.md#0x1_bit_vector)
+- [`0x1::cmp`](cmp.md#0x1_cmp)
- [`0x1::error`](error.md#0x1_error)
- [`0x1::features`](features.md#0x1_features)
- [`0x1::fixed_point32`](fixed_point32.md#0x1_fixed_point32)
diff --git a/aptos-move/framework/move-stdlib/sources/cmp.move b/aptos-move/framework/move-stdlib/sources/cmp.move
new file mode 100644
index 00000000000000..2c53c1874c3dec
--- /dev/null
+++ b/aptos-move/framework/move-stdlib/sources/cmp.move
@@ -0,0 +1,150 @@
+module std::cmp {
+ enum Ordering has copy, drop {
+ /// First value is less than the second value.
+ Less,
+ /// First value is equal to the second value.
+ Equal,
+ /// First value is greater than the second value.
+ Greater,
+ }
+
+ // TODO - functions here are `public(friend)` here for one release,
+ // and to be changed to `public` one release later.
+ #[test_only]
+ friend std::bcs_tests;
+
+ /// Compares two values with the natural ordering:
+ /// - native types are compared identically to `<` and other operators
+ /// - complex types
+ /// - Structs and vectors - are compared lexicographically - first field/element is compared first,
+ /// and if equal we proceed to the next.
+ /// - enum's are compared first by their variant, and if equal - they are compared as structs are.
+ native public(friend) fun compare(first: &T, second: &T): Ordering;
+
+ public fun is_eq(self: &Ordering): bool {
+ self is Ordering::Equal
+ }
+
+ public fun is_ne(self: &Ordering): bool {
+ !(self is Ordering::Equal)
+ }
+
+ public fun is_lt(self: &Ordering): bool {
+ self is Ordering::Less
+ }
+
+ public fun is_le(self: &Ordering): bool {
+ !(self is Ordering::Greater)
+ }
+
+ public fun is_gt(self: &Ordering): bool {
+ self is Ordering::Greater
+ }
+
+ public fun is_ge(self: &Ordering): bool {
+ !(self is Ordering::Less)
+ }
+
+ #[test_only]
+ struct SomeStruct has drop {
+ field_1: u64,
+ field_2: u64,
+ }
+
+ #[test_only]
+ enum SimpleEnum has drop {
+ V { field: u64 },
+ }
+
+ #[test_only]
+ enum SomeEnum has drop {
+ V1 { field_1: u64 },
+ V2 { field_2: u64 },
+ V3 { field_3: SomeStruct },
+ V4 { field_4: vector },
+ V5 { field_5: SimpleEnum },
+ }
+
+ #[test]
+ fun test_compare_numbers() {
+ assert!(is_ne(&compare(&1, &5)), 0);
+ assert!(!is_eq(&compare(&1, &5)), 0);
+ assert!(is_lt(&compare(&1, &5)), 1);
+ assert!(is_le(&compare(&1, &5)), 2);
+ assert!(is_eq(&compare(&5, &5)), 3);
+ assert!(!is_ne(&compare(&5, &5)), 3);
+ assert!(!is_lt(&compare(&5, &5)), 4);
+ assert!(is_le(&compare(&5, &5)), 5);
+ assert!(!is_eq(&compare(&7, &5)), 6);
+ assert!(is_ne(&compare(&7, &5)), 6);
+ assert!(!is_lt(&compare(&7, &5)), 7);
+ assert!(!is_le(&compare(&7, &5)), 8);
+
+ assert!(!compare(&1, &5).is_eq(), 0);
+ assert!(compare(&1, &5).is_ne(), 0);
+ assert!(compare(&1, &5).is_lt(), 1);
+ assert!(compare(&1, &5).is_le(), 2);
+ assert!(!compare(&1, &5).is_gt(), 1);
+ assert!(!compare(&1, &5).is_ge(), 1);
+ assert!(compare(&5, &5).is_eq(), 3);
+ assert!(!compare(&5, &5).is_ne(), 3);
+ assert!(!compare(&5, &5).is_lt(), 4);
+ assert!(compare(&5, &5).is_le(), 5);
+ assert!(!compare(&5, &5).is_gt(), 5);
+ assert!(compare(&5, &5).is_ge(), 5);
+ assert!(!compare(&7, &5).is_eq(), 6);
+ assert!(compare(&7, &5).is_ne(), 6);
+ assert!(!compare(&7, &5).is_lt(), 7);
+ assert!(!compare(&7, &5).is_le(), 8);
+ assert!(compare(&7, &5).is_gt(), 7);
+ assert!(compare(&7, &5).is_ge(), 8);
+ }
+
+ #[test]
+ fun test_compare_vectors() {
+ let empty = vector[]; // here for typing, for the second line
+ assert!(compare(&empty, &vector[1] ) is Ordering::Less, 0);
+ assert!(compare(&empty, &vector[] ) is Ordering::Equal, 1);
+ assert!(compare(&vector[1], &vector[] ) is Ordering::Greater, 2);
+ assert!(compare(&vector[1, 2], &vector[1, 2] ) is Ordering::Equal, 3);
+ assert!(compare(&vector[1, 2, 3], &vector[5] ) is Ordering::Less, 4);
+ assert!(compare(&vector[1, 2, 3], &vector[5, 6, 7]) is Ordering::Less, 5);
+ assert!(compare(&vector[1, 2, 3], &vector[1, 2, 7]) is Ordering::Less, 6);
+ }
+
+ #[test]
+ fun test_compare_structs() {
+ assert!(compare(&SomeStruct { field_1: 1, field_2: 2}, &SomeStruct { field_1: 1, field_2: 2}) is Ordering::Equal, 0);
+ assert!(compare(&SomeStruct { field_1: 1, field_2: 2}, &SomeStruct { field_1: 1, field_2: 3}) is Ordering::Less, 1);
+ assert!(compare(&SomeStruct { field_1: 1, field_2: 2}, &SomeStruct { field_1: 1, field_2: 1}) is Ordering::Greater, 2);
+ assert!(compare(&SomeStruct { field_1: 1, field_2: 2}, &SomeStruct { field_1: 1, field_2: 1}) is Ordering::Greater, 3);
+ }
+
+ #[test]
+ fun test_compare_vector_of_structs() {
+ assert!(compare(&vector[SomeStruct { field_1: 1, field_2: 2}, SomeStruct { field_1: 3, field_2: 4}], &vector[SomeStruct { field_1: 1, field_2: 3}]) is Ordering::Less, 0);
+ assert!(compare(&vector[SomeStruct { field_1: 1, field_2: 2}, SomeStruct { field_1: 3, field_2: 4}], &vector[SomeStruct { field_1: 1, field_2: 2}, SomeStruct { field_1: 1, field_2: 3}]) is Ordering::Greater, 1);
+ }
+
+ #[test]
+ fun test_compare_enums() {
+ assert!(compare(&SomeEnum::V1 { field_1: 6}, &SomeEnum::V1 { field_1: 6}) is Ordering::Equal, 0);
+ assert!(compare(&SomeEnum::V1 { field_1: 6}, &SomeEnum::V2 { field_2: 1}) is Ordering::Less, 1);
+ assert!(compare(&SomeEnum::V1 { field_1: 6}, &SomeEnum::V2 { field_2: 8}) is Ordering::Less, 2);
+ assert!(compare(&SomeEnum::V1 { field_1: 6}, &SomeEnum::V1 { field_1: 5}) is Ordering::Greater, 3);
+
+ assert!(compare(&SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 2}}, &SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 2}}) is Ordering::Equal, 4);
+ assert!(compare(&SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 2}}, &SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 3}}) is Ordering::Less, 5);
+ assert!(compare(&SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 2}}, &SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 1}}) is Ordering::Greater, 6);
+ assert!(compare(&SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 2}}, &SomeEnum::V3 { field_3: SomeStruct { field_1: 1, field_2: 1}}) is Ordering::Greater, 7);
+
+ assert!(compare(&SomeEnum::V4 { field_4: vector[1, 2]}, &SomeEnum::V4 { field_4: vector[1, 2]}) is Ordering::Equal, 8);
+ assert!(compare(&SomeEnum::V4 { field_4: vector[1, 2, 3]}, &SomeEnum::V4 { field_4: vector[5]}) is Ordering::Less, 9);
+ assert!(compare(&SomeEnum::V4 { field_4: vector[1, 2, 3]}, &SomeEnum::V4 { field_4: vector[5, 6, 7]}) is Ordering::Less, 10);
+ assert!(compare(&SomeEnum::V4 { field_4: vector[1, 2, 3]}, &SomeEnum::V4 { field_4: vector[1, 2, 7]}) is Ordering::Less, 11);
+
+ assert!(compare(&SomeEnum::V5 { field_5: SimpleEnum::V { field: 3}}, &SomeEnum::V5 { field_5: SimpleEnum::V { field: 3}}) is Ordering::Equal, 12);
+ assert!(compare(&SomeEnum::V5 { field_5: SimpleEnum::V { field: 5}}, &SomeEnum::V5 { field_5: SimpleEnum::V { field: 3}}) is Ordering::Greater, 13);
+ assert!(compare(&SomeEnum::V5 { field_5: SimpleEnum::V { field: 3}}, &SomeEnum::V5 { field_5: SimpleEnum::V { field: 5}}) is Ordering::Less, 14);
+ }
+}
diff --git a/aptos-move/framework/move-stdlib/tests/bcs_tests.move b/aptos-move/framework/move-stdlib/tests/bcs_tests.move
index 7fb6b0b57b0a9e..c22cf8126342d1 100644
--- a/aptos-move/framework/move-stdlib/tests/bcs_tests.move
+++ b/aptos-move/framework/move-stdlib/tests/bcs_tests.move
@@ -134,12 +134,27 @@ module std::bcs_tests {
assert!(option::none() == bcs::constant_serialized_size>>(), 3);
}
- // enum Singleton {
- // V1(u64),
- // }
-
- // fun encode_enum() {
- // assert!(option::none() == bcs::constant_serialized_size());
- // assert!(option::none() == bcs::constant_serialized_size>());
- // }
+ enum Singleton {
+ V1(u64),
+ }
+
+ fun encode_enum() {
+ assert!(option::none() == bcs::constant_serialized_size());
+ assert!(option::none() == bcs::constant_serialized_size>());
+ }
+
+ // test that serialization is little-endian, and so produces different
+ // ordering than "expected" natural ordering.
+ #[test]
+ fun bcs_comparison() {
+ let val = 256 * 4 + 2;
+ let other = 256 * 2 + 4;
+
+ assert!(std::cmp::compare(&val, &other).is_gt());
+
+ let bytes_val = bcs::to_bytes(&val);
+ let bytes_other = bcs::to_bytes(&other);
+
+ assert!(std::cmp::compare(&bytes_val, &bytes_other).is_lt());
+ }
}
diff --git a/execution/executor/tests/internal_indexer_test.rs b/execution/executor/tests/internal_indexer_test.rs
index 13d03f80926932..0a2872e98582a0 100644
--- a/execution/executor/tests/internal_indexer_test.rs
+++ b/execution/executor/tests/internal_indexer_test.rs
@@ -204,6 +204,7 @@ fn test_db_indexer_data() {
ident_str!("acl"),
ident_str!("any"),
ident_str!("bcs"),
+ ident_str!("cmp"),
ident_str!("dkg"),
ident_str!("mem"),
ident_str!("code"),