What you essentially want for the user to not write any unsafe code is this kind of interface:
trait Allocator {
fn allocate<'a, T>(&'a self, init: T) -> Handle<'a, T>;
fn deallocate<'a, T>(&'a self, handle: Handle<'a, T>);
fn read<T>(&self, handle: Handle<'_, T>) -> impl Deref<T>;
fn write<T>(&self, handle: Handle<'_, T>) -> impl DerefMut<T>;
}
&'a RefCell<T> is pretty close to a definition of Handle<'a, T>, except that Rust provides no implementations of allocate and deallocate that take a const instead of a mut reference for self. Trying to make an allocator that lets you safely deallocate something requires a completely different implementation of Handle<'a, T> than what RefCell can provide, and even if you're fine without deallocation, allocation with a const ref still requires unsafe to get the lifetime parameter right.