#![allow(clippy::expect_used)]
use core::mem::{align_of, offset_of, size_of};
use polyplug_abi::{AbiError, Buffer, GuestContractHandle, StringView};
#[test]
fn layout_u8_size_align() {
assert_eq!(size_of::<u8>(), 1, "u8 size must be 1 byte");
assert_eq!(align_of::<u8>(), 1, "u8 alignment must be 1 byte");
}
#[test]
fn layout_u16_size_align() {
assert_eq!(size_of::<u16>(), 2, "u16 size must be 2 bytes");
assert_eq!(align_of::<u16>(), 2, "u16 alignment must be 2 bytes");
}
#[test]
fn layout_u32_size_align() {
assert_eq!(size_of::<u32>(), 4, "u32 size must be 4 bytes");
assert_eq!(align_of::<u32>(), 4, "u32 alignment must be 4 bytes");
}
#[test]
fn layout_u64_size_align() {
assert_eq!(size_of::<u64>(), 8, "u64 size must be 8 bytes");
assert_eq!(align_of::<u64>(), 8, "u64 alignment must be 8 bytes");
}
#[test]
#[cfg(target_pointer_width = "64")]
fn layout_usize_size_align() {
assert_eq!(
size_of::<usize>(),
8,
"usize size must be 8 bytes on x86_64"
);
assert_eq!(
align_of::<usize>(),
8,
"usize alignment must be 8 bytes on x86_64"
);
}
#[test]
fn layout_bool_size_align() {
assert_eq!(size_of::<bool>(), 1, "bool size must be 1 byte");
assert_eq!(align_of::<bool>(), 1, "bool alignment must be 1 byte");
}
#[test]
fn layout_stringview_fields_and_size() {
assert_eq!(
size_of::<StringView>(),
16,
"StringView size must be 16 bytes (ptr + len)"
);
assert_eq!(
align_of::<StringView>(),
8,
"StringView alignment must be 8 bytes"
);
assert_eq!(
offset_of!(StringView, ptr),
0,
"StringView.ptr must be at offset 0"
);
assert_eq!(
offset_of!(StringView, len),
8,
"StringView.len must be at offset 8"
);
}
#[test]
fn layout_buffer_fields_and_size() {
assert_eq!(
size_of::<Buffer>(),
24,
"Buffer size must be 24 bytes (ptr + len + cap)"
);
assert_eq!(align_of::<Buffer>(), 8, "Buffer alignment must be 8 bytes");
assert_eq!(offset_of!(Buffer, ptr), 0, "Buffer.ptr must be at offset 0");
assert_eq!(offset_of!(Buffer, len), 8, "Buffer.len must be at offset 8");
assert_eq!(
offset_of!(Buffer, cap),
16,
"Buffer.cap must be at offset 16"
);
}
#[test]
fn layout_abierror_fields_and_size() {
assert_eq!(
size_of::<AbiError>(),
24,
"AbiError size must be 24 bytes (code + message)"
);
assert_eq!(
align_of::<AbiError>(),
8,
"AbiError alignment must be 8 bytes"
);
assert_eq!(
offset_of!(AbiError, code),
0,
"AbiError.code must be at offset 0"
);
assert_eq!(
offset_of!(AbiError, message),
8,
"AbiError.message must be at offset 8"
);
}
#[test]
fn layout_plugin_handle_fields_and_size() {
assert_eq!(
size_of::<GuestContractHandle>(),
8,
"GuestContractHandle size must be 8 bytes (index + generation)"
);
assert_eq!(
align_of::<GuestContractHandle>(),
4,
"GuestContractHandle alignment must be 4 bytes"
);
assert_eq!(
offset_of!(GuestContractHandle, index),
0,
"GuestContractHandle.index must be at offset 0"
);
assert_eq!(
offset_of!(GuestContractHandle, generation),
4,
"GuestContractHandle.generation must be at offset 4"
);
}
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
enum EnumU8 {
A = 0,
B = 1,
}
#[test]
fn layout_enum_u8_size_align() {
assert_eq!(
size_of::<EnumU8>(),
1,
"#[repr(u8)] enum size must be 1 byte"
);
assert_eq!(
align_of::<EnumU8>(),
1,
"#[repr(u8)] enum alignment must be 1 byte"
);
assert_eq!(EnumU8::A as u8, 0, "EnumU8::A discriminant must be 0");
assert_eq!(EnumU8::B as u8, 1, "EnumU8::B discriminant must be 1");
}
#[repr(u16)]
#[derive(Debug, Clone, Copy)]
enum EnumU16 {
A = 0,
B = 1,
}
#[test]
fn layout_enum_u16_size_align() {
assert_eq!(
size_of::<EnumU16>(),
2,
"#[repr(u16)] enum size must be 2 bytes"
);
assert_eq!(
align_of::<EnumU16>(),
2,
"#[repr(u16)] enum alignment must be 2 bytes"
);
assert_eq!(EnumU16::A as u16, 0, "EnumU16::A discriminant must be 0");
assert_eq!(EnumU16::B as u16, 1, "EnumU16::B discriminant must be 1");
}
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
enum EnumU32 {
A = 0,
B = 1,
}
#[test]
fn layout_enum_u32_size_align() {
assert_eq!(
size_of::<EnumU32>(),
4,
"#[repr(u32)] enum size must be 4 bytes"
);
assert_eq!(
align_of::<EnumU32>(),
4,
"#[repr(u32)] enum alignment must be 4 bytes"
);
assert_eq!(EnumU32::A as u32, 0, "EnumU32::A discriminant must be 0");
assert_eq!(EnumU32::B as u32, 1, "EnumU32::B discriminant must be 1");
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogLevel {
Trace = 0,
Debug = 1,
Info = 2,
Warn = 3,
Error = 4,
}
#[test]
fn layout_loglevel_size_align() {
assert_eq!(
size_of::<LogLevel>(),
4,
"LogLevel (#[repr(u32)]) size must be 4 bytes"
);
assert_eq!(
align_of::<LogLevel>(),
4,
"LogLevel (#[repr(u32)]) alignment must be 4 bytes"
);
}
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
enum SingleVariant {
OnlyOne = 42,
}
#[test]
fn layout_enum_single_variant() {
assert_eq!(
size_of::<SingleVariant>(),
4,
"Single variant #[repr(u32)] enum size must be 4 bytes"
);
assert_eq!(
align_of::<SingleVariant>(),
4,
"Single variant #[repr(u32)] enum alignment must be 4 bytes"
);
assert_eq!(
SingleVariant::OnlyOne as u32,
42,
"SingleVariant::OnlyOne discriminant must be 42"
);
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct SimpleStructNoPadding {
a: u32,
b: u32,
c: u64,
}
#[test]
fn layout_simple_struct_no_padding() {
assert_eq!(
size_of::<SimpleStructNoPadding>(),
16,
"SimpleStructNoPadding size must be 16 bytes"
);
assert_eq!(
align_of::<SimpleStructNoPadding>(),
8,
"SimpleStructNoPadding alignment must be 8 bytes"
);
assert_eq!(
offset_of!(SimpleStructNoPadding, a),
0,
"a must be at offset 0"
);
assert_eq!(
offset_of!(SimpleStructNoPadding, b),
4,
"b must be at offset 4"
);
assert_eq!(
offset_of!(SimpleStructNoPadding, c),
8,
"c must be at offset 8"
);
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct StructWithInternalPadding {
a: u8, b: u64, c: u32, }
#[test]
fn layout_struct_with_internal_padding() {
assert_eq!(
size_of::<StructWithInternalPadding>(),
24,
"StructWithInternalPadding size must be 24 bytes"
);
assert_eq!(
align_of::<StructWithInternalPadding>(),
8,
"StructWithInternalPadding alignment must be 8 bytes"
);
assert_eq!(
offset_of!(StructWithInternalPadding, a),
0,
"a must be at offset 0"
);
assert_eq!(
offset_of!(StructWithInternalPadding, b),
8,
"b must be at offset 8 (after 7 bytes padding)"
);
assert_eq!(
offset_of!(StructWithInternalPadding, c),
16,
"c must be at offset 16"
);
let padding_before_b: usize = offset_of!(StructWithInternalPadding, b)
- (offset_of!(StructWithInternalPadding, a) + size_of::<u8>());
assert_eq!(
padding_before_b, 7,
"Expected 7 bytes padding between a and b"
);
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct LogWithLevelArgs {
level: LogLevel, message: StringView, }
#[test]
fn layout_logwithlevelargs_layout() {
assert_eq!(
size_of::<LogWithLevelArgs>(),
24,
"LogWithLevelArgs size must be 24 bytes"
);
assert_eq!(
align_of::<LogWithLevelArgs>(),
8,
"LogWithLevelArgs alignment must be 8 bytes"
);
assert_eq!(
offset_of!(LogWithLevelArgs, level),
0,
"level must be at offset 0"
);
assert_eq!(
offset_of!(LogWithLevelArgs, message),
8,
"message must be at offset 8 (after 4 bytes padding)"
);
let padding: usize = offset_of!(LogWithLevelArgs, message)
- (offset_of!(LogWithLevelArgs, level) + size_of::<LogLevel>());
assert_eq!(
padding, 4,
"Expected 4 bytes padding between level and message"
);
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct StructTrailingPadding {
a: u64, b: u8, }
#[test]
fn layout_struct_trailing_padding() {
assert_eq!(
size_of::<StructTrailingPadding>(),
16,
"StructTrailingPadding size must be 16 bytes"
);
assert_eq!(
align_of::<StructTrailingPadding>(),
8,
"StructTrailingPadding alignment must be 8 bytes"
);
assert_eq!(
offset_of!(StructTrailingPadding, a),
0,
"a must be at offset 0"
);
assert_eq!(
offset_of!(StructTrailingPadding, b),
8,
"b must be at offset 8"
);
let trailing_padding: usize = size_of::<StructTrailingPadding>()
- (offset_of!(StructTrailingPadding, b) + size_of::<u8>());
assert_eq!(trailing_padding, 7, "Expected 7 bytes trailing padding");
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct InnerStruct {
x: u32,
y: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct NestedStruct {
inner: InnerStruct, z: u64, }
#[test]
fn layout_nested_struct() {
assert_eq!(
size_of::<NestedStruct>(),
16,
"NestedStruct size must be 16 bytes"
);
assert_eq!(
align_of::<NestedStruct>(),
8,
"NestedStruct alignment must be 8 bytes"
);
assert_eq!(
offset_of!(NestedStruct, inner),
0,
"inner must be at offset 0"
);
assert_eq!(offset_of!(NestedStruct, z), 8, "z must be at offset 8");
assert_eq!(
size_of::<InnerStruct>(),
8,
"InnerStruct size must be 8 bytes"
);
assert_eq!(
offset_of!(InnerStruct, x),
0,
"InnerStruct.x must be at offset 0"
);
assert_eq!(
offset_of!(InnerStruct, y),
4,
"InnerStruct.y must be at offset 4"
);
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct StructWithEnumField {
status: LogLevel, value: u64, }
#[test]
fn layout_struct_with_enum_field() {
assert_eq!(
size_of::<StructWithEnumField>(),
16,
"StructWithEnumField size must be 16 bytes"
);
assert_eq!(
align_of::<StructWithEnumField>(),
8,
"StructWithEnumField alignment must be 8 bytes"
);
assert_eq!(
offset_of!(StructWithEnumField, status),
0,
"status must be at offset 0"
);
assert_eq!(
offset_of!(StructWithEnumField, value),
8,
"value must be at offset 8"
);
let padding: usize = offset_of!(StructWithEnumField, value)
- (offset_of!(StructWithEnumField, status) + size_of::<LogLevel>());
assert_eq!(
padding, 4,
"Expected 4 bytes padding between status and value"
);
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct TwoPrimitivesNoPadding {
a: u32,
b: u32,
}
#[test]
fn layout_two_primitives_no_padding() {
assert_eq!(
size_of::<TwoPrimitivesNoPadding>(),
8,
"TwoPrimitivesNoPadding size must be 8 bytes"
);
assert_eq!(
align_of::<TwoPrimitivesNoPadding>(),
4,
"TwoPrimitivesNoPadding alignment must be 4 bytes"
);
assert_eq!(
offset_of!(TwoPrimitivesNoPadding, a),
0,
"a must be at offset 0"
);
assert_eq!(
offset_of!(TwoPrimitivesNoPadding, b),
4,
"b must be at offset 4"
);
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct TwoPrimitivesWithPadding {
a: u32, b: u64, }
#[test]
fn layout_two_primitives_with_padding() {
assert_eq!(
size_of::<TwoPrimitivesWithPadding>(),
16,
"TwoPrimitivesWithPadding size must be 16 bytes"
);
assert_eq!(
align_of::<TwoPrimitivesWithPadding>(),
8,
"TwoPrimitivesWithPadding alignment must be 8 bytes"
);
assert_eq!(
offset_of!(TwoPrimitivesWithPadding, a),
0,
"a must be at offset 0"
);
assert_eq!(
offset_of!(TwoPrimitivesWithPadding, b),
8,
"b must be at offset 8"
);
let padding: usize = offset_of!(TwoPrimitivesWithPadding, b)
- (offset_of!(TwoPrimitivesWithPadding, a) + size_of::<u32>());
assert_eq!(padding, 4, "Expected 4 bytes padding between a and b");
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct ThreeParamsMixed {
a: u8, b: StringView, c: u32, }
#[test]
fn layout_three_params_mixed() {
assert_eq!(
size_of::<ThreeParamsMixed>(),
32,
"ThreeParamsMixed size must be 32 bytes"
);
assert_eq!(
align_of::<ThreeParamsMixed>(),
8,
"ThreeParamsMixed alignment must be 8 bytes"
);
assert_eq!(offset_of!(ThreeParamsMixed, a), 0, "a must be at offset 0");
assert_eq!(offset_of!(ThreeParamsMixed, b), 8, "b must be at offset 8");
assert_eq!(
offset_of!(ThreeParamsMixed, c),
24,
"c must be at offset 24"
);
let padding_ab: usize =
offset_of!(ThreeParamsMixed, b) - (offset_of!(ThreeParamsMixed, a) + size_of::<u8>());
assert_eq!(padding_ab, 7, "Expected 7 bytes padding between a and b");
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct EnumThenStringView {
level: LogLevel, message: StringView, }
#[test]
fn layout_enum_then_stringview() {
assert_eq!(
size_of::<EnumThenStringView>(),
24,
"EnumThenStringView size must be 24 bytes"
);
assert_eq!(
align_of::<EnumThenStringView>(),
8,
"EnumThenStringView alignment must be 8 bytes"
);
assert_eq!(
offset_of!(EnumThenStringView, level),
0,
"level must be at offset 0"
);
assert_eq!(
offset_of!(EnumThenStringView, message),
8,
"message must be at offset 8"
);
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct StringViewThenEnum {
message: StringView, level: LogLevel, }
#[test]
fn layout_stringview_then_enum() {
assert_eq!(
size_of::<StringViewThenEnum>(),
24,
"StringViewThenEnum size must be 24 bytes"
);
assert_eq!(
align_of::<StringViewThenEnum>(),
8,
"StringViewThenEnum alignment must be 8 bytes"
);
assert_eq!(
offset_of!(StringViewThenEnum, message),
0,
"message must be at offset 0"
);
assert_eq!(
offset_of!(StringViewThenEnum, level),
16,
"level must be at offset 16"
);
let trailing_padding: usize = size_of::<StringViewThenEnum>()
- (offset_of!(StringViewThenEnum, level) + size_of::<LogLevel>());
assert_eq!(trailing_padding, 4, "Expected 4 bytes trailing padding");
assert_eq!(
size_of::<EnumThenStringView>(),
size_of::<StringViewThenEnum>(),
"Both structs should have same total size"
);
assert_ne!(
offset_of!(EnumThenStringView, level),
offset_of!(StringViewThenEnum, level),
"level offset differs based on field order"
);
}
#[repr(C)]
struct EmptyStruct {}
#[test]
fn layout_empty_struct() {
assert_eq!(
size_of::<EmptyStruct>(),
0,
"EmptyStruct size must be 0 bytes"
);
assert_eq!(
align_of::<EmptyStruct>(),
1,
"EmptyStruct alignment must be 1 byte"
);
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct AllU8Fields {
a: u8,
b: u8,
c: u8,
d: u8,
}
#[test]
fn layout_all_u8_fields() {
assert_eq!(
size_of::<AllU8Fields>(),
4,
"AllU8Fields size must be 4 bytes"
);
assert_eq!(
align_of::<AllU8Fields>(),
1,
"AllU8Fields alignment must be 1 byte"
);
assert_eq!(offset_of!(AllU8Fields, a), 0, "a must be at offset 0");
assert_eq!(offset_of!(AllU8Fields, b), 1, "b must be at offset 1");
assert_eq!(offset_of!(AllU8Fields, c), 2, "c must be at offset 2");
assert_eq!(offset_of!(AllU8Fields, d), 3, "d must be at offset 3");
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct MultiplePaddingRegions {
a: u8, b: u16, c: u8, d: u32, e: u8, }
#[test]
fn layout_multiple_padding_regions() {
assert_eq!(
size_of::<MultiplePaddingRegions>(),
16,
"MultiplePaddingRegions size must be 16 bytes"
);
assert_eq!(
align_of::<MultiplePaddingRegions>(),
4,
"MultiplePaddingRegions alignment must be 4 bytes"
);
assert_eq!(
offset_of!(MultiplePaddingRegions, a),
0,
"a must be at offset 0"
);
assert_eq!(
offset_of!(MultiplePaddingRegions, b),
2,
"b must be at offset 2"
);
assert_eq!(
offset_of!(MultiplePaddingRegions, c),
4,
"c must be at offset 4"
);
assert_eq!(
offset_of!(MultiplePaddingRegions, d),
8,
"d must be at offset 8"
);
assert_eq!(
offset_of!(MultiplePaddingRegions, e),
12,
"e must be at offset 12"
);
}
#[repr(C)]
#[derive(Debug)]
struct BufferFollowedByU32 {
buf: Buffer, extra: u32, }
#[test]
fn layout_buffer_followed_by_u32() {
assert_eq!(
size_of::<BufferFollowedByU32>(),
32,
"BufferFollowedByU32 size must be 32 bytes"
);
assert_eq!(
align_of::<BufferFollowedByU32>(),
8,
"BufferFollowedByU32 alignment must be 8 bytes"
);
assert_eq!(
offset_of!(BufferFollowedByU32, buf),
0,
"buf must be at offset 0"
);
assert_eq!(
offset_of!(BufferFollowedByU32, extra),
24,
"extra must be at offset 24"
);
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct HandleFollowedByU64 {
handle: GuestContractHandle, value: u64, }
#[test]
fn layout_handle_followed_by_u64() {
assert_eq!(
size_of::<HandleFollowedByU64>(),
16,
"HandleFollowedByU64 size must be 16 bytes"
);
assert_eq!(
align_of::<HandleFollowedByU64>(),
8,
"HandleFollowedByU64 alignment must be 8 bytes"
);
assert_eq!(
offset_of!(HandleFollowedByU64, handle),
0,
"handle must be at offset 0"
);
assert_eq!(
offset_of!(HandleFollowedByU64, value),
8,
"value must be at offset 8"
);
}
#[repr(u64)]
#[derive(Debug, Clone, Copy)]
enum EnumU64 {
A = 0,
B = 1,
}
#[test]
fn layout_enum_u64_size_align() {
assert_eq!(
size_of::<EnumU64>(),
8,
"#[repr(u64)] enum size must be 8 bytes"
);
assert_eq!(
align_of::<EnumU64>(),
8,
"#[repr(u64)] enum alignment must be 8 bytes"
);
assert_eq!(EnumU64::A as u64, 0, "EnumU64::A discriminant must be 0");
assert_eq!(EnumU64::B as u64, 1, "EnumU64::B discriminant must be 1");
}
#[test]
fn layout_signed_and_float_primitives() {
assert_eq!(size_of::<i8>(), 1, "i8 size must be 1 byte");
assert_eq!(align_of::<i8>(), 1, "i8 alignment must be 1 byte");
assert_eq!(size_of::<i16>(), 2, "i16 size must be 2 bytes");
assert_eq!(align_of::<i16>(), 2, "i16 alignment must be 2 bytes");
assert_eq!(size_of::<i32>(), 4, "i32 size must be 4 bytes");
assert_eq!(align_of::<i32>(), 4, "i32 alignment must be 4 bytes");
assert_eq!(size_of::<i64>(), 8, "i64 size must be 8 bytes");
assert_eq!(align_of::<i64>(), 8, "i64 alignment must be 8 bytes");
assert_eq!(size_of::<f32>(), 4, "f32 size must be 4 bytes");
assert_eq!(align_of::<f32>(), 4, "f32 alignment must be 4 bytes");
assert_eq!(size_of::<f64>(), 8, "f64 size must be 8 bytes");
assert_eq!(align_of::<f64>(), 8, "f64 alignment must be 8 bytes");
}
#[repr(C)]
#[derive(Debug)]
struct AllAbiTypesStruct {
sv: StringView, buf: Buffer, err: AbiError, handle: GuestContractHandle, }
#[test]
fn layout_all_abi_types_struct() {
assert_eq!(
size_of::<AllAbiTypesStruct>(),
72,
"AllAbiTypesStruct size must be 72 bytes"
);
assert_eq!(
align_of::<AllAbiTypesStruct>(),
8,
"AllAbiTypesStruct alignment must be 8 bytes"
);
assert_eq!(
offset_of!(AllAbiTypesStruct, sv),
0,
"sv must be at offset 0"
);
assert_eq!(
offset_of!(AllAbiTypesStruct, buf),
16,
"buf must be at offset 16"
);
assert_eq!(
offset_of!(AllAbiTypesStruct, err),
40,
"err must be at offset 40"
);
assert_eq!(
offset_of!(AllAbiTypesStruct, handle),
64,
"handle must be at offset 64"
);
}