implement allocators as zsts

This commit is contained in:
Corwin 2022-07-31 00:44:12 +01:00
parent 3ec95a0277
commit e92e8d39a5
3 changed files with 27 additions and 10 deletions

View file

@ -9,9 +9,9 @@ use alloc::boxed::Box;
#[agb::entry] #[agb::entry]
fn main(_gba: agb::Gba) -> ! { fn main(_gba: agb::Gba) -> ! {
loop { loop {
let a = Box::new_in(1, agb::EWRAM_ALLOC); let a = Box::new_in(1, agb::ExternalAllocator);
let b = Box::new(1); let b = Box::new(1);
let c = Box::new_in(3, agb::IWRAM_ALLOC); let c = Box::new_in(3, agb::InternalAllocator);
agb::println!("ewram allocation made to {:?}", &*a as *const _); agb::println!("ewram allocation made to {:?}", &*a as *const _);
agb::println!("global allocation made to {:?}", &*b as *const _); agb::println!("global allocation made to {:?}", &*b as *const _);
agb::println!("iwram allocation made to {:?}", &*c as *const _); agb::println!("iwram allocation made to {:?}", &*c as *const _);

View file

@ -1,4 +1,4 @@
use core::alloc::Layout; use core::alloc::{Allocator, Layout};
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use core::ptr::NonNull; use core::ptr::NonNull;
@ -43,6 +43,20 @@ static GLOBAL_ALLOC: BlockAllocator = unsafe {
}) })
}; };
macro_rules! impl_zst_allocator {
($name_of_struct: ty, $name_of_static: ident) => {
unsafe impl Allocator for $name_of_struct {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
$name_of_static.allocate(layout)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
$name_of_static.deallocate(ptr, layout)
}
}
};
}
/// This is the allocator for the External Working Ram. This is currently /// This is the allocator for the External Working Ram. This is currently
/// equivalent to the Global Allocator (where things are allocated if no allocator is provided). This implements the allocator trait, so /// equivalent to the Global Allocator (where things are allocated if no allocator is provided). This implements the allocator trait, so
/// is meant to be used in specifying where certain structures should be /// is meant to be used in specifying where certain structures should be
@ -64,7 +78,9 @@ static GLOBAL_ALLOC: BlockAllocator = unsafe {
/// ); /// );
/// # } /// # }
/// ``` /// ```
pub static EWRAM_ALLOC: &BlockAllocator = &GLOBAL_ALLOC; pub struct ExternalAllocator;
impl_zst_allocator!(ExternalAllocator, GLOBAL_ALLOC);
/// This is the allocator for the Internal Working Ram. This implements the /// This is the allocator for the Internal Working Ram. This implements the
/// allocator trait, so is meant to be used in specifying where certain /// allocator trait, so is meant to be used in specifying where certain
@ -86,7 +102,10 @@ pub static EWRAM_ALLOC: &BlockAllocator = &GLOBAL_ALLOC;
/// ); /// );
/// # } /// # }
/// ``` /// ```
pub static IWRAM_ALLOC: &BlockAllocator = &__IWRAM_ALLOC; pub struct InternalAllocator;
impl_zst_allocator!(InternalAllocator, __IWRAM_ALLOC);
static __IWRAM_ALLOC: BlockAllocator = unsafe { static __IWRAM_ALLOC: BlockAllocator = unsafe {
BlockAllocator::new(StartEnd { BlockAllocator::new(StartEnd {
start: iwram_data_end, start: iwram_data_end,
@ -227,7 +246,7 @@ mod test {
#[test_case] #[test_case]
fn allocate_to_iwram_works(_gba: &mut crate::Gba) { fn allocate_to_iwram_works(_gba: &mut crate::Gba) {
let a = Box::new_in(1, IWRAM_ALLOC); let a = Box::new_in(1, InternalAllocator);
let p = &*a as *const i32; let p = &*a as *const i32;
let addr = p as usize; let addr = p as usize;
assert!( assert!(

View file

@ -190,7 +190,7 @@ pub mod syscall;
/// Interactions with the internal timers /// Interactions with the internal timers
pub mod timer; pub mod timer;
pub use {agb_alloc::EWRAM_ALLOC, agb_alloc::IWRAM_ALLOC}; pub use {agb_alloc::ExternalAllocator, agb_alloc::InternalAllocator};
#[cfg(not(any(test, feature = "testing")))] #[cfg(not(any(test, feature = "testing")))]
#[panic_handler] #[panic_handler]
@ -206,8 +206,6 @@ fn panic_implementation(info: &core::panic::PanicInfo) -> ! {
loop {} loop {}
} }
static mut GBASINGLE: single::Singleton<Gba> = single::Singleton::new(unsafe { Gba::single_new() });
/// The Gba struct is used to control access to the Game Boy Advance's hardware in a way which makes it the /// The Gba struct is used to control access to the Game Boy Advance's hardware in a way which makes it the
/// borrow checker's responsibility to ensure no clashes of global resources. /// borrow checker's responsibility to ensure no clashes of global resources.
/// ///
@ -245,7 +243,7 @@ impl Gba {
#[doc(hidden)] #[doc(hidden)]
#[must_use] #[must_use]
pub unsafe fn new_in_entry() -> Self { pub unsafe fn new_in_entry() -> Self {
GBASINGLE.take() Self::single_new()
} }
const unsafe fn single_new() -> Self { const unsafe fn single_new() -> Self {