pub trait PhfBorrow<B: ?Sized> {
// Required method
fn borrow(&self) -> &B;
}
Expand description
Identical to std::borrow::Borrow
except omitting blanket impls to facilitate other
borrowing patterns.
The same semantic requirements apply:
In particular
Eq
,Ord
andHash
must be equivalent for borrowed and owned values:x.borrow() == y.borrow()
should give the same result asx == y
.
(This crate’s API only requires Eq
and PhfHash
, however.)
§Motivation
The conventional signature for lookup methods on collections looks something like this:
impl<K, V> Map<K, V> where K: PhfHash + Eq {
fn get<T: ?Sized>(&self, key: &T) -> Option<&V> where T: PhfHash + Eq, K: Borrow<T> {
...
}
}
This allows the key type used for lookup to be different than the key stored in the map so for
example you can use &str
to look up a value in a Map<String, _>
. However, this runs into
a problem in the case where T
and K
are both a Foo<_>
type constructor but
the contained type is different (even being the same type with different lifetimes).
The main issue for this crate’s API is that, with this method signature, you cannot perform a
lookup on a Map<UniCase<&'static str>, _>
with a UniCase<&'a str>
where 'a
is not
'static
; there is no impl of Borrow
that resolves to
impl Borrow<UniCase<'a>> for UniCase<&'static str>
and one cannot be added either because of
all the blanket impls.
Instead, this trait is implemented conservatively, without blanket impls, so that impls like
this may be added. This is feasible since the set of types that implement PhfHash
is
intentionally small.
This likely won’t be fixable with specialization alone but will require full support for lattice impls since we technically want to add overlapping blanket impls.