-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 9b56f8b
Showing
7 changed files
with
695 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
|
||
/target | ||
**/*.rs.bk | ||
Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[package] | ||
name = "boxext" | ||
version = "0.1.0" | ||
authors = ["Mike Hommey <[email protected]>"] | ||
license = "Apache-2.0/MIT" | ||
description = "Extensions to the `Box` type" | ||
repository = "https://github.com/glandium/boxext" | ||
keywords = ["box", "allocator"] | ||
|
||
[features] | ||
default = ["std"] | ||
std = [] | ||
unstable-rust = [] | ||
|
||
[dependencies] | ||
static_assertions = "0.2" | ||
allocator_api = { version = "0.2", optional = true } | ||
|
||
[dev-dependencies] | ||
boxext_derive = { path = "boxext_derive", version = "0.1" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "boxext_derive" | ||
version = "0.1.0" | ||
authors = ["Mike Hommey <[email protected]>"] | ||
license = "Apache-2.0/MIT" | ||
description = "Custom Derive for the `boxext::Zero` type" | ||
repository = "https://github.com/glandium/boxext" | ||
keywords = ["box", "allocator", "derive"] | ||
|
||
[dependencies] | ||
syn = ">= 0.12, <0.14" | ||
quote = ">=0.4, <0.6" | ||
|
||
[lib] | ||
proc-macro = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Copyright 2018 Mike Hommey | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
extern crate proc_macro; | ||
|
||
extern crate syn; | ||
|
||
#[macro_use] | ||
extern crate quote; | ||
|
||
use proc_macro::TokenStream; | ||
use syn::{Data, DeriveInput, Fields}; | ||
|
||
#[proc_macro_derive(Zero)] | ||
pub fn derive_zero(input: TokenStream) -> TokenStream { | ||
let input: DeriveInput = syn::parse(input).unwrap(); | ||
|
||
let name = input.ident; | ||
|
||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); | ||
|
||
let mut types = vec![]; | ||
|
||
match input.data { | ||
Data::Struct(ref data) => { | ||
match data.fields { | ||
Fields::Named(ref fields) => { | ||
for f in &fields.named { | ||
types.push(&f.ty); | ||
} | ||
} | ||
Fields::Unnamed(ref fields) => { | ||
for f in &fields.unnamed { | ||
types.push(&f.ty); | ||
} | ||
} | ||
Fields::Unit => {} | ||
} | ||
} | ||
_ => panic!("Can only derive(Zero) for structs"), | ||
} | ||
|
||
let predicates = if let Some(ref w) = where_clause { | ||
w.predicates.iter().collect() | ||
} else { | ||
vec![] | ||
}; | ||
|
||
let expanded = if predicates.is_empty() && types.is_empty() { | ||
quote! { | ||
unsafe impl #impl_generics ::boxext::Zero for #name #ty_generics {} | ||
} | ||
} else { | ||
quote! { | ||
unsafe impl #impl_generics ::boxext::Zero for #name #ty_generics | ||
where #(#predicates,)* #(#types: ::boxext::Zero,)* | ||
{} | ||
} | ||
}; | ||
|
||
expanded.into() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
// Copyright 2018 Mike Hommey | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
use core::ptr; | ||
use allocator_api::{Alloc, Box, RawVec}; | ||
use {BoxExt, Zero}; | ||
|
||
/// Extensions to the `allocator_api::Box` type | ||
pub trait BoxInExt<A: Alloc> { | ||
/// Type contained inside the `Box`. | ||
type Inner; | ||
|
||
/// Allocates memory in the given allocator and then places the result of | ||
/// `f` into it. | ||
/// | ||
/// This doesn't actually allocate if `Self::Inner` is zero-sized. | ||
/// | ||
/// When building with optimization enabled, this is expected to avoid | ||
/// copies, contrary to `Box::new_in`. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// extern crate allocator_api; | ||
/// extern crate boxext; | ||
/// use allocator_api::Box; | ||
/// use boxext::BoxInExt; | ||
/// # include!("dummy.rs"); | ||
/// | ||
/// struct Foo(usize, usize); | ||
/// | ||
/// impl Foo { | ||
/// fn new(a: usize, b: usize) -> Self { | ||
/// Foo(a, b) | ||
/// } | ||
/// } | ||
/// | ||
/// fn main() { | ||
/// // equivalent to `Box::new_in(Foo(1, 2), MyHeap)` | ||
/// let buf = Box::new_in_with(|| Foo(1, 2), MyHeap); | ||
/// | ||
/// // equivalent to `Box::new_in(Foo::new(2, 3), MyHeap)` | ||
/// let buf = Box::new_in_with(|| Foo::new(2, 3), MyHeap); | ||
/// } | ||
/// ``` | ||
fn new_in_with<F: FnOnce() -> Self::Inner>(f: F, a: A) -> Self; | ||
|
||
/// Allocates zeroed memory in the given allocator. | ||
/// | ||
/// This doesn't actually allocate if `Self::Inner` is zero-sized. | ||
/// | ||
/// This will get zeroed memory directly from the allocator. | ||
/// | ||
/// # Example | ||
/// | ||
/// ``` | ||
/// extern crate allocator_api; | ||
/// extern crate boxext; | ||
/// use allocator_api::Box; | ||
/// use boxext::BoxInExt; | ||
/// # include!("dummy.rs"); | ||
/// | ||
/// fn main() { | ||
/// // equivalent to `Box::new_in([0usize; 64], MyHeap)` | ||
/// let buf: Box<[usize; 64], _> = Box::new_zeroed_in(MyHeap); | ||
/// } | ||
/// ``` | ||
/// | ||
/// # Safety | ||
/// | ||
/// This method is only assumed safe for `Self::Inner` types implementing | ||
/// the [`Zero`] trait, and not available otherwise. See the definition | ||
/// of that trait. | ||
/// | ||
/// [`Zero`]: trait.Zero.html | ||
fn new_zeroed_in(a: A) -> Self | ||
where | ||
Self: Sized, | ||
Self::Inner: Zero; | ||
} | ||
|
||
impl<T, A: Alloc + Clone> BoxInExt<A> for Box<T, A> { | ||
type Inner = T; | ||
|
||
#[inline] | ||
fn new_in_with<F: FnOnce() -> Self::Inner>(f: F, a: A) -> Self { | ||
unsafe { | ||
let v = RawVec::<T, A>::with_capacity_in(1, a.clone()); | ||
let raw = Box::into_raw(v.into_box()) as *mut T; | ||
ptr::write(raw, f()); | ||
Box::from_raw_in(raw, a) | ||
} | ||
} | ||
|
||
#[inline] | ||
fn new_zeroed_in(a: A) -> Self | ||
where | ||
T: Zero, | ||
{ | ||
unsafe { | ||
let v = RawVec::<T, A>::with_capacity_zeroed_in(1, a.clone()); | ||
let raw = Box::into_raw(v.into_box()); | ||
Box::from_raw_in(raw as *mut T, a) | ||
} | ||
} | ||
} | ||
|
||
impl<T, A: Alloc + Clone + Default> BoxExt for Box<T, A> { | ||
type Inner = <Self as BoxInExt<A>>::Inner; | ||
|
||
/// Allocates memory in the given allocator and then places the result of | ||
/// `f` into it. | ||
/// | ||
/// This doesn't actually allocate if `Self::Inner` is zero-sized. | ||
/// | ||
/// When building with optimization enabled, this is expected to avoid | ||
/// copies, contrary to `allocator_api::Box::new_in`. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// extern crate allocator_api; | ||
/// extern crate boxext; | ||
/// use allocator_api::Box; | ||
/// use boxext::BoxExt; | ||
/// # include!("dummy.rs"); | ||
/// | ||
/// struct Foo(usize, usize); | ||
/// | ||
/// impl Foo { | ||
/// fn new(a: usize, b: usize) -> Self { | ||
/// Foo(a, b) | ||
/// } | ||
/// } | ||
/// | ||
/// fn main() { | ||
/// // equivalent to `Box::new_in(Foo(1, 2), MyHeap)` | ||
/// let buf: Box<_, MyHeap> = Box::new_with(|| Foo(1, 2)); | ||
/// | ||
/// // equivalent to `Box::new_in(Foo::new(2, 3), MyHeap)` | ||
/// let buf: Box<_, MyHeap> = Box::new_with(|| Foo::new(2, 3)); | ||
/// } | ||
/// ``` | ||
/// | ||
/// This is a convenience wrapper around [`allocator_api::Box::new_in_with`] | ||
/// when the allocator implements `Default`. | ||
/// | ||
/// [`allocator_api::Box::new_in_with`]: trait.BoxInExt.html#tymethod.new_in_with | ||
#[inline] | ||
fn new_with<F: FnOnce() -> Self::Inner>(f: F) -> Self { | ||
BoxInExt::new_in_with(f, Default::default()) | ||
} | ||
|
||
/// Allocates zeroed memory in the given allocator. | ||
/// | ||
/// This doesn't actually allocate if `Self::Inner` is zero-sized. | ||
/// | ||
/// This will get zeroed memory directly from it. | ||
/// | ||
/// # Example | ||
/// | ||
/// ``` | ||
/// extern crate allocator_api; | ||
/// extern crate boxext; | ||
/// use allocator_api::Box; | ||
/// use boxext::BoxExt; | ||
/// # include!("dummy.rs"); | ||
/// | ||
/// fn main() { | ||
/// // equivalent to `Box::new_in([0usize; 64], MyHeap)` | ||
/// let buf: Box<[usize; 64], MyHeap> = Box::new_zeroed(); | ||
/// } | ||
/// ``` | ||
/// | ||
/// This is a convenience wrapper around [`allocator_api::Box::new_zeroed_in`] | ||
/// when the allocator implements `Default`. | ||
/// | ||
/// [`allocator_api::Box::new_zeroed_in`]: trait.BoxInExt.html#tymethod.new_zeroed_in | ||
/// | ||
/// # Safety | ||
/// | ||
/// This method is only assumed safe for `Self::Inner` types implementing | ||
/// the [`Zero`] trait, and not available otherwise. See the definition | ||
/// of that trait. | ||
/// | ||
/// [`Zero`]: trait.Zero.html | ||
#[inline] | ||
fn new_zeroed() -> Self | ||
where | ||
T: Zero, | ||
{ | ||
BoxInExt::new_zeroed_in(Default::default()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/// A dummy allocator for tests. | ||
mod dummy { | ||
extern crate core; | ||
use super::allocator_api::{Alloc, AllocErr, Layout, Opaque}; | ||
use self::core::ptr::NonNull; | ||
|
||
#[derive(Clone, Default)] | ||
pub struct MyHeap; | ||
|
||
static mut HEAP_BUF: [u8; 4096] = [0; 4096]; | ||
static mut HEAP_CURSOR: usize = 0; | ||
|
||
unsafe impl<'a> Alloc for MyHeap { | ||
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { | ||
let ptr = HEAP_BUF.as_ptr() as usize; | ||
let mut start = HEAP_CURSOR; | ||
let modulo = (ptr + start) & (layout.align() - 1); | ||
if modulo != 0 { | ||
start += layout.align() - modulo; | ||
} | ||
assert_eq!((ptr + start) & (layout.align() - 1), 0); | ||
let end = start + layout.size(); | ||
let buf = HEAP_BUF.get_mut(start..end); | ||
HEAP_CURSOR = end; | ||
buf.map(|b| NonNull::new_unchecked(b as *mut [u8] as *mut u8 as *mut Opaque)) | ||
.ok_or_else(|| AllocErr) | ||
} | ||
unsafe fn dealloc(&mut self, _ptr: NonNull<Opaque>, _layout: Layout) {} | ||
} | ||
|
||
} | ||
|
||
use self::dummy::MyHeap; |
Oops, something went wrong.