Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 147 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
mod macros;
pub mod types;

#[cfg(test)]
extern crate alloc;

/// A layout of a digit data type in memory.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(C)]
Expand Down Expand Up @@ -39,12 +42,12 @@ pub enum LayoutContent {

#[repr(u32)]
enum DigitLayoutType {
Unsigned = 0xe0_00_00_00, // 0b111...
Real = 0xc0_00_00_00, // 0b110...
Named = 0, // 0b...
Unsigned = 0xE000_0000, // 0b111...
Real = 0xC000_0000, // 0b110...
Named = 0, // 0b...
}
const UNSIGNED: u32 = DigitLayoutType::Unsigned as _;
const SIGNED: u32 = DigitLayoutType::Real as _;
const UNSIGNED: u32 = DigitLayoutType::Unsigned as u32;
const SIGNED: u32 = DigitLayoutType::Real as u32;
const HEAD: u32 = UNSIGNED;

impl DigitLayout {
Expand Down Expand Up @@ -85,7 +88,7 @@ impl DigitLayout {
_ => panic!("Invalid character in digit name"),
};
body += (b as u32 + 1) * exp;
const GUARD: u32 = 0xc0_00_00_00; // 0b110...
const GUARD: u32 = 0xC000_0000; // 0b110...
assert!(body & GUARD != GUARD);
assert!(exp & GUARD != GUARD);
exp *= 37; // 37 = 10 + 26 + 1
Expand All @@ -96,26 +99,26 @@ impl DigitLayout {
#[inline(always)]
const fn new(ty: DigitLayoutType, body: u32, group: u16, size: u16) -> Self {
Self {
code: ((ty as u32) | body),
code: (ty as u32) | body,
group,
size,
}
}

/// Raw transmutation to `u32`.
/// Raw transmutation to `u64`.
#[inline]
pub const fn to_u64(self) -> u64 {
unsafe { core::mem::transmute(self) }
}

/// Get the number of bytes occupied by this layout.
pub const fn group_size(self) -> usize {
self.group as _
self.group as usize
}

/// Get the number of bytes occupied by this layout.
pub const fn nbytes(self) -> usize {
self.size as _
self.size as usize
}

/// Decode the content of the digit layout.
Expand Down Expand Up @@ -151,12 +154,12 @@ impl DigitLayout {

#[inline(always)]
const fn decode_exponent(self) -> u32 {
((self.code & !HEAD) >> 16) & 0xff
((self.code & !HEAD) >> 16) & 0xFF
}

#[inline(always)]
const fn decode_mantissa(self) -> u32 {
self.code & 0xffff
self.code & 0xFFFF
}
}

Expand Down Expand Up @@ -317,3 +320,135 @@ fn test_named() {
}
));
}

#[test]
fn test_decode_methods() {
// 测试decode_unsigned方法
let u8_layout = DigitLayout::unsigned(8, 1);
assert_eq!(u8_layout.decode_unsigned(), 8);

let u16_layout = DigitLayout::unsigned(16, 1);
assert_eq!(u16_layout.decode_unsigned(), 16);

// 测试decode_exponent和decode_mantissa方法
let f32_layout = DigitLayout::real(8, 23, 1);
assert_eq!(f32_layout.decode_exponent(), 8);
assert_eq!(f32_layout.decode_mantissa(), 23);

let f64_layout = DigitLayout::real(11, 52, 1);
assert_eq!(f64_layout.decode_exponent(), 11);
assert_eq!(f64_layout.decode_mantissa(), 52);
}

#[test]
fn test_group_size_and_nbytes() {
// 测试group_size和nbytes方法
let layout1 = DigitLayout::unsigned(32, 4);
assert_eq!(layout1.group_size(), 4);
assert_eq!(layout1.nbytes(), 16); // 32/8 * 4 = 16

let layout2 = DigitLayout::real(8, 23, 2);
assert_eq!(layout2.group_size(), 2);
assert_eq!(layout2.nbytes(), 8); // (1+8+23)/8 * 2 = 8

let layout3 = DigitLayout::named("test", 3, 12);
assert_eq!(layout3.group_size(), 3);
assert_eq!(layout3.nbytes(), 12);
}

#[test]
fn test_to_u64() {
// 测试to_u64方法
let layout = DigitLayout::unsigned(32, 1);
let u64_value = layout.to_u64();
assert_ne!(u64_value, 0);

let same_layout = DigitLayout::unsigned(32, 1);
assert_eq!(layout.to_u64(), same_layout.to_u64());
let different_layout = DigitLayout::unsigned(64, 1);
assert_ne!(layout.to_u64(), different_layout.to_u64());
}

#[test]
fn test_display_impl() {
// 测试Display实现
use core::fmt::Write;
use alloc::string::String;

struct TestWriter(String);

impl Write for TestWriter {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.0.push_str(s);
Ok(())
}
}

// 测试unsigned类型的Display
let u8_layout = DigitLayout::unsigned(8, 1);
let mut writer = TestWriter(String::new());
write!(writer, "{}", u8_layout).unwrap();
assert_eq!(writer.0, "u8");

// 测试unsigned数组的Display
let u8_array_layout = DigitLayout::unsigned(8, 4);
let mut writer = TestWriter(String::new());
write!(writer, "{}", u8_array_layout).unwrap();
assert_eq!(writer.0, "[u8; 4]");

// 测试real类型的Display
let f32_layout = DigitLayout::real(8, 23, 1);
let mut writer = TestWriter(String::new());
write!(writer, "{}", f32_layout).unwrap();
assert_eq!(writer.0, "f32_e8m23");

// 测试real数组的Display
let f32_array_layout = DigitLayout::real(8, 23, 2);
let mut writer = TestWriter(String::new());
write!(writer, "{}", f32_array_layout).unwrap();
assert_eq!(writer.0, "[f32_e8m23; 2]");

// 测试named类型的Display
let named_layout = DigitLayout::named("test", 1, 4);
let mut writer = TestWriter(String::new());
write!(writer, "{}", named_layout).unwrap();
assert_eq!(writer.0, "test");
}

#[test]
fn test_named_edge_cases() {
use core::fmt::Write;
use alloc::string::String;

struct TestWriter(String);

impl Write for TestWriter {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.0.push_str(s);
Ok(())
}
}

// 测试named方法的边缘情况
let empty_name = DigitLayout::named("", 1, 1);
// 测试空名称的显示(不使用format!宏)
let mut writer = TestWriter(String::new());
let _ = write!(writer, "{}", empty_name);

let alphanumeric = DigitLayout::named("a1B2c3", 1, 1);
assert!(matches!(
alphanumeric.decode(),
LayoutContent::Named {
name: [b'a', b'1', b'b', b'2', b'c', b'3', 0, 0]
}
));

// 测试带下划线和点的名称
let with_special = DigitLayout::named("a_b.c", 1, 1);
assert!(matches!(
with_special.decode(),
LayoutContent::Named {
name: [b'a', b'b', b'c', 0, 0, 0, 0, 0]
}
));
}
2 changes: 1 addition & 1 deletion src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/// 定义一个 [`DigitLayout`](crate::DigitLayout) 实例。
/// Defines an instance of [`DigitLayout`](crate::DigitLayout).
#[macro_export]
macro_rules! layout {
($name:ident u($bits:expr); $group:expr) => {
Expand Down
32 changes: 16 additions & 16 deletions src/types.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
//! 为一些基本类型和常用类型提供预定义布局。
//! Predefined layouts for basic and commonly used types.

#![allow(missing_docs)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

代码中出现的所有 [allow(...)] 须通过注释说明理由


layout!(U8 u( 8));
layout!(U16 u( 16));
layout!(U32 u( 32));
layout!(U64 u( 64));
layout!(U128 u(128));
layout!(I8 i( 8));
layout!(I16 i( 16));
layout!(I32 i( 32));
layout!(I64 i( 64));
layout!(I128 i(128));
layout!(F16 e( 5)m( 10));
layout!(BF16 e( 8)m( 7));
layout!(F32 e( 8)m( 23));
layout!(F64 e(11)m( 52));
layout!(F128 e(15)m(112));
layout!(U8 u( 8));
layout!(U16 u( 16));
layout!(U32 u( 32));
layout!(U64 u( 64));
layout!(U128 u(128));
layout!(I8 i( 8));
layout!(I16 i( 16));
layout!(I32 i( 32));
layout!(I64 i( 64));
layout!(I128 i(128));
layout!(F16 e( 5)m( 10));
layout!(BF16 e( 8)m( 7));
layout!(F32 e( 8)m( 23));
layout!(F64 e(11)m( 52));
layout!(F128 e(15)m(112));
layout!(Bool; [1] in 1);