#[macro_export]
macro_rules! for_each_layout {
(all, $callback:ident $(, $extra:tt)*) => {
$callback! {
$($extra,)*
(Bool, bool, false),
(Int8, i8, 0),
(Int16, i16, 0),
(Int32, i32, 0),
(Int64, i64, 0),
(Int128, i128, 0),
(UInt8, u8, 0),
(UInt16, u16, 0),
(UInt32, u32, 0),
(UInt64, u64, 0),
(UInt128, u128, 0),
(Float32, f32, 0.0),
(Float64, f64, 0.0),
(Interval, (i32, i32, i64), (0, 0, 0)),
(Varlen, &str, ""),
}
};
(fixed, $callback:ident $(, $extra:tt)*) => {
$callback! {
$($extra,)*
(Bool, bool, false),
(Int8, i8, 0),
(Int16, i16, 0),
(Int32, i32, 0),
(Int64, i64, 0),
(Int128, i128, 0),
(UInt8, u8, 0),
(UInt16, u16, 0),
(UInt32, u32, 0),
(UInt64, u64, 0),
(UInt128, u128, 0),
(Float32, f32, 0.0),
(Float64, f64, 0.0),
(Interval, (i32, i32, i64), (0, 0, 0)),
}
};
(ordered, $callback:ident $(, $extra:tt)*) => {
$callback! {
$($extra,)*
(Bool, bool, false),
(Int8, i8, 0),
(Int16, i16, 0),
(Int32, i32, 0),
(Int64, i64, 0),
(Int128, i128, 0),
(UInt8, u8, 0),
(UInt16, u16, 0),
(UInt32, u32, 0),
(UInt64, u64, 0),
(UInt128, u128, 0),
(Interval, (i32, i32, i64), (0, 0, 0)),
}
};
(integer, $callback:ident $(, $extra:tt)*) => {
$callback! {
$($extra,)*
(Int8, i8, 0),
(Int16, i16, 0),
(Int32, i32, 0),
(Int64, i64, 0),
(Int128, i128, 0),
(UInt8, u8, 0),
(UInt16, u16, 0),
(UInt32, u32, 0),
(UInt64, u64, 0),
(UInt128, u128, 0),
}
};
(signed, $callback:ident $(, $extra:tt)*) => {
$callback! {
$($extra,)*
(Int8, i8, 0),
(Int16, i16, 0),
(Int32, i32, 0),
(Int64, i64, 0),
(Int128, i128, 0),
}
};
(unsigned, $callback:ident $(, $extra:tt)*) => {
$callback! {
$($extra,)*
(UInt8, u8, 0),
(UInt16, u16, 0),
(UInt32, u32, 0),
(UInt64, u64, 0),
(UInt128, u128, 0),
}
};
(exact, $callback:ident $(, $extra:tt)*) => {
$callback! {
$($extra,)*
(Int8, i8, 0),
(Int16, i16, 0),
(Int32, i32, 0),
(Int64, i64, 0),
(Int128, i128, 0),
(UInt8, u8, 0),
(UInt16, u16, 0),
(UInt32, u32, 0),
(UInt64, u64, 0),
}
};
(narrow, $callback:ident $(, $extra:tt)*) => {
$callback! {
$($extra,)*
(Int8, i8, 0),
(Int16, i16, 0),
(Int32, i32, 0),
(Int64, i64, 0),
(UInt8, u8, 0),
(UInt16, u16, 0),
(UInt32, u32, 0),
(UInt64, u64, 0),
}
};
(float, $callback:ident $(, $extra:tt)*) => {
$callback! {
$($extra,)*
(Float32, f32, 0.0),
(Float64, f64, 0.0),
}
};
}
#[cfg(test)]
mod tests {
use crate::{Buffer, Data};
macro_rules! names {
($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
&[$(stringify!($variant)),+]
};
}
const ALL: &[&str] = for_each_layout!(all, names);
const FIXED: &[&str] = for_each_layout!(fixed, names);
const ORDERED: &[&str] = for_each_layout!(ordered, names);
const INTEGER: &[&str] = for_each_layout!(integer, names);
const SIGNED: &[&str] = for_each_layout!(signed, names);
const UNSIGNED: &[&str] = for_each_layout!(unsigned, names);
const EXACT: &[&str] = for_each_layout!(exact, names);
const NARROW: &[&str] = for_each_layout!(narrow, names);
const FLOAT: &[&str] = for_each_layout!(float, names);
fn sorted(group: &[&str], extra: &[&str]) -> Vec<String> {
let mut names: Vec<String> =
group.iter().chain(extra).map(|name| (*name).to_string()).collect();
names.sort();
names
}
#[test]
fn no_group_lists_a_layout_twice() {
for group in [ALL, FIXED, ORDERED, INTEGER, SIGNED, UNSIGNED, EXACT, NARROW, FLOAT] {
let mut seen = group.to_vec();
seen.sort_unstable();
let mut once = seen.clone();
once.dedup();
assert_eq!(seen, once, "a group lists the same layout twice");
}
}
#[test]
fn every_group_is_part_of_the_whole_list() {
for group in [FIXED, ORDERED, INTEGER, SIGNED, UNSIGNED, EXACT, NARROW, FLOAT] {
for name in group {
assert!(ALL.contains(name), "{name} is in a group but not in the all group");
}
}
}
#[test]
fn each_group_plus_what_it_leaves_out_is_the_group_above_it() {
assert_eq!(sorted(ALL, &[]), sorted(FIXED, &["Varlen"]));
assert_eq!(sorted(FIXED, &[]), sorted(ORDERED, FLOAT));
assert_eq!(sorted(ORDERED, &[]), sorted(INTEGER, &["Bool", "Interval"]));
assert_eq!(sorted(INTEGER, &[]), sorted(SIGNED, UNSIGNED));
assert_eq!(sorted(INTEGER, &[]), sorted(EXACT, &["UInt128"]));
assert_eq!(sorted(EXACT, &[]), sorted(NARROW, &["Int128"]));
}
#[test]
fn the_element_type_and_the_zero_belong_to_the_variant() {
macro_rules! built {
($(($variant:ident, $native:ty, $zero:expr)),+ $(,)?) => {
vec![$(Data::$variant(Buffer::<$native>::from_vec(vec![$zero])),)+]
};
}
let runs = for_each_layout!(fixed, built);
assert_eq!(runs.len(), FIXED.len());
for run in runs {
assert_eq!(run.len(), 1);
}
}
}