1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! [Proof of Concept] Allocator singletons and parameterized collections on stable
//!
//! # Isn't the `alloc` crate going to be stabilized in 1.36?
//!
//! Yes, and you will be able to use it in libraries and `std` binaries but *not* in `no_std`
//! binaries because `alloc` has a hard dependency on `#[global_allocator]` (stable) and, on
//! `no_std`, `#[global_allocator]` has a hard dependency on `#[alloc_error_handler]` which is
//! unstable and has no stabilization date.
//!
//! # Features
//!
//! - You are not limited to a single global allocator; you can create as many allocators as you
//!   want.
//!
//! - Instantiate collections on any of these allocators.
//!
//! - Works on stable.
//!
//! # Cons
//!
//! - Doesn't integrate with the `alloc` crate. Meaning that we need to re-create that crate from
//! scratch.
//!
//! - Dynamically Sized Types (e.g. `Box<[u8]>` and `Box<dyn Fn()>`) are not supported because
//! [`CoerceUnsized`] and [`Unsize`] are unstable APIs.
//!
//! [`CoerceUnsized`]: https://doc.rust-lang.org/core/ops/trait.CoerceUnsized.html
//! [`Unsize`]: https://doc.rust-lang.org/core/marker/trait.Unsize.html
//!
//! # Example
//!
//! ``` ignore
//! #![no_main]
//! #![no_std]
//!
//! use core::alloc::Layout;
//!
//! use alloc_many::{alloc, oom};
//! use alloc_many_bump::{consts, BumpAlloc}; // NOTE: MSRV = 1.36
//! use alloc_many_collections::Box; // instead of the (still) unstable `alloc` crate
//! use cortex_m_rt::entry;
//! use panic_halt as _; // panic handler
//!
//! // instantiate a bump allocator and bind it to the type `A`
//! #[allocator] // instead of the reserved `#[global_allocator]`
//! static A: BumpAlloc<consts::U128> = BumpAlloc::new();
//!
//! #[entry]
//! fn main() -> ! {
//!     // allocate this value on allocator `A`
//!     let _x: Box<A, _> = Box::new(0);
//!
//!     loop {}
//! }
//!
//! // called when any allocator signals OOM
//! #[oom] // instead of the reserved, unstable `#[alloc_error_handler]`
//! fn oom(_: Layout) -> ! {
//!     loop {}
//! }
//! ```
//!
//! (Yes, a bump pointer allocator is not a really good choice for an allocator. You may want to
//! check out [my TLSF allocator][tlsf])
//!
//! [tlsf]: https://github.com/japaric/tlsf
//!
//! # Minimum Supported Rust Version (MSRV)
//!
//! This crate is guaranteed to compile on stable Rust 1.32 and up. It might compile on older
//! versions but that may change in any new patch release.

#![cfg_attr(not(test), no_std)]
#![deny(missing_docs)]
#![deny(rust_2018_compatibility)]
#![deny(rust_2018_idioms)]
#![deny(warnings)]

#[allow(unused_extern_crates)]
#[cfg(test)]
extern crate self as alloc_many;

use core::alloc::Layout;

pub use alloc_many_macros::{allocator, oom};

/// Singleton version of [`core::alloc::GlobalAlloc`][0]
///
/// [0]: https://doc.rust-lang.org/core/alloc/trait.GlobalAlloc.html
pub unsafe trait Alloc {
    /// Returns a pointer meeting the size and alignment guarantees of `layout`
    ///
    /// Singleton version of [`core::alloc::GlobalAlloc::alloc`][0]
    ///
    /// [0]: https://doc.rust-lang.org/core/alloc/trait.GlobalAlloc.html#tymethod.alloc
    unsafe fn alloc(layout: Layout) -> *mut u8;

    /// Deallocate the memory referenced by `ptr`
    ///
    /// Singleton version of [`core::alloc::GlobalAlloc::dealloc`][0]
    ///
    /// [0]: https://doc.rust-lang.org/core/alloc/trait.GlobalAlloc.html#tymethod.dealloc
    unsafe fn dealloc(ptr: *mut u8, layout: Layout);

    /// Behaves like `alloc`, but also ensures that the contents are set to zero before being
    /// returned.
    ///
    /// Singleton version of [`core::alloc::GlobalAlloc::alloc_zeroed`][0]
    ///
    /// [0]: https://doc.rust-lang.org/core/alloc/trait.GlobalAlloc.html#tymethod.alloc_zeroed
    unsafe fn alloc_zeroed(layout: Layout) -> *mut u8;

    /// Shrink or grow a block of memory to the given `new_size`. The block is described by the
    /// given `ptr` pointer and `layout`.
    ///
    /// Singleton version of [`core::alloc::GlobalAlloc::realloc`][0]
    ///
    /// [0]: https://doc.rust-lang.org/core/alloc/trait.GlobalAlloc.html#tymethod.realloc
    unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8;
}