{"id":29210695,"url":"https://github.com/embarkstudios/presser","last_synced_at":"2025-07-02T21:07:36.546Z","repository":{"id":61592323,"uuid":"552451008","full_name":"EmbarkStudios/presser","owner":"EmbarkStudios","description":"A crate to help you copy things into raw buffers without invoking spooky action at a distance (undefined behavior).","archived":false,"fork":false,"pushed_at":"2023-11-07T14:41:54.000Z","size":74,"stargazers_count":155,"open_issues_count":2,"forks_count":8,"subscribers_count":6,"default_branch":"main","last_synced_at":"2024-08-11T09:25:14.477Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EmbarkStudios.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null}},"created_at":"2022-10-16T16:17:26.000Z","updated_at":"2024-07-24T05:12:52.000Z","dependencies_parsed_at":"2023-11-06T23:59:42.571Z","dependency_job_id":null,"html_url":"https://github.com/EmbarkStudios/presser","commit_stats":{"total_commits":23,"total_committers":3,"mean_commits":7.666666666666667,"dds":0.08695652173913049,"last_synced_commit":"9050bfa7ef4d993603f7d1fda1504c580ca412f2"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/EmbarkStudios/presser","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmbarkStudios%2Fpresser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmbarkStudios%2Fpresser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmbarkStudios%2Fpresser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmbarkStudios%2Fpresser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EmbarkStudios","download_url":"https://codeload.github.com/EmbarkStudios/presser/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmbarkStudios%2Fpresser/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263215297,"owners_count":23431895,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-02T21:07:35.354Z","updated_at":"2025-07-02T21:07:36.530Z","avatar_url":"https://github.com/EmbarkStudios.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- Allow this file to not have a first line heading --\u003e\n\u003c!-- markdownlint-disable-file MD041 no-emphasis-as-heading --\u003e\n\n\u003c!-- inline html --\u003e\n\u003c!-- markdownlint-disable-file MD033 --\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n# `🗜 presser`\n\n**Utilities to help make working with raw, possibly-uninitialized buffers easier and safer.**\n\n[![Embark](https://img.shields.io/badge/embark-open%20source-blueviolet.svg)](https://embark.dev)\n[![Embark](https://img.shields.io/badge/discord-ark-%237289da.svg?logo=discord)](https://discord.gg/dAuKfZS)\n[![Crates.io](https://img.shields.io/crates/v/presser.svg)](https://crates.io/crates/presser)\n[![Published Docs](https://docs.rs/presser/badge.svg)](https://docs.rs/presser)\n[![Git Docs](https://img.shields.io/badge/git%20main%20docs-published-blue?style=plastic)](https://embarkstudios.github.io/presser/presser/index.html)\n[![dependency status](https://deps.rs/repo/github/EmbarkStudios/presser/status.svg)](https://deps.rs/repo/github/EmbarkStudios/presser)\n\u003c/div\u003e\n\n`presser` can help you when copying data into and reading data from raw buffers. One primary use-case is copying data into\ngraphics-api-allocated buffers which will then be accessed by the GPU. Common methods for doing this\nright now in Rust can often invoke UB in subtle and hard-to-see ways. For example, viewing an allocated\nbut uninitialized buffer as an `\u0026mut [u8]` **is instantly undefined behavior**\\*, and `transmute`ing even a\n`T: Copy` type which has *any padding bytes in its layout* as a `\u0026[u8]` to be the source of a copy is\n**also instantly undefined behavior**, in both cases because it is *invalid* to create a reference to an invalid\nvalue (and uninitialized memory is an invalid `u8`), *even if* your code never actually accesses that memory.\nThis immediately makes what seems like the most straightforward way to copy data into buffers unsound 😬\n\n\\* *If you're currently thinking to yourself \"bah! what's the issue? surely an uninit u8 is just any random bit pattern\nand that's fine we don't care,\" [check out this blog post](https://www.ralfj.de/blog/2019/07/14/uninit.html) by\n@RalfJung, one of the people leading the effort to better define Rust's memory and execution model. As is explored\nin that blog post, an* uninit *piece of memory is not simply* an arbitrary bit pattern, *it is a wholly separate\nstate about a piece of memory, outside of its value, which lets the compiler perform optimizations that reorder,\ndelete, and otherwise change the actual execution flow of your program in ways that cannot be described simply\nby \"the value could have* some *possible bit pattern\". LLVM and Clang are changing themselves to require special\n`noundef` attribute to perform many important optimizations that are otherwise unsound. For a concrete example\nof the sorts of problems this can cause, [see this issue @scottmcm hit](https://github.com/rust-lang/rust/pull/98919#issuecomment-1186106387).*\n\n## A bad example\n\n```rust\n#[derive(Clone, Copy)]\n#[repr(C)]\nstruct MyDataStruct {\n    a: u8,\n    b: u32,\n}\n\nlet my_data = MyDataStruct { a: 0, b: 42 };\n\n// 🚨 MyDataStruct contains 3 padding bytes after `a`, which are\n// uninit, therefore getting a slice that includes them is UB!\nlet my_data_bytes: \u0026[u8] = transmute(\u0026my_data);\n\n// allocate an uninit buffer of some size\nlet my_buffer: MyBufferType = some_api.alloc_buffer_size(2048);\n\n// 🚨 this is UB for the same reason, these bytes are uninit!\nlet buffer_as_bytes: \u0026mut [u8] =\n    slice::from_raw_parts(my_buffer.ptr(), my_buffer.size());\n\n// 🚨 this is UB because not only are both slices invalid,\n// this is not ensuring proper alignment!\nbuffer_as_bytes.copy_from_slice(my_data_bytes);\n```\n\n`presser` helps with this by allowing you to view raw allocated memory of some size as a \"`Slab`\" of memory and then\nprovides *safe, valid* ways to copy data into that memory:\n\n### A good example\n\n```rust\n#[derive(Clone, Copy)]\n#[repr(C)]\nstruct MyDataStruct {\n    a: u8,\n    b: u32,\n}\n\nlet my_data = MyDataStruct { a: 0, b: 42 };\n\n// allocate an uninit buffer of some size\nlet my_buffer: MyBufferType = some_api.alloc_buffer_size(2048);\n\n// use `RawAllocation` helper to allow access to a presser `Slab`.\n// alternatively, you could implement the `Slab` on your buffer type directly if that\n// type is owned by your code!\nlet mut raw_allocation = presser::RawAllocation::from_raw_parts(my_buffer.ptr(), my_buffer.size());\n\n// here we assert that we have exclusive access to the data in the buffer, and get the actual\n// `Slab` to use to copy into.\nlet mut slab = unsafe { raw_allocation.borrow_as_slab() };\n\n// now we may safely copy `my_data` into `my_buffer`, starting at a minimum offset of 0 into the buffer\nlet copy_record = presser::copy_to_offset(\u0026my_data, \u0026mut slab, 0)?;\n\n// note that due to alignment requirements of `my_data`, the *actual* start of the bytes of\n// `my_data` may be placed at a different offset than requested. so, we check the returned\n// `CopyRecord` to check the actual start offset of the copied data.\nlet actual_start_offset = copy_record.copy_start_offset;\n\n// we may later (*unsafely*) read back our data. note that the read helpers provided by presser\n// are mostly unsafe. They do help protect you from some common footguns, but you still ultimately need\n// to guarantee you put the proper data where you're telling it you put the proper data.\nlet my_copied_data_in_my_buffer: \u0026MyDataStruct = unsafe {\n    presser::read_at_offset(\u0026slab, actual_start_offset)?\n};\n```\n\nNote that, as seen at the end, actually accessing the copied data is still unsafe. This means that you still need\nto take care that you're laying out your data exactly as whatever later reads it expects, whether that be a graphics\nAPI or your own data structure built on top of `presser`. The read functions that `presser` provides help check some\ncommon footguns (ensuring the given offset within the slab is properly aligned and the slab has enough memory to contain\nthe wanted type), but they're still ultimately unsafe and require you to assert you put the proper data in the proper place.\n\nSee more in [the git `main` docs](https://embarkstudios.github.io/presser/presser/index.html)\nor [the released version docs](https://docs.rs/presser).\n\n## Contribution\n\n[![Contributor Covenant](https://img.shields.io/badge/contributor%20covenant-v1.4-ff69b4.svg)](CODE_OF_CONDUCT.md)\n\nWe welcome community contributions to this project.\n\nPlease read our [Contributor Guide](CONTRIBUTING.md) for more information on how to get started.\nPlease also read our [Contributor Terms](CONTRIBUTING.md#contributor-terms) before you make any contributions.\n\nAny contribution intentionally submitted for inclusion in an Embark Studios project, shall comply with the Rust standard licensing model (MIT OR Apache 2.0) and therefore be dual licensed as described below, without any additional terms or conditions:\n\n### License\n\nThis contribution is dual licensed under EITHER OF\n\n* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or \u003chttp://www.apache.org/licenses/LICENSE-2.0\u003e)\n* MIT license ([LICENSE-MIT](LICENSE-MIT) or \u003chttp://opensource.org/licenses/MIT\u003e)\n\nat your option.\n\nFor clarity, \"your\" refers to Embark or any other licensee/user of the contribution.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fembarkstudios%2Fpresser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fembarkstudios%2Fpresser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fembarkstudios%2Fpresser/lists"}