use std::alloc::{GlobalAlloc, Layout};

use crate::{AllocProfile, AllocProfileGuard, AllocProfiler};

pub struct NullAllocProfiler<A: GlobalAlloc> {
    profiled_allocator: A,
}

impl<A: GlobalAlloc> NullAllocProfiler<A> {
    pub const fn new(profiled_allocator: A) -> Self {
        Self { profiled_allocator }
    }
}

#[inherent::inherent]
impl<A: GlobalAlloc> AllocProfiler for NullAllocProfiler<A> {
    pub fn get_current_profile(&self) -> AllocProfile {
        AllocProfile::default()
    }

    pub fn profile_guard<'a>(&'a self, total: &'a mut AllocProfile) -> AllocProfileGuard<'a, Self> {
        AllocProfileGuard::new(self, total)
    }
}

unsafe impl<A: GlobalAlloc> GlobalAlloc for NullAllocProfiler<A> {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        unsafe { self.profiled_allocator.alloc(layout) }
    }

    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        unsafe { self.profiled_allocator.dealloc(ptr, layout) }
    }

    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        unsafe { self.profiled_allocator.alloc_zeroed(layout) }
    }

    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
        unsafe { self.profiled_allocator.realloc(ptr, layout, new_size) }
    }
}
