pub trait Lower<'short, T: ?Sized, Lifetime: Sealed = BoundTo<&'short Self>> {
type Proxy: Deref<Target = T>;
// Required method
fn lower(&'short self) -> Self::Proxy;
}Expand description
For some problems, neither std::ops::Deref nor Reborrow alone are sufficient.
This can occur in cases where
- A
?Sizedwithout lifetimes type is desired for a clean API. - A container cannot implement
Derefto a target type.
As a concrete example, consider the following:
use diskann_utils::Reborrow;
// A type participating in generalized references.
enum ThisOrThat {
This(Vec<f32>),
That(Vec<f64>),
}
enum ThisOrThatView<'a> {
This(&'a [f32]),
That(&'a [f64]),
}
impl<'a> Reborrow<'a> for ThisOrThat {
type Target = ThisOrThatView<'a>;
fn reborrow(&'a self) -> Self::Target {
match self {
Self::This(v) => ThisOrThatView::This(&*v),
Self::That(v) => ThisOrThatView::That(&*v),
}
}
}
// We have a function taking a `?Sized` type.
fn takes_unsized<T: ?Sized>(_: &T) {}
fn calls_unsized<'a, U, T: ?Sized>(x: &'a U) {
// How do I call `takes_unsized`?
}The question we’re trying to answer is: how do we make a trait that allows both
calls_unsized::<'a, Vec<f32>, [f32]>calls_unsized::<'a, ThisOrThat, ThisOrThatView<'a>>
Observe that Vec<f32> can use Deref to get to [f32], but no such implementation
is possible for ThisOrThat.
§Lower
The Lower trait solves this problem by first lowering U to a proxy type that is
then dereferencable to T. To solve the above example:
use diskann_utils::reborrow::Lower;
fn calls_unsized<'a, U, T: ?Sized>(x: &'a U)
where
U: Lower<'a, T>,
{
takes_unsized::<T>(&x.lower())
}
impl<'short> Lower<'short, ThisOrThatView<'short>> for ThisOrThat {
type Proxy = diskann_utils::reborrow::Place<ThisOrThatView<'short>>;
fn lower(&'short self) -> Self::Proxy {
diskann_utils::reborrow::Place(self.reborrow())
}
}
fn with_vec(x: &Vec<f32>) {
calls_unsized::<Vec<f32>, [f32]>(x)
}
fn with_this_or_that<'a>(x: &'a ThisOrThat) {
calls_unsized::<'a, ThisOrThat, ThisOrThatView<'a>>(x)
}Note the use of [diskann_utils::reborrow::Place] to create a type that dereferences to
the contained value.