Cast &self to mut (to use predefined trait where it isn't mut)

As pointed out in the comments, casting &self to &mut is undefined behavior and is not allowed even in unsafe code (though the compiler is powerless to prevent you from doing it in an unsafe block). Fortunately, it's not needed.

allocate() takes &self to allow the allocator to be used from multiple threads. (Remember that a &mut reference is exclusive, only one may exist at a time.) The simplest thread-safe way to get a mutable reference out of an immutable one is by wrapping the actual allocator in a mutex:

struct MappocAllocator {
    inner: Mutex<Mappoc>,  // your actual allocator
}

impl Allocator for MappocAllocator {
    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { 
        let alloc = self.inner.lock().unwrap();
        // now you have access to `&mut Mappoc` for the duration of the lock
        ...
    }
}

I'm not sure what kind of allocator would be able to allocate without making changes to the allocator itself

This is a misunderstanding of what &T means. A shared reference doesn't necessarily imply that the data under it won't change, it means that it's safe to use by multiple actors at once. For example, lock-free mutating APIs always take &self.

If the Mappoc allocator is written in Rust and is thread-safe (or partly/fully lock-free) itself, then its methods should take &self to begin with, and you won't need a mutex (because a mutex or its equivalent will be part of Mappoc implementation). If Mappoc's methods take &mut self, it means they're not safe to be invoked from multiple threads, and it's a good thing that Rust forces you to access them through a mutex. This is the system working exactly as designed.

Finally, some allocators, like mimalloc or jemalloc, are implemented in C or C++ that does its own locking. But then their Rust fronts don't need &mut self either because they invoke the actual allocator through a raw pointer.