use std::borrow::Cow;
use std::fmt::{self, Display};
use std::str;
pub use type_layout_derive::TypeLayout;
#[doc(hidden)]
pub use memoffset;
pub trait TypeLayout {
fn type_layout() -> TypeLayoutInfo;
}
#[derive(Debug)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub struct TypeLayoutInfo {
pub name: Cow<'static, str>,
pub size: usize,
pub alignment: usize,
pub fields: Vec<Field>,
}
#[derive(Debug)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub enum Field {
Field {
name: Cow<'static, str>,
ty: Cow<'static, str>,
size: usize,
},
Padding {
size: usize,
},
}
impl fmt::Display for TypeLayoutInfo {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
writeln!(
formatter,
"{} (size {}, alignment {})",
self.name, self.size, self.alignment
)?;
let longest_name = self
.fields
.iter()
.map(|field| match field {
Field::Field { name, .. } => name.len(),
Field::Padding { .. } => "[padding]".len(),
})
.max()
.unwrap_or(1);
let widths = RowWidths {
offset: "Offset".len(),
name: longest_name,
size: "Size".len(),
};
write_row(
formatter,
widths,
Row {
offset: "Offset",
name: "Name",
size: "Size",
},
)?;
write_row(
formatter,
widths,
Row {
offset: "------",
name: str::repeat("-", longest_name),
size: "----",
},
)?;
let mut offset = 0;
for field in &self.fields {
match field {
Field::Field { name, size, .. } => {
write_row(formatter, widths, Row { offset, name, size })?;
offset += size;
}
Field::Padding { size } => {
write_row(
formatter,
widths,
Row {
offset,
name: "[padding]",
size,
},
)?;
offset += size;
}
}
}
Ok(())
}
}
#[derive(Clone, Copy)]
struct RowWidths {
offset: usize,
name: usize,
size: usize,
}
struct Row<O, N, S> {
offset: O,
name: N,
size: S,
}
fn write_row<O: Display, N: Display, S: Display>(
formatter: &mut fmt::Formatter,
widths: RowWidths,
row: Row<O, N, S>,
) -> fmt::Result {
writeln!(
formatter,
"| {:<offset_width$} | {:<name_width$} | {:<size_width$} |",
row.offset,
row.name,
row.size,
offset_width = widths.offset,
name_width = widths.name,
size_width = widths.size
)
}