#固定大小 # #缓冲区 #引用计数 #指针 #非对齐

heapbuf

固定大小的堆缓冲区,具有可选的自定义对齐、引用计数和自定义析构器逻辑

2个不稳定版本

0.1.0 2024年5月16日
0.0.1 2024年5月6日

#193 in 内存管理

Download history 144/week @ 2024-05-03 176/week @ 2024-05-10 99/week @ 2024-05-17 33/week @ 2024-05-24 29/week @ 2024-05-31 22/week @ 2024-06-07 40/week @ 2024-06-14 21/week @ 2024-06-21 35/week @ 2024-06-28 65/week @ 2024-07-05 35/week @ 2024-07-12 55/week @ 2024-07-19 18/week @ 2024-07-26 3/week @ 2024-08-02

每月121次下载

MIT/Apache

53KB
876

heapbuf

Rust库,实现了具有可选自定义对齐、引用计数和自定义析构器逻辑的固定大小堆缓冲区。

为了在Rust中使用方便,该缓冲区还实现了Read/Write和Seek特性。在缓冲区边界之外进行读取/写入/定位将触发UnexpectedEof错误。

使用场景

这个库主要开发有两个目的

  1. 与C代码交互,这些C代码将堆缓冲区/对象的所有权交给Rust,而Rust完成后需要手动释放所有权以返回给C代码。
  2. 与需要固定大小缓冲区且具有自定义对齐的C代码交互。

特性

此库支持以下crates及其数据类型

  • half_support: half crate f16类型
  • f128_support: f128 crate f128类型
  • uintx_support: uintx crate u24类型至u120类型

如果您想启用所有功能,为了方便起见,存在一个"all"功能。

[dependencies]
heapbuf = {version = "0.0.1", features = ["all"]}

示例

use std::mem::{align_of, size_of};
use std::sync::atomic::{AtomicU16, AtomicU32, Ordering};
use std::thread;
use std::time::Duration;
use heapbuf::*;



#[test]
pub fn test() {
    let mut x : HBuf = HBuf::allocate(512);
    let _ : &[u8] = x.as_slice();
    let _ : &mut [u8] = x.as_mut_slice();
    x[0] = 1u8;
    assert_eq!(1, x[0]);

    //This option is None if the alignment is not 4. We did not specify alignment when allocating
    //So we may or may not be 4 byte aligned. Depends on the OS
    let _ : Option<&[u32]> = x.as_slice_u32();
    let x : HBuf = HBuf::allocate_aligned(512, 4);
    let _ : &[u32] = x.as_slice_u32().unwrap(); //This is safe because our alignment is 4!
    let _ : &[i16] = x.as_slice_i16().unwrap();
    let _ : &[f32] = x.as_slice_f32().unwrap();
    //Other supported types for slices are u16-u128, i8-i128, f32, f64
    //From other crates depending on selected crate features: f16, f128, u24...,


    //Example construct from pointer
    let some_vec: Vec<u8> = vec![123u8; 4096];
    let mut some_vec: std::mem::ManuallyDrop<Vec<u8>>  = std::mem::ManuallyDrop::new(some_vec);
    let some_pointer: *mut u8 = some_vec.as_mut_ptr();
    fn dealloc_vec(ptr: *mut u8 , size: usize) {
        //This just deallocates a Vec... This could also call a C function
        unsafe {
            drop(Vec::from_raw_parts(ptr, size, size));
        }
    }

    let buf : HBuf = unsafe {
        HBuf::from_raw_parts_with_destructor(some_pointer, some_vec.capacity(), dealloc_vec)
    };

    drop(buf); //Will run dealloc_vec and destroy the allocated vec.


    //Example reference counting
    let mut x : HBuf = HBuf::allocate_aligned(31, 4);
    let x2 = x.clone(); //Does not clone the heap buffer, only creates another reference. just lice Rc.clone()
    assert_eq!(x.ref_count(), 2);
    assert_eq!(x2.ref_count(), 2);
    x[0] = 1;
    drop(x); //Would not run any destructors since there is still 1 reference.
    assert_eq!(x2.ref_count(), 1);
    assert_eq!(x2[0], 1);
    drop(x2); //Will deallocate and run destructors since there are no more references.


    //Example Threading
    let x : HBuf = HBuf::allocate_aligned_zeroed(32, 4);
    let x2 = x.clone(); //This is Send/Sync
    let handle = thread::spawn(move || {
        loop {
            //You have to use the atomic operations if you use more than one thread
            //If you use the normal operations with different threads involved then there is no guarantee
            //When/That the threads will see each other's changes!
            //This is a busy waiting loop that you should never do btw!
            if x2.atomic_load_u32(4, Ordering::SeqCst) == 420 {
                return;
            }
        }
    });
    thread::sleep(Duration::from_millis(500));
    x.atomic_store_u32(4, 420, Ordering::SeqCst);
    handle.join().unwrap();
    //Option is None if alignment mismatches!
    let _ : &[AtomicU32] = x.as_slice_atomic_u32().unwrap();
    let _ : &[AtomicU16] = x.as_slice_atomic_u16().unwrap();
    let _ : &AtomicU32 = x.as_atomic_u32(4).unwrap();
    x.as_atomic_u32(8).unwrap().store(24, Ordering::SeqCst);
    assert_eq!(24, x.as_slice_u32().unwrap()[2]);

    //Example reading/writing structs
    #[derive(Clone, Copy)] //Only structs with the Copy trait can be read!
    struct Test {
        member1: u32,
        member2: u64,
    }
    let mut x: HBuf = HBuf::allocate_aligned_zeroed(size_of::<Test>() * 2, align_of::<Test>());
    unsafe {
        //This is not the best idea on structs that have Drop logic.
        //Use with pure data structs only!
        x.set(0, Test { member1: 12, member2: 24 });
        let my_struct : Test =  x.get::<Test>(0);
        assert_eq!(my_struct.member1, 12);
        assert_eq!(my_struct.member2, 24);

        //Reads the second struct
        let my_struct : Test =  x.get::<Test>(size_of::<Test>());
        //The exact numbers depend on the system (alignment/endian etc.)
        assert_eq!(my_struct.member1, 0);
        assert_eq!(my_struct.member2, 0);
        let slice: &[Test] = x.as_slice_generic().unwrap(); //Only succeeds if buffer is properly aligned
        assert_eq!(slice.len(), 2);
    }
}

依赖项

~155KB