diff options
Diffstat (limited to 'third_party/rust/memalloc')
-rw-r--r-- | third_party/rust/memalloc/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/memalloc/Cargo.toml | 10 | ||||
-rw-r--r-- | third_party/rust/memalloc/README.md | 26 | ||||
-rw-r--r-- | third_party/rust/memalloc/src/lib.rs | 158 |
4 files changed, 195 insertions, 0 deletions
diff --git a/third_party/rust/memalloc/.cargo-checksum.json b/third_party/rust/memalloc/.cargo-checksum.json new file mode 100644 index 0000000000..fb0b4b7c7c --- /dev/null +++ b/third_party/rust/memalloc/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"af07b00f080db01744f57056b0a4d44194afc07831d12aaa256f12ae22f9723d","README.md":"dc9539e01a85abc218e7e4fc1a2ee4512025a3ea6295a25ab50de91c3b500398","src/lib.rs":"4635b797b1b7d65f4c500b8e031715946c2631de8792b62bfc96ed79b4eee887"},"package":"df39d232f5c40b0891c10216992c2f250c054105cb1e56f0fc9032db6203ecc1"}
\ No newline at end of file diff --git a/third_party/rust/memalloc/Cargo.toml b/third_party/rust/memalloc/Cargo.toml new file mode 100644 index 0000000000..bc4421c2cd --- /dev/null +++ b/third_party/rust/memalloc/Cargo.toml @@ -0,0 +1,10 @@ +[package] + +name = "memalloc" +version = "0.1.0" +authors = ["Jonathan Reem <jonathan.reem@gmail.com>"] +repository = "https://github.com/reem/rust-memalloc.git" +description = "Memory allocation in stable rust." +readme = "README.md" +license = "MIT" + diff --git a/third_party/rust/memalloc/README.md b/third_party/rust/memalloc/README.md new file mode 100644 index 0000000000..d2d0489009 --- /dev/null +++ b/third_party/rust/memalloc/README.md @@ -0,0 +1,26 @@ +# memalloc + +> Raw allocation APIs in stable rust. + +## [Documentation](https://crates.fyi/crates/memalloc/0.1.0) + +## Usage + +See the tests at the bottom of `src/lib.rs` for some examples. + +Use the crates.io repository; add this to your `Cargo.toml` along +with the rest of your dependencies: + +```toml +[dependencies] +memalloc = "0.1" +``` + +## Author + +[Jonathan Reem](https://medium.com/@jreem) is the primary author and maintainer of memalloc. + +## License + +MIT + diff --git a/third_party/rust/memalloc/src/lib.rs b/third_party/rust/memalloc/src/lib.rs new file mode 100644 index 0000000000..94cf7d2df7 --- /dev/null +++ b/third_party/rust/memalloc/src/lib.rs @@ -0,0 +1,158 @@ +#![cfg_attr(test, deny(warnings))] +#![deny(missing_docs)] + +//! # memalloc +//! +//! Memory allocation in stable rust, providing a similar interface to `std::rt::heap`, +//! notably these functions align everything according to the alignment of `u8`, rather +//! than using a user-provided alignment. +//! +//! Additionally, they do not allow for handling allocation failure, and will simply +//! abort the process on OOM. Unfortunately, this limitation is unavoidable if we want +//! to use only stable APIs. +//! + +use std::mem; + +/// Returns a pointer to `size` bytes of memory aligned to `mem::align_of::<u8>()`. +/// +/// On failure, aborts the process. +/// +/// Behavior is undefined if the requested size is 0. +#[inline] +pub unsafe fn allocate(size: usize) -> *mut u8 { + ptr_from_vec(Vec::with_capacity(size)) +} + +/// Resizes the allocation referenced by `ptr` to `new_size` bytes. +/// +/// On failure, aborts the process. +/// +/// If the allocation was relocated, the memory at the passed-in pointer is +/// undefined after the call. +/// +/// Behavior is undefined if the requested `new_size` is 0. +/// +/// The `old_size` parameter is the size used to create the allocation +/// referenced by `ptr`, or the `new_size` passed to previous reallocations. +pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, new_size: usize) -> *mut u8 { + if old_size > new_size { + let mut buf = Vec::from_raw_parts(ptr, new_size, old_size); + buf.shrink_to_fit(); + + ptr_from_vec(buf) + } else if new_size > old_size { + let additional = new_size - old_size; + + let mut buf = Vec::from_raw_parts(ptr, 0, old_size); + buf.reserve_exact(additional); + + ptr_from_vec(buf) + } else { + ptr + } +} + +/// Deallocates the memory referenced by `ptr`. +/// +/// Behavior is undefined if `ptr` is null. +/// +/// The `old_size` parameter is the size used to create the allocation +/// referenced by `ptr`, or the `new_size` passed to the last reallocation. +#[inline] +pub unsafe fn deallocate(ptr: *mut u8, old_size: usize) { + Vec::from_raw_parts(ptr, 0, old_size); +} + +/// A token empty allocation which cannot be read from or written to, +/// but which can be used as a placeholder when a 0-sized allocation is +/// required. +pub fn empty() -> *mut u8 { + 1 as *mut u8 +} + +#[inline] +fn ptr_from_vec(mut buf: Vec<u8>) -> *mut u8 { + let ptr = buf.as_mut_ptr(); + mem::forget(buf); + + ptr +} + +#[cfg(test)] +mod tests { + use std::ptr; + use {allocate, reallocate, deallocate, empty}; + + #[test] + fn test_empty() { + let ptr = empty(); + assert!(ptr != ptr::null_mut()); + } + + #[test] + fn test_allocate() { + let buffer = unsafe { allocate(8) }; + + assert!(buffer != ptr::null_mut()); + + unsafe { + ptr::write(buffer.offset(0), 8); + ptr::write(buffer.offset(1), 4); + ptr::write(buffer.offset(3), 5); + ptr::write(buffer.offset(5), 3); + ptr::write(buffer.offset(7), 6); + + assert_eq!(ptr::read(buffer.offset(0)), 8); + assert_eq!(ptr::read(buffer.offset(1)), 4); + assert_eq!(ptr::read(buffer.offset(3)), 5); + assert_eq!(ptr::read(buffer.offset(5)), 3); + assert_eq!(ptr::read(buffer.offset(7)), 6); + }; + + unsafe { deallocate(buffer, 8); } + + // Try a large buffer + let buffer = unsafe { allocate(1024 * 1024) }; + assert!(buffer != ptr::null_mut()); + + unsafe { + ptr::write(buffer.offset(1024 * 1024 - 1), 12); + assert_eq!(ptr::read(buffer.offset(1024 * 1024 - 1)), 12); + }; + + unsafe { deallocate(buffer, 1024 * 1024); } + } + + #[test] + fn test_reallocate() { + let mut buffer = unsafe { allocate(8) }; + assert!(buffer != ptr::null_mut()); + + buffer = unsafe { reallocate(buffer, 8, 16) }; + assert!(buffer != ptr::null_mut()); + + unsafe { + // Put some data in the buffer + ptr::write(buffer.offset(0), 8); + ptr::write(buffer.offset(1), 4); + ptr::write(buffer.offset(5), 3); + ptr::write(buffer.offset(7), 6); + }; + + // Allocate so in-place fails. + unsafe { allocate(128) }; + + buffer = unsafe { reallocate(buffer, 16, 32) }; + assert!(buffer != ptr::null_mut()); + + unsafe { + // Ensure the data is still there. + assert_eq!(ptr::read(buffer.offset(0)), 8); + assert_eq!(ptr::read(buffer.offset(1)), 4); + assert_eq!(ptr::read(buffer.offset(5)), 3); + assert_eq!(ptr::read(buffer.offset(7)), 6); + }; + } +} + |