use crate::ToOrderableBytes;
impl ToOrderableBytes for bool {
const ENCODED_LEN: usize = 1;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
[*self as u8]
}
}
impl ToOrderableBytes for u8 {
const ENCODED_LEN: usize = 1;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
[*self]
}
}
impl ToOrderableBytes for i8 {
const ENCODED_LEN: usize = 1;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
[(*self as u8) ^ (1u8 << 7)]
}
}
impl ToOrderableBytes for u16 {
const ENCODED_LEN: usize = 2;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
self.to_be_bytes()
}
}
impl ToOrderableBytes for i16 {
const ENCODED_LEN: usize = 2;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
((*self as u16) ^ (1u16 << 15)).to_be_bytes()
}
}
impl ToOrderableBytes for u32 {
const ENCODED_LEN: usize = 4;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
self.to_be_bytes()
}
}
impl ToOrderableBytes for i32 {
const ENCODED_LEN: usize = 4;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
((*self as u32) ^ (1u32 << 31)).to_be_bytes()
}
}
impl ToOrderableBytes for u64 {
const ENCODED_LEN: usize = 8;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
self.to_be_bytes()
}
}
impl ToOrderableBytes for i64 {
const ENCODED_LEN: usize = 8;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
((*self as u64) ^ (1u64 << 63)).to_be_bytes()
}
}
impl ToOrderableBytes for u128 {
const ENCODED_LEN: usize = 16;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
self.to_be_bytes()
}
}
impl ToOrderableBytes for i128 {
const ENCODED_LEN: usize = 16;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
((*self as u128) ^ (1u128 << 127)).to_be_bytes()
}
}
impl ToOrderableBytes for char {
const ENCODED_LEN: usize = 4;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
(*self as u32).to_be_bytes()
}
}
impl ToOrderableBytes for f32 {
const ENCODED_LEN: usize = 4;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
let value = if *self == -0.0 { 0.0 } else { *self };
let bits = value.to_bits();
let sign_extension = (bits as i32 >> 31) as u32;
let mask = sign_extension | (1u32 << 31);
(bits ^ mask).to_be_bytes()
}
}
impl ToOrderableBytes for f64 {
const ENCODED_LEN: usize = 8;
type Bytes = [u8; Self::ENCODED_LEN];
fn to_orderable_bytes(&self) -> [u8; Self::ENCODED_LEN] {
let value = if *self == -0.0 { 0.0 } else { *self };
let bits = value.to_bits();
let sign_extension = (bits as i64 >> 63) as u64;
let mask = sign_extension | (1u64 << 63);
(bits ^ mask).to_be_bytes()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bool_known_anchors() {
assert_eq!(false.to_orderable_bytes(), [0x00]);
assert_eq!(true.to_orderable_bytes(), [0x01]);
}
#[test]
fn bool_byte_order_matches_natural_order() {
assert!(false.to_orderable_bytes() < true.to_orderable_bytes());
}
#[test]
fn u8_known_anchors() {
assert_eq!(u8::MIN.to_orderable_bytes(), [0x00]);
assert_eq!(0x42u8.to_orderable_bytes(), [0x42]);
assert_eq!(u8::MAX.to_orderable_bytes(), [0xFF]);
}
#[test]
fn u8_byte_order_matches_natural_order() {
let ascending = [u8::MIN, 1, 100, 200, u8::MAX];
for window in ascending.windows(2) {
assert!(
window[0].to_orderable_bytes() < window[1].to_orderable_bytes(),
"{} < {} failed",
window[0],
window[1]
);
}
}
#[test]
fn i8_known_anchors() {
assert_eq!(i8::MIN.to_orderable_bytes(), [0x00]);
assert_eq!(0i8.to_orderable_bytes(), [0x80]);
assert_eq!(i8::MAX.to_orderable_bytes(), [0xFF]);
}
#[test]
fn i8_byte_order_matches_natural_order() {
let ascending = [i8::MIN, -100, -1, 0, 1, 100, i8::MAX];
for window in ascending.windows(2) {
assert!(
window[0].to_orderable_bytes() < window[1].to_orderable_bytes(),
"{} < {} failed",
window[0],
window[1]
);
}
}
#[test]
fn u16_known_anchors() {
assert_eq!(u16::MIN.to_orderable_bytes(), [0x00, 0x00]);
assert_eq!(u16::MAX.to_orderable_bytes(), [0xFF, 0xFF]);
assert_eq!(0x1234u16.to_orderable_bytes(), [0x12, 0x34]);
}
#[test]
fn u16_byte_order_matches_natural_order() {
let ascending = [u16::MIN, 1, 256, 10000, u16::MAX - 1, u16::MAX];
for window in ascending.windows(2) {
assert!(
window[0].to_orderable_bytes() < window[1].to_orderable_bytes(),
"{} < {} failed",
window[0],
window[1]
);
}
}
#[test]
fn i16_known_anchors() {
assert_eq!(i16::MIN.to_orderable_bytes(), [0x00, 0x00]);
assert_eq!(0i16.to_orderable_bytes(), [0x80, 0x00]);
assert_eq!(i16::MAX.to_orderable_bytes(), [0xFF, 0xFF]);
}
#[test]
fn i16_byte_order_matches_natural_order() {
let ascending = [i16::MIN, -10000, -1, 0, 1, 10000, i16::MAX];
for window in ascending.windows(2) {
assert!(
window[0].to_orderable_bytes() < window[1].to_orderable_bytes(),
"{} < {} failed",
window[0],
window[1]
);
}
}
#[test]
fn u32_known_anchors() {
assert_eq!(u32::MIN.to_orderable_bytes(), [0x00; 4]);
assert_eq!(u32::MAX.to_orderable_bytes(), [0xFF; 4]);
assert_eq!(
0x1234_5678u32.to_orderable_bytes(),
[0x12, 0x34, 0x56, 0x78]
);
}
#[test]
fn u32_byte_order_matches_natural_order() {
let ascending = [
u32::MIN,
1,
1 << 8,
1 << 16,
1 << 24,
u32::MAX - 1,
u32::MAX,
];
for window in ascending.windows(2) {
assert!(
window[0].to_orderable_bytes() < window[1].to_orderable_bytes(),
"{} < {} failed",
window[0],
window[1]
);
}
}
#[test]
fn i32_known_anchors() {
assert_eq!(i32::MIN.to_orderable_bytes(), [0x00, 0x00, 0x00, 0x00]);
assert_eq!(0i32.to_orderable_bytes(), [0x80, 0x00, 0x00, 0x00]);
assert_eq!(i32::MAX.to_orderable_bytes(), [0xFF, 0xFF, 0xFF, 0xFF]);
}
#[test]
fn i32_byte_order_matches_natural_order() {
let ascending = [i32::MIN, -1_000_000_000, -1, 0, 1, 1_000_000_000, i32::MAX];
for window in ascending.windows(2) {
assert!(
window[0].to_orderable_bytes() < window[1].to_orderable_bytes(),
"{} < {} failed",
window[0],
window[1]
);
}
}
#[test]
fn u64_known_anchors() {
assert_eq!(u64::MIN.to_orderable_bytes(), [0x00; 8]);
assert_eq!(u64::MAX.to_orderable_bytes(), [0xFF; 8]);
let one = 1u64.to_orderable_bytes();
let mut expected_one = [0u8; 8];
expected_one[7] = 1;
assert_eq!(one, expected_one);
}
#[test]
fn u64_byte_order_matches_natural_order() {
let ascending = [
u64::MIN,
1,
1 << 16,
1 << 32,
1 << 48,
u64::MAX - 1,
u64::MAX,
];
for window in ascending.windows(2) {
assert!(
window[0].to_orderable_bytes() < window[1].to_orderable_bytes(),
"{} < {} failed",
window[0],
window[1]
);
}
}
#[test]
fn i64_known_anchors() {
assert_eq!(i64::MIN.to_orderable_bytes(), [0x00; 8]);
assert_eq!(
0i64.to_orderable_bytes(),
[0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
);
assert_eq!(i64::MAX.to_orderable_bytes(), [0xFF; 8]);
}
#[test]
fn i64_byte_order_matches_natural_order() {
let ascending = [
i64::MIN,
-1_000_000_000_000,
-1,
0,
1,
1_000_000_000_000,
i64::MAX,
];
for window in ascending.windows(2) {
assert!(
window[0].to_orderable_bytes() < window[1].to_orderable_bytes(),
"{} < {} failed",
window[0],
window[1]
);
}
}
#[test]
fn u128_known_anchors() {
assert_eq!(u128::MIN.to_orderable_bytes(), [0; 16]);
assert_eq!(u128::MAX.to_orderable_bytes(), [0xFF; 16]);
let one = 1u128.to_orderable_bytes();
let mut expected_one = [0u8; 16];
expected_one[15] = 1;
assert_eq!(one, expected_one);
}
#[test]
fn u128_byte_order_matches_natural_order() {
let ascending = [
u128::MIN,
1,
(1u128 << 32),
(1u128 << 64),
(1u128 << 96),
u128::MAX - 1,
u128::MAX,
];
for window in ascending.windows(2) {
assert!(
window[0].to_orderable_bytes() < window[1].to_orderable_bytes(),
"{} < {} failed",
window[0],
window[1]
);
}
}
#[test]
fn i128_known_anchors() {
assert_eq!(i128::MIN.to_orderable_bytes(), [0; 16]);
assert_eq!(i128::MAX.to_orderable_bytes(), [0xFF; 16]);
let mut expected_zero = [0u8; 16];
expected_zero[0] = 0x80;
assert_eq!(0i128.to_orderable_bytes(), expected_zero);
}
#[test]
fn i128_byte_order_matches_natural_order() {
let ascending = [
i128::MIN,
-(1i128 << 96),
-(1i128 << 64),
-1,
0,
1,
(1i128 << 64),
(1i128 << 96),
i128::MAX,
];
for window in ascending.windows(2) {
assert!(
window[0].to_orderable_bytes() < window[1].to_orderable_bytes(),
"{} < {} failed",
window[0],
window[1]
);
}
}
#[test]
fn char_known_anchors() {
assert_eq!('A'.to_orderable_bytes(), [0x00, 0x00, 0x00, 0x41]);
assert_eq!('\0'.to_orderable_bytes(), [0x00, 0x00, 0x00, 0x00]);
assert_eq!(char::MAX.to_orderable_bytes(), [0x00, 0x10, 0xFF, 0xFF]);
}
#[test]
fn char_byte_order_matches_natural_order() {
let ascending = [
'\0',
'0',
'A',
'a',
'\u{7F}',
'\u{D7FF}',
'\u{E000}',
'\u{1F600}',
char::MAX,
];
for window in ascending.windows(2) {
assert!(
window[0].to_orderable_bytes() < window[1].to_orderable_bytes(),
"{:?} < {:?} failed",
window[0],
window[1]
);
}
}
#[test]
fn f32_zero_canonical_bytes() {
assert_eq!(0.0f32.to_orderable_bytes(), [0x80, 0x00, 0x00, 0x00]);
}
#[test]
fn f32_negative_zero_canonicalises_with_zero() {
assert_eq!((-0.0f32).to_orderable_bytes(), 0.0f32.to_orderable_bytes());
}
#[test]
fn f32_byte_order_matches_natural_order() {
let ascending = [
f32::NEG_INFINITY,
f32::MIN,
-1e30,
-1.0,
-f32::MIN_POSITIVE,
0.0,
f32::MIN_POSITIVE,
1.0,
1e30,
f32::MAX,
f32::INFINITY,
];
for window in ascending.windows(2) {
let a = window[0].to_orderable_bytes();
let b = window[1].to_orderable_bytes();
assert!(a < b, "{} < {} failed", window[0], window[1]);
}
}
#[test]
fn f32_subnormals_sort_above_zero_below_normals() {
let subnormal = f32::from_bits(1);
assert!(0.0f32.to_orderable_bytes() < subnormal.to_orderable_bytes());
assert!(subnormal.to_orderable_bytes() < f32::MIN_POSITIVE.to_orderable_bytes());
}
#[test]
fn f64_zero_canonical_bytes() {
assert_eq!(
0.0f64.to_orderable_bytes(),
[0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
);
}
#[test]
fn f64_negative_zero_canonicalises_with_zero() {
assert_eq!((-0.0f64).to_orderable_bytes(), 0.0f64.to_orderable_bytes());
}
#[test]
fn f64_byte_order_matches_natural_order() {
let ascending = [
f64::NEG_INFINITY,
f64::MIN,
-1e100,
-1.0,
-f64::MIN_POSITIVE,
0.0,
f64::MIN_POSITIVE,
1.0,
1e100,
f64::MAX,
f64::INFINITY,
];
for window in ascending.windows(2) {
let a = window[0].to_orderable_bytes();
let b = window[1].to_orderable_bytes();
assert!(a < b, "{} < {} failed", window[0], window[1]);
}
}
#[test]
fn f64_subnormals_sort_above_zero_below_normals() {
let subnormal = f64::from_bits(1);
assert!(0.0f64.to_orderable_bytes() < subnormal.to_orderable_bytes());
assert!(subnormal.to_orderable_bytes() < f64::MIN_POSITIVE.to_orderable_bytes());
}
}