Yes, this can be done with lifetimes and borrowing.
struct WithAlloc<'a,T,A: Allocator + 'a> {
data: *mut T,
_pd: PhantomData<fn(&'a ()) -> &'a ()>, //this gives us invariant lifetime, which cannot be weaken nor strengthen
}
Here, WithAlloc
struct doesn't borrow an allocator, but yet, an instance of the type may not be called with a reference to a wrong allocator.
If it is a type produced by desugaring, then the following example is correct (Edit: it is not - I didn't understood how ghost-cell works):
let alloc1 = ...;
let alloc2 = ...;
let box_in_1;
with alloc: Allocator = &alloc1 {
box_in_1 = Box::new(...); //there, `box_in_1` has got a branded reference to `alloc1`
}
with alloc = &alloc1 {
drop(box_in_1) //OK, since both references have the same lifetime.
}
with alloc = &alloc2 {
drop(box_in_1) //Error, because lifetime of `&alloc2` is not the same as of `&alloc1`
}
So we can prove whether we had allocated with some specific allocator or not.