use alloc::vec::Vec;
pub use alloc::vec::Vec as SchemaVec;
pub use hekate_core::trace::ColumnType;
#[macro_export]
macro_rules! define_columns {
(
$(#[$meta:meta])*
$vis:vis $name:ident {
$( $field:ident : $kind:tt ),* $(,)?
}
) => {
$(#[$meta])*
#[derive(Clone, Copy, Debug)]
$vis struct $name;
impl $name {
$crate::define_columns!(@consts 0usize; $( $field : $kind, )*);
#[allow(unused_mut)]
pub fn build_layout() -> $crate::schema::SchemaVec<$crate::schema::ColumnType> {
let mut v = $crate::schema::SchemaVec::with_capacity(Self::NUM_COLUMNS);
$( $crate::define_columns!(@push v, $kind); )*
v
}
}
};
(@consts $offset:expr;) => {
pub const NUM_COLUMNS: usize = $offset;
};
(@consts $offset:expr; $field:ident : [$ty:ident; $n:expr], $( $rest:tt )*) => {
#[allow(dead_code)]
pub const $field: usize = $offset;
$crate::define_columns!(@consts $offset + $n; $( $rest )*);
};
(@consts $offset:expr; $field:ident : $ty:ident, $( $rest:tt )*) => {
#[allow(dead_code)]
pub const $field: usize = $offset;
$crate::define_columns!(@consts $offset + 1usize; $( $rest )*);
};
(@push $v:ident, $ty:ident) => {
$v.push($crate::schema::ColumnType::$ty);
};
(@push $v:ident, [$ty:ident; $n:expr]) => {
$v.extend(::core::iter::repeat($crate::schema::ColumnType::$ty).take($n));
};
}
pub fn chiplet_offsets(column_counts: &[usize]) -> Vec<usize> {
let mut offsets = Vec::with_capacity(column_counts.len());
let mut acc = 0;
for &count in column_counts {
offsets.push(acc);
acc += count;
}
offsets
}
#[cfg(test)]
mod tests {
use super::*;
define_columns! {
pub TestScalar {
A: B32,
B: B32,
Q: Bit,
}
}
define_columns! {
pub TestMixed {
ADDR_B0: B32,
ADDR_B1: B32,
ADDR_B2: B32,
ADDR_B3: B32,
IS_WRITE: Bit,
SELECTOR: Bit,
AUX_INV: B128,
DIFF_BYTE_IDX: [Bit; 8],
DIFF_BIT_IDX: [Bit; 8],
A_BITS: [Bit; 8],
}
}
define_columns! {
pub TestLargeArrays {
STATE_BITS: [Bit; 1600],
RC_BITS: [Bit; 64],
LANES: [B64; 25],
S_ROUND: Bit,
S_IN_OUT: Bit,
}
}
define_columns! {
pub TestEmpty {}
}
#[test]
fn scalar_indices() {
assert_eq!(TestScalar::A, 0);
assert_eq!(TestScalar::B, 1);
assert_eq!(TestScalar::Q, 2);
assert_eq!(TestScalar::NUM_COLUMNS, 3);
}
#[test]
fn mixed_scalar_and_array() {
assert_eq!(TestMixed::ADDR_B0, 0);
assert_eq!(TestMixed::ADDR_B1, 1);
assert_eq!(TestMixed::ADDR_B2, 2);
assert_eq!(TestMixed::ADDR_B3, 3);
assert_eq!(TestMixed::IS_WRITE, 4);
assert_eq!(TestMixed::SELECTOR, 5);
assert_eq!(TestMixed::AUX_INV, 6);
assert_eq!(TestMixed::DIFF_BYTE_IDX, 7);
assert_eq!(TestMixed::DIFF_BIT_IDX, 15);
assert_eq!(TestMixed::A_BITS, 23);
assert_eq!(TestMixed::NUM_COLUMNS, 31);
}
#[test]
fn large_arrays() {
assert_eq!(TestLargeArrays::STATE_BITS, 0);
assert_eq!(TestLargeArrays::RC_BITS, 1600);
assert_eq!(TestLargeArrays::LANES, 1664);
assert_eq!(TestLargeArrays::S_ROUND, 1689);
assert_eq!(TestLargeArrays::S_IN_OUT, 1690);
assert_eq!(TestLargeArrays::NUM_COLUMNS, 1691);
}
#[test]
fn empty_schema() {
assert_eq!(TestEmpty::NUM_COLUMNS, 0);
assert!(TestEmpty::build_layout().is_empty());
}
#[test]
fn scalar_layout() {
let layout = TestScalar::build_layout();
assert_eq!(layout.len(), 3);
assert_eq!(layout[0], ColumnType::B32);
assert_eq!(layout[1], ColumnType::B32);
assert_eq!(layout[2], ColumnType::Bit);
}
#[test]
fn mixed_layout() {
let layout = TestMixed::build_layout();
assert_eq!(layout.len(), TestMixed::NUM_COLUMNS);
assert_eq!(layout[0], ColumnType::B32);
assert_eq!(layout[4], ColumnType::Bit);
assert_eq!(layout[6], ColumnType::B128);
for i in 0..8 {
assert_eq!(layout[TestMixed::DIFF_BYTE_IDX + i], ColumnType::Bit);
}
}
#[test]
fn large_array_layout() {
let layout = TestLargeArrays::build_layout();
assert_eq!(layout.len(), 1691);
assert_eq!(layout[0], ColumnType::Bit);
assert_eq!(layout[1599], ColumnType::Bit);
assert_eq!(layout[1664], ColumnType::B64);
assert_eq!(layout[1688], ColumnType::B64);
assert_eq!(layout[1689], ColumnType::Bit);
}
#[test]
fn offsets_basic() {
let o = chiplet_offsets(&[9, 5, 10, 9, 17, 49]);
assert_eq!(o, vec![0, 9, 14, 24, 33, 50]);
}
#[test]
fn offsets_empty() {
assert!(chiplet_offsets(&[]).is_empty());
}
#[test]
fn offsets_single() {
assert_eq!(chiplet_offsets(&[42]), vec![0]);
}
}