One worthy goal would be to be able to perform compile-time size/alignment assertions for inline storage without changing the final api, and retaining the storage-agnostic goal of the final container objects. Heap storage should not do any assertions.
My approach is to use generic associated types as assertion objects and have the final create function perform the check using the assertion object directly. This way each associated assertion is a policy for the final create function. For all storages the assertion is performed as a trait requirement on create, the trick is to make the assertion always pass for Heap storages but possibly-fail for Inline storages.
Here is a POC of this.
Unfortunately having the check being part of the signature means that all call sites will need to propagate the constraint even if we know that eg on HeapStorage it will always pass. The compiler first checks the trait bounds and refuses to evaluate the bound itself. This means that if we attempt to make an alias with HeapStorage the constraint will have to leak to user code as well.
Eg a user can't write an external create function:
fn create<T>(val : T) -> RawBox<T, HeapStorage> {
RawBox::create(val)
}
even though the trait is always valid. Instead they have to write the following:
fn create<T>(val : T) -> RawBox<T, HeapStorage> where [u8 ; size_assert::<HeapStorage, S>()] : Sized {
RawBox::create(val)
}
it would be nice if the compiler attempted to evaluate the trait first. The above should be able to reduce to:
[u8 ; {HeapStorage::Asserter<T>::VALUE as usize} - 1] : Sized =>
// At this point AlwaysTrueAsserter is parameterized but we can avoid it.
[u8 ; {AlwaysTrueAsserter::VALUE as usize} - 1] : Sized =>
[u8 ; {true as usize} - 1] : Sized =>
[u8 ; 0] : Sized
So the fact that I have to specify the bound seems a bit unneeded to me.
One worthy goal would be to be able to perform compile-time size/alignment assertions for inline storage without changing the final api, and retaining the storage-agnostic goal of the final container objects. Heap storage should not do any assertions.
My approach is to use generic associated types as assertion objects and have the final create function perform the check using the assertion object directly. This way each associated assertion is a policy for the final create function. For all storages the assertion is performed as a trait requirement on create, the trick is to make the assertion always pass for Heap storages but possibly-fail for Inline storages.
Here is a POC of this.
Unfortunately having the check being part of the signature means that all call sites will need to propagate the constraint even if we know that eg on HeapStorage it will always pass. The compiler first checks the trait bounds and refuses to evaluate the bound itself. This means that if we attempt to make an alias with HeapStorage the constraint will have to leak to user code as well.
Eg a user can't write an external create function:
even though the trait is always valid. Instead they have to write the following:
it would be nice if the compiler attempted to evaluate the trait first. The above should be able to reduce to:
So the fact that I have to specify the bound seems a bit unneeded to me.