use anyhow::Result;
pub struct Constant {
pub name: &'static str,
pub value: i128,
}
#[derive(Clone)]
pub enum Type {
U8,
U16,
U32,
U64,
Array(Box<Type>, usize),
Struct(Struct),
Union(Union),
TrailingString(&'static str),
TrailingTypes(Box<Type>, &'static str),
DynamicStruct(fn(&[u8]) -> Result<Vec<Field>>),
}
impl Type {
pub fn size(&self) -> usize {
match self {
Type::U8 => 1,
Type::U16 => 2,
Type::U32 => 4,
Type::U64 => 8,
Type::TrailingString(_) => 0,
Type::Array(t, n) => t.size() * n,
Type::Struct(s) => s.size(),
Type::Union(u) => u.size(),
Type::TrailingTypes(_, _) => 0,
Type::DynamicStruct(_) => 0,
}
}
pub fn is_static_sized(&self) -> bool {
match self {
Type::U8 | Type::U16 | Type::U32 | Type::U64 => true,
Type::Array(t, _) => t.is_static_sized(),
Type::Struct(s) => s.is_static_sized(),
Type::Union(u) => u.is_static_sized(),
Type::TrailingString(_) | Type::TrailingTypes(_, _) | Type::DynamicStruct(_) => false,
}
}
}
#[derive(Clone)]
pub struct Field {
pub name: Option<&'static str>,
pub ty: Type,
}
#[derive(Clone)]
pub struct Union {
pub name: &'static str,
pub fields: Vec<Field>,
}
impl Union {
pub fn size(&self) -> usize {
self.fields
.iter()
.max_by_key(|f| f.ty.size())
.map_or(0, |f| f.ty.size())
}
pub fn is_static_sized(&self) -> bool {
self.fields.iter().all(|f| f.ty.is_static_sized())
}
}
#[derive(Clone)]
pub struct Struct {
pub name: &'static str,
pub key_match: fn(i128, i128, i128) -> bool,
pub fields: Vec<Field>,
}
impl Struct {
pub fn size(&self) -> usize {
self.fields.iter().fold(0, |acc, f| acc + f.ty.size())
}
pub fn is_static_sized(&self) -> bool {
self.fields.iter().all(|f| f.ty.is_static_sized())
}
}
#[test]
fn test_type_size() {
{
let t = Type::U8;
assert_eq!(t.size(), 1);
}
{
let t = Type::U32;
assert_eq!(t.size(), 4);
}
{
let t = Type::U64;
assert_eq!(t.size(), 8);
}
{
let t = Type::Array(Box::new(Type::U8), 5);
assert_eq!(t.size(), 5);
}
{
let t = Type::Array(Box::new(Type::U32), 5);
assert_eq!(t.size(), 20);
}
{
let s = Struct {
name: "foo",
key_match: |_, _, _| false,
fields: vec![
Field {
name: Some("f1"),
ty: Type::U32,
},
Field {
name: Some("f2"),
ty: Type::U8,
},
],
};
let t = Type::Struct(s);
assert_eq!(t.size(), 5);
}
{
let s = Struct {
name: "foo",
key_match: |_, _, _| false,
fields: vec![
Field {
name: Some("f1"),
ty: Type::U32,
},
Field {
name: Some("f2"),
ty: Type::U8,
},
],
};
let t = Type::Array(Box::new(Type::Struct(s)), 4);
assert_eq!(t.size(), 20);
}
{
let u = Union {
name: "foo",
fields: vec![
Field {
name: Some("f1"),
ty: Type::U32,
},
Field {
name: Some("f2"),
ty: Type::U8,
},
Field {
name: Some("f3"),
ty: Type::U64,
},
],
};
let t = Type::Union(u);
assert_eq!(t.size(), 8);
}
{
let u = Union {
name: "union_one",
fields: vec![
Field {
name: Some("f1"),
ty: Type::U32,
},
Field {
name: Some("f1"),
ty: Type::U8,
},
],
};
let uu = Union {
name: "union_two",
fields: vec![
Field {
name: Some("f1"),
ty: Type::U8,
},
Field {
name: Some("f1"),
ty: Type::U16,
},
],
};
let s = Struct {
name: "foo",
key_match: |_, _, _| false,
fields: vec![
Field {
name: Some("f1"),
ty: Type::Union(u),
},
Field {
name: Some("f2"),
ty: Type::Union(uu),
},
],
};
let t = Type::Struct(s);
assert_eq!(t.size(), 6);
}
{
let s = Struct {
name: "foo",
key_match: |_, _, _| false,
fields: vec![
Field {
name: Some("f1"),
ty: Type::U32,
},
Field {
name: Some("f2"),
ty: Type::U8,
},
],
};
let ss = Struct {
name: "bar",
key_match: |_, _, _| false,
fields: vec![
Field {
name: Some("f1"),
ty: Type::U32,
},
Field {
name: Some("f2"),
ty: Type::Struct(s),
},
],
};
let t = Type::Struct(ss);
assert_eq!(t.size(), 9);
}
}