#buffer #memory-buffer #memory #raw #copy #graphics #uninitialized-memory

无std presser

一个库,帮助您在不触发远距离神秘行为(未定义行为)的情况下将事物复制到原始缓冲区。

5个不稳定版本

0.3.1 2022年10月16日
0.3.0 2022年10月16日
0.2.1 2022年10月15日
0.2.0 2022年10月13日
0.1.1 2022年7月4日

#62内存管理

Download history 17291/week @ 2024-03-14 21706/week @ 2024-03-21 20628/week @ 2024-03-28 15668/week @ 2024-04-04 18686/week @ 2024-04-11 19632/week @ 2024-04-18 18780/week @ 2024-04-25 17551/week @ 2024-05-02 14409/week @ 2024-05-09 16711/week @ 2024-05-16 18232/week @ 2024-05-23 18537/week @ 2024-05-30 17962/week @ 2024-06-06 20659/week @ 2024-06-13 16990/week @ 2024-06-20 17632/week @ 2024-06-27

每月76,268次下载
620个库中使用(通过gpu-allocator

MIT/Apache

44KB
294

🗜 presser

帮助将数据复制到原始、可能未初始化的缓冲区的工具。

Embark Embark Crates.io Published Docs Git Docs dependency status

presser可以帮助您将数据复制到原始缓冲区。一个主要用例是将数据复制到将被GPU访问的图形API分配的缓冲区。现在在Rust中执行此操作的方法往往会在微妙且难以察觉的方式中引发未定义行为。例如,将已分配但未初始化的缓冲区视为&[u8] 是立即未定义行为,并且将具有任何填充字节的布局的T: Copy类型&[u8]作为复制的源也是立即未定义行为,在这两种情况下,因为它创建一个无效值(未初始化内存是一个无效的u8)的引用是无效的,即使您的代码实际上从未访问过该内存。这使得复制数据到缓冲区的最直接方式变得不可靠 😬

* 如果你现在正在想:“呸!有什么问题?未初始化的 u8 只是任意位模式而已,这没问题,我们不关心,”请查看 @RalfJung 撰写的这篇博客文章,他是领导定义 Rust 内存和执行模型改进工作的一员。[查看博客文章](https://www.ralfj.de/blog/2019/07/14/uninit.html)。正如那篇文章中所述,一个未初始化的内存块不是一个随意的位模式,而是一个完全独立的内存状态,与它的值无关,这使得编译器能够执行优化,例如重排、删除以及以其他方式改变程序的执行流程,这些方式不能简单地用“值可能有某种可能的位模式”来描述。LLVM 和 Clang 正在改变自己,要求使用特殊的 noundef 属性来执行许多否则不可靠的重要优化。关于这类问题可能导致的具体示例,请参阅 [scottmcm 提出的这个 issue](https://github.com/rust-lang/rust/pull/98919#issuecomment-1186106387)。*

一个糟糕的例子

#[derive(Clone, Copy)]
#[repr(C)]
struct MyDataStruct {
    a: u8,
    b: u32,
}

let my_data = MyDataStruct { a: 0, b: 42 };

// 🚨 MyDataStruct contains 3 padding bytes after `a`, which are
// uninit, therefore getting a slice that includes them is UB!
let my_data_bytes: &[u8] = transmute(&my_data);

// allocate an uninit buffer of some size
let my_buffer: MyBufferType = some_api.alloc_buffer_size(2048);

// 🚨 this is UB for the same reason, these bytes are uninit!
let buffer_as_bytes: &mut [u8] =
    slice::from_raw_parts(my_buffer.ptr(), my_buffer.size());

// 🚨 this is UB because not only are both slices invalid,
// this is not ensuring proper alignment!
buffer_as_bytes.copy_from_slice(my_data_bytes);

presser 通过允许你将某些大小的已分配原始内存视为一个 "Slab" 内存块,然后提供将数据复制到该内存的 安全、有效 方式来帮助解决这个问题。

一个好的例子

#[derive(Clone, Copy)]
#[repr(C)]
struct MyDataStruct {
    a: u8,
    b: u32,
}

let my_data = MyDataStruct { a: 0, b: 42 };

// allocate an uninit buffer of some size
let my_buffer: MyBufferType = some_api.alloc_buffer_size(2048);

// use `RawAllocation` helper to allow access to a presser `Slab`.
// alternatively, you could implement the `Slab` on your buffer type directly if that
// type is owned by your code!
let raw_allocation = presser::RawAllocation::from_raw_parts(my_buffer.ptr(), my_buffer.size());

// here we assert that we have exclusive access to the data in the buffer, and get the actual
// `Slab` to use to copy into.
let slab = unsafe { raw_allocation.borrow_as_slab(); }

// now we may safely copy `my_data` into `my_buffer`, starting at a minimum offset of 0 into the buffer
let copy_record = presser::copy_to_offset(&my_data, &mut slab, 0)?;

// note that due to alignment requirements of `my_data`, the *actual* start of the bytes of
// `my_data` may be placed at a different offset than requested. so, we check the returned
// `CopyRecord` to check the actual start offset of the copied data.
let actual_start_offset = copy_record.copy_start_offset;

请注意,实际访问复制的数据是一个完全独立的问题,presser(目前)不关心这个问题。请小心!

更多信息请参见 git main 文档发布版本文档

贡献

Contributor Covenant

我们欢迎社区对这个项目的贡献。

请阅读我们的 贡献指南 了解如何开始,在做出任何贡献之前,请阅读我们的 贡献条款

任何有意提交以包含在 Embark Studios 项目中的贡献,都应遵守 Rust 标准许可模型(MIT 或 Apache 2.0),因此将双重许可,如下所述,不附加任何额外的条款或条件。

许可

本贡献将根据您的选择采用以下任一许可:

  • Apache License,版本 2.0,([Apache 许可证](https://github.com/embarkstudios/presser/blob/eea263995892b761aae6307b0c2952cc7170a6bb/LICENSE-APACHE) 或 [Apache 许可证 2.0](https://apache.ac.cn/licenses/LICENSE-2.0))
  • MIT 许可证 ([MIT 许可证](https://github.com/embarkstudios/presser/blob/eea263995892b761aae6307b0c2952cc7170a6bb/LICENSE-MIT) 或 [MIT 许可证](http://opensource.org/licenses/MIT))

任选其一。

为了清晰起见,“你的”指的是 Embark 或任何其他贡献者/用户。

无运行时依赖

特性