use crate::dtype::DType;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldDescriptor {
pub name: &'static str,
pub dtype: DType,
pub offset: usize,
pub size: usize,
}
pub unsafe trait FerrayRecord: Clone + Send + Sync + 'static {
fn field_descriptors() -> &'static [FieldDescriptor];
fn record_size() -> usize;
#[must_use]
fn field_by_name(name: &str) -> Option<&'static FieldDescriptor> {
Self::field_descriptors().iter().find(|fd| fd.name == name)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[repr(C)]
#[derive(Clone, Debug)]
struct TestRecord {
x: f64,
y: f64,
label: i32,
}
unsafe impl FerrayRecord for TestRecord {
fn field_descriptors() -> &'static [FieldDescriptor] {
static FIELDS: [FieldDescriptor; 3] = [
FieldDescriptor {
name: "x",
dtype: DType::F64,
offset: 0,
size: 8,
},
FieldDescriptor {
name: "y",
dtype: DType::F64,
offset: 8,
size: 8,
},
FieldDescriptor {
name: "label",
dtype: DType::I32,
offset: 16,
size: 4,
},
];
&FIELDS
}
fn record_size() -> usize {
core::mem::size_of::<Self>()
}
}
#[test]
fn record_field_descriptors() {
let fields = TestRecord::field_descriptors();
assert_eq!(fields.len(), 3);
assert_eq!(fields[0].name, "x");
assert_eq!(fields[0].dtype, DType::F64);
assert_eq!(fields[1].name, "y");
assert_eq!(fields[2].name, "label");
assert_eq!(fields[2].dtype, DType::I32);
}
#[test]
fn record_field_by_name() {
let fd = TestRecord::field_by_name("y").unwrap();
assert_eq!(fd.dtype, DType::F64);
assert_eq!(fd.offset, 8);
assert!(TestRecord::field_by_name("nonexistent").is_none());
}
#[test]
fn record_size() {
assert!(TestRecord::record_size() >= 20); }
}