use super::*;
use crate::repr::{Batch, BatchBuilder};
use crate::schema::TypeCode;
use crate::test_support::Rng;
use crate::test_support::{le_cell, opk_pk, random_schema, row_key};
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
enum Cell {
Signed(i128),
Unsigned(u128),
Float(u64),
Bytes(Vec<u8>),
}
type Model = (Vec<u8>, Vec<Option<Cell>>);
fn random_cell(rng: &mut Rng, col: &SchemaColumn, bb: &mut BatchBuilder) -> Option<Cell> {
if col.nullable && rng.gen_range(4) == 0 {
bb.put_null();
return None;
}
let w = col.size() as usize;
let tc = col.type_code;
Some(if tc.is_german_string() {
let long = |c: u8| [&[b'x'; 20][..], &[c]].concat();
let v = rng.pick(&[vec![], b"a".to_vec(), b"ab".to_vec(), long(b'a'), long(b'b')]);
bb.put_blob(&v);
Cell::Bytes(v)
} else if matches!(tc, TypeCode::F32 | TypeCode::F64) {
let v = rng.pick(&[0.0, -0.0, 1.0, -1.0, f64::NAN, f64::INFINITY, f64::NEG_INFINITY]);
bb.put_float(v);
let (bits, top) = match w {
4 => ((v as f32).to_bits() as u64, 31),
_ => (v.to_bits(), 63),
};
let key = if bits >> top == 1 { !bits } else { bits | 1 << top };
Cell::Float(key & u64::MAX >> (63 - top))
} else {
let mut le = vec![0u8; w];
match rng.gen_range(5) {
0 => {}
1 => le[0] = 1,
2 => le.fill(0xFF),
3 => {
le.fill(0xFF);
le[w - 1] = 0x7F;
}
_ => le[w - 1] = 0x80,
}
bb.put_int(le_cell(&le));
let negative = tc.is_signed_int() && le[w - 1] & 0x80 != 0;
let mut v = [if negative { 0xFF } else { 0 }; 16];
v[..w].copy_from_slice(&le);
match tc.is_signed_int() {
true => Cell::Signed(i128::from_le_bytes(v)),
false => Cell::Unsigned(u128::from_le_bytes(v)),
}
})
}
fn random_row(rng: &mut Rng, s: &SchemaDescriptor) -> (Batch, Model) {
let natives: Vec<u128> = s.pk_columns().map(|_| rng.pick(&[0, 1, u128::MAX])).collect();
let pk = opk_pk(s, &natives);
let mut bb = BatchBuilder::new(s);
bb.begin_row_bytes(&pk, 1);
let cells = s.payload_columns().map(|(_, c)| random_cell(rng, c, &mut bb)).collect();
bb.end_row();
(bb.finish(), (pk, cells))
}
fn selected<O: PayloadOrder>(s: &SchemaDescriptor, a: &Batch, b: &Batch, order: O) -> Ordering {
order.compare(s, a, 0, b, 0)
}
#[test]
fn row_order_is_the_pk_bytes_then_each_typed_payload_cell() {
let fixed_ints: Vec<TypeCode> = TypeCode::ALL.iter().copied().filter(|t| t.is_fixed_int()).collect();
let mut rng = Rng::new(0x000D_E20F);
for i in 0..4000 {
let s = match i % 2 {
0 => random_schema(&mut rng, TypeCode::ALL, true),
_ => random_schema(&mut rng, &fixed_ints, false),
};
let (a, ma) = random_row(&mut rng, &s);
let (b, mb) = random_row(&mut rng, &s);
let payload = compare_rows(&s, &a, 0, &b, 0);
assert_eq!(payload, ma.1.cmp(&mb.1), "{s:?}: {ma:?} vs {mb:?}");
assert_eq!(
compare_full_rows(&s, &a, 0, &b, 0),
ma.cmp(&mb),
"{s:?}: {ma:?} vs {mb:?}"
);
assert_eq!(
with_payload_cmp!(s, selected, &s, &a, &b),
payload,
"{s:?}: {ma:?} vs {mb:?}"
);
assert_eq!(
ma == mb,
row_key(&a, &s, 0) == row_key(&b, &s, 0),
"{s:?}: {ma:?} vs {mb:?}"
);
if s.payload_columns()
.all(|(_, c)| !c.nullable && c.type_code.is_fixed_int())
{
assert_eq!(s.payload_cmp, PayloadCmpKind::FixedIntNonnull, "{s:?}");
}
}
}