Hello! I created this minimal example for a problem I'm facing. I have the following trait that is easily implemented for owned types:
trait Deserialize: Sized {
type Error;
fn deserialize(buf: &mut &[u8]) -> Result<Self, Self::Error>;
}
struct Owned([u8; 2]);
impl Deserialize for Owned {
type Error = TryFromSliceError;
fn deserialize(buf: &mut &[u8]) -> Result<Self, Self::Error> {
let (data, rest) = buf.split_at(2);
let owned = Owned(data.try_into()?);
*buf = rest;
Ok(owned)
}
}
I also have this extension trait implemented for all implementers of Deserialize
:
trait FromHex: Deserialize {
fn from_hex(hex: impl AsRef<[u8]>) -> Result<Self, Self::Error> {
let bytes = hex::decode(hex).unwrap(); // error ignored in the example
Self::deserialize(&mut &bytes[..])
}
}
impl<T> FromHex for T where T: Deserialize {}
This compiles. However, if I want to implement Deserialize
for borrowed types, I have to add lifetimes to it:
struct Borrowed<'a>(&'a [u8]);
impl<'a> Deserialize<'a> for Borrowed<'a> {
type Error = ();
fn deserialize(buf: &mut &'a [u8]) -> Result<Self, Self::Error> {
Ok(Borrowed(buf))
}
}
And of course this breaks FromHex
, since the bytes
slice in its implementation does not live long enough.
My question is: how can I allow Deserialize
to be implemented for both owned and borrowed types, and implement FromHex
only for types that are both owned and Deserialize
?
In other words, I would need something like trait FromHex: Deserialize<'_>
, which is not valid syntax. What's the most idiomatic solution here? Create separate Deserialize
traits for owned and borrowed types? Change the buf
parameter type to something else? Thank you in advance!
Edit: I tried using HRTB but couldn't find a solution either. Here's a playground.