use crate::{
XabiBytes, XabiErrorWire, XabiExport, XabiFuture, XabiManifest, XabiOption, XabiOwnedBytes,
XabiResult, XabiSlice, XabiStr, XabiWaker,
};
macro_rules! field {
($name:literal, $ty:ty, $field:tt, $field_ty:literal) => {
XabiFieldLayout::new($name, std::mem::offset_of!($ty, $field), $field_ty)
};
}
macro_rules! tuple_field {
($name:literal, $ty:ty, $field:tt, $field_ty:literal) => {
XabiFieldLayout::new($name, std::mem::offset_of!($ty, $field), $field_ty)
};
}
pub struct XabiLayout {
pub package: &'static str,
pub module: &'static str,
pub contract: XabiContractLayout,
pub collect: fn(&mut dyn XabiLayoutCollector),
}
pub trait XabiLayoutCollector {
fn push(&mut self, item: XabiLayoutItem);
}
impl XabiLayoutCollector for Vec<XabiLayoutItem> {
fn push(&mut self, item: XabiLayoutItem) {
Vec::push(self, item);
}
}
pub trait XabiLayoutSource {
fn collect_xabi_layout(collector: &mut dyn XabiLayoutCollector);
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum XabiLayoutItem {
Type(XabiTypeLayout),
VTable(XabiVTableLayout),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct XabiContractLayout {
pub abi_id: &'static str,
pub abi_version: u32,
pub rust_trait: &'static str,
}
impl XabiContractLayout {
pub const fn new(abi_id: &'static str, abi_version: u32, rust_trait: &'static str) -> Self {
Self {
abi_id,
abi_version,
rust_trait,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum XabiLayoutStability {
Fixed,
Prefix,
}
impl XabiLayoutStability {
pub const fn as_str(self) -> &'static str {
match self {
Self::Fixed => "fixed",
Self::Prefix => "prefix",
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct XabiTypeLayout {
pub name: &'static str,
pub stability: XabiLayoutStability,
pub size: usize,
pub align: usize,
pub fields: &'static [XabiFieldLayout],
}
impl XabiTypeLayout {
pub const fn new(
name: &'static str,
stability: XabiLayoutStability,
size: usize,
align: usize,
fields: &'static [XabiFieldLayout],
) -> Self {
Self {
name,
stability,
size,
align,
fields,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct XabiFieldLayout {
pub name: &'static str,
pub offset: usize,
pub ty: &'static str,
}
impl XabiFieldLayout {
pub const fn new(name: &'static str, offset: usize, ty: &'static str) -> Self {
Self { name, offset, ty }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct XabiVTableLayout {
pub name: &'static str,
pub full_size: usize,
pub min_size: usize,
}
impl XabiVTableLayout {
pub const fn new(name: &'static str, full_size: usize, min_size: usize) -> Self {
Self {
name,
full_size,
min_size,
}
}
}
#[doc(hidden)]
pub fn collect_runtime_layout(collector: &mut dyn XabiLayoutCollector) {
const XABI_STR_FIELDS: &[XabiFieldLayout] = &[
field!("ptr", XabiStr, ptr, "*const u8"),
field!("len", XabiStr, len, "usize"),
];
const XABI_SLICE_U8_FIELDS: &[XabiFieldLayout] = &[
field!("ptr", XabiSlice<u8>, ptr, "*const u8"),
field!("len", XabiSlice<u8>, len, "usize"),
];
const XABI_BYTES_FIELDS: &[XabiFieldLayout] =
&[tuple_field!("0", XabiBytes, 0, "XabiSlice<u8>")];
const XABI_OWNED_BYTES_FIELDS: &[XabiFieldLayout] = &[
field!("ptr", XabiOwnedBytes, ptr, "*mut u8"),
field!("len", XabiOwnedBytes, len, "usize"),
field!(
"free",
XabiOwnedBytes,
free,
"unsafe extern \"C\" fn(*mut u8, usize)"
),
];
const XABI_OPTION_FIELDS: &[XabiFieldLayout] = &[
field!("size", XabiOption, size, "usize"),
field!("abi_version", XabiOption, abi_version, "u32"),
field!("is_some", XabiOption, is_some, "u8"),
field!("payload", XabiOption, payload, "XabiOwnedBytes"),
];
const XABI_RESULT_FIELDS: &[XabiFieldLayout] = &[
field!("code", XabiResult, code, "i32"),
field!("payload", XabiResult, payload, "XabiOwnedBytes"),
];
const XABI_EXPORT_FIELDS: &[XabiFieldLayout] = &[
field!("size", XabiExport, size, "usize"),
field!("abi_version", XabiExport, abi_version, "u32"),
field!("abi_id", XabiExport, abi_id, "XabiStr"),
field!("name", XabiExport, name, "XabiStr"),
field!("contract_version", XabiExport, contract_version, "u32"),
field!("export_version", XabiExport, export_version, "u32"),
field!("capabilities", XabiExport, capabilities, "u64"),
field!(
"make",
XabiExport,
make,
"unsafe extern \"C\" fn() -> *mut c_void"
),
];
const XABI_MANIFEST_FIELDS: &[XabiFieldLayout] = &[
field!("size", XabiManifest, size, "usize"),
field!("abi_version", XabiManifest, abi_version, "u32"),
field!("exports", XabiManifest, exports, "XabiSlice<XabiExport>"),
];
const XABI_ERROR_WIRE_FIELDS: &[XabiFieldLayout] = &[
field!("size", XabiErrorWire, size, "usize"),
field!("abi_version", XabiErrorWire, abi_version, "u32"),
field!("kind", XabiErrorWire, kind, "u32"),
];
const XABI_WAKER_FIELDS: &[XabiFieldLayout] = &[
field!("size", XabiWaker, size, "usize"),
field!("abi_version", XabiWaker, abi_version, "u32"),
field!("instance", XabiWaker, instance, "*mut c_void"),
field!(
"clone",
XabiWaker,
clone,
"unsafe extern \"C\" fn(*mut c_void) -> XabiWaker"
),
field!(
"wake",
XabiWaker,
wake,
"unsafe extern \"C\" fn(*mut c_void)"
),
field!(
"wake_by_ref",
XabiWaker,
wake_by_ref,
"unsafe extern \"C\" fn(*mut c_void)"
),
field!(
"release",
XabiWaker,
release,
"unsafe extern \"C\" fn(*mut c_void)"
),
];
const XABI_FUTURE_FIELDS: &[XabiFieldLayout] = &[
field!("size", XabiFuture, size, "usize"),
field!("abi_version", XabiFuture, abi_version, "u32"),
field!("instance", XabiFuture, instance, "*mut c_void"),
field!(
"poll",
XabiFuture,
poll,
"unsafe extern \"C\" fn(*mut c_void, *const XabiWaker, *mut XabiResult) -> i32"
),
field!(
"release",
XabiFuture,
release,
"unsafe extern \"C\" fn(*mut c_void)"
),
];
type_layout::<XabiStr>(
collector,
"xabi::XabiStr",
XabiLayoutStability::Fixed,
XABI_STR_FIELDS,
);
type_layout::<XabiSlice<u8>>(
collector,
"xabi::XabiSlice<u8>",
XabiLayoutStability::Fixed,
XABI_SLICE_U8_FIELDS,
);
type_layout::<XabiBytes>(
collector,
"xabi::XabiBytes",
XabiLayoutStability::Fixed,
XABI_BYTES_FIELDS,
);
type_layout::<XabiOwnedBytes>(
collector,
"xabi::XabiOwnedBytes",
XabiLayoutStability::Fixed,
XABI_OWNED_BYTES_FIELDS,
);
type_layout::<XabiOption>(
collector,
"xabi::XabiOption",
XabiLayoutStability::Prefix,
XABI_OPTION_FIELDS,
);
type_layout::<XabiResult>(
collector,
"xabi::XabiResult",
XabiLayoutStability::Fixed,
XABI_RESULT_FIELDS,
);
type_layout::<XabiExport>(
collector,
"xabi::XabiExport",
XabiLayoutStability::Prefix,
XABI_EXPORT_FIELDS,
);
type_layout::<XabiManifest>(
collector,
"xabi::XabiManifest",
XabiLayoutStability::Prefix,
XABI_MANIFEST_FIELDS,
);
type_layout::<XabiErrorWire>(
collector,
"xabi::XabiErrorWire",
XabiLayoutStability::Prefix,
XABI_ERROR_WIRE_FIELDS,
);
type_layout::<XabiWaker>(
collector,
"xabi::XabiWaker",
XabiLayoutStability::Prefix,
XABI_WAKER_FIELDS,
);
type_layout::<XabiFuture>(
collector,
"xabi::XabiFuture",
XabiLayoutStability::Prefix,
XABI_FUTURE_FIELDS,
);
}
fn type_layout<T>(
collector: &mut dyn XabiLayoutCollector,
name: &'static str,
stability: XabiLayoutStability,
fields: &'static [XabiFieldLayout],
) {
collector.push(XabiLayoutItem::Type(XabiTypeLayout::new(
name,
stability,
std::mem::size_of::<T>(),
std::mem::align_of::<T>(),
fields,
)));
}