use std::fmt::Debug;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Type<I: Layout> {
pub layout: I::TypeLayout,
pub annotations: Vec<Annotation>,
pub variant: TypeVariant<I>,
}
impl<I: Layout> Type<I> {
pub fn into<J: Layout>(self) -> Type<J>
where
I::TypeLayout: Into<J::TypeLayout>,
I::FieldLayout: Into<J::FieldLayout>,
I::OpaqueLayout: Into<J::OpaqueLayout>,
{
Type {
layout: self.layout.into(),
annotations: self.annotations,
variant: self.variant.into(),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Annotation {
PragmaPack(u64),
AttrPacked,
Align(Option<u64>),
}
pub trait Layout {
type TypeLayout: Copy + Default + Debug + Eq + PartialEq;
type FieldLayout: Copy + Default + Debug + Eq + PartialEq;
type OpaqueLayout: Copy + Default + Debug + Eq + PartialEq;
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
pub struct TypeLayout {
pub size_bits: u64,
pub field_alignment_bits: u64,
pub pointer_alignment_bits: u64,
pub required_alignment_bits: u64,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
pub struct FieldLayout {
pub offset_bits: u64,
pub size_bits: u64,
}
impl Layout for TypeLayout {
type TypeLayout = TypeLayout;
type FieldLayout = FieldLayout;
type OpaqueLayout = TypeLayout;
}
impl Layout for () {
type TypeLayout = ();
type FieldLayout = ();
type OpaqueLayout = TypeLayout;
}
impl Into<()> for TypeLayout {
fn into(self) {}
}
impl Into<()> for FieldLayout {
fn into(self) {}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TypeVariant<I: Layout> {
Builtin(BuiltinType),
Record(Record<I>),
Typedef(Box<Type<I>>),
Array(Array<I>),
Enum(Vec<i128>),
Opaque(I::OpaqueLayout),
}
impl<I: Layout> TypeVariant<I> {
pub fn into<J: Layout>(self) -> TypeVariant<J>
where
I::TypeLayout: Into<J::TypeLayout>,
I::FieldLayout: Into<J::FieldLayout>,
I::OpaqueLayout: Into<J::OpaqueLayout>,
{
match self {
TypeVariant::Builtin(bi) => TypeVariant::Builtin(bi),
TypeVariant::Record(rt) => TypeVariant::Record(Record {
kind: rt.kind,
fields: rt.fields.into_iter().map(|v| v.into()).collect(),
}),
TypeVariant::Typedef(td) => TypeVariant::Typedef(Box::new((*td).into())),
TypeVariant::Array(at) => TypeVariant::Array(Array {
element_type: Box::new((*at.element_type).into()),
num_elements: at.num_elements,
}),
TypeVariant::Opaque(l) => TypeVariant::Opaque(l.into()),
TypeVariant::Enum(v) => TypeVariant::Enum(v),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Record<I: Layout> {
pub kind: RecordKind,
pub fields: Vec<RecordField<I>>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Array<I: Layout> {
pub element_type: Box<Type<I>>,
pub num_elements: Option<u64>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RecordField<I: Layout> {
pub layout: Option<I::FieldLayout>,
pub annotations: Vec<Annotation>,
pub named: bool,
pub bit_width: Option<u64>,
pub ty: Type<I>,
}
impl<I: Layout> RecordField<I> {
pub fn into<J: Layout>(self) -> RecordField<J>
where
I::TypeLayout: Into<J::TypeLayout>,
I::FieldLayout: Into<J::FieldLayout>,
I::OpaqueLayout: Into<J::OpaqueLayout>,
{
RecordField {
layout: self.layout.map(|v| v.into()),
annotations: self.annotations,
named: self.named,
bit_width: self.bit_width,
ty: self.ty.into(),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum RecordKind {
Struct,
Union,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum BuiltinType {
Unit,
Bool,
U8,
U16,
U32,
U64,
U128,
I8,
I16,
I32,
I64,
I128,
Char,
SignedChar,
UnsignedChar,
Short,
UnsignedShort,
Int,
UnsignedInt,
Long,
UnsignedLong,
LongLong,
UnsignedLongLong,
F32,
F64,
Float,
Double,
Pointer,
}