I am not sure that my title is very convincing, let me try to expose the problem that I am facing.
I have a trait, which defines a generic function with a return type to be defined by the implementations.
pub trait Encoder<Value> {
/// Return type of the encode method
/// This type has to expose a slice of bytes, but does not have to have ownership
type EncodedValue<'a>: AsRef<[u8]>
where
Value: 'a;
/// Encode a value
fn encode(value: &Value) -> Self::EncodedValue<'_>;
}
The EncodedValue
only needs to expose a slice of bytes. It can be owned, such as Vec<u8>
, but it could also be just a reference to some bytes. The important thing here is that the trait Encoder
does not define if its implementation generates owned values or references.
For instance, here's one implementation that does not take ownership of anything.
/// An encoder that simply returns the bytes, without taking ownership of them.
struct PassThroughEncoder;
/// We define this encoder just for types that owns some bytes and can expose it
impl<T> Encoder<T> for PassThroughEncoder
where
T: AsRef<[u8]>,
{
type EncodedValue<'a> = &'a [u8]
where
T: 'a;
fn encode(value: &T) -> Self::EncodedValue<'_> {
value.as_ref()
}
}
Then, I can use this implementation, for instance like this (I know it's stupid, i am just trying to create a minimal example)
/// This works fine !
/// But notice that the encoder used is specified to be `PassThroughEncoder`
fn encode_with_specific_encoder<T>(value: &T) -> &[u8]
where
T: AsRef<[u8]>,
{
let encoded = PassThroughEncoder::encode(value);
encoded.as_ref()
}
But my problem comes when I want to define the function above, but with a generic type for the encoder, ie using the trait and not one implementation.
/// If we leave it to be a generic encoder, then it will not work.
/// The reason why this does not work is because `Encoded` is not necessarly a borrowed type.
/// It could be an owned type with a lifetime definition.
fn encode_with_generic_encoder<'a, T, E>(value: &'a T) -> &[u8]
where
T: AsRef<[u8]>,
E: Encoder<T>,
// BELOW are all the trait bounds that I tried to add, and none of them works...
// E::EncodedValue<'a>: 'a,
// <E as Encoder<T>>::EncodedValue<'a>: 'a
// E::EncodedValue<'a>: Borrow<[u8]>
{
let encoded = E::encode(value);
encoded.as_ref()
}
Of course, I understand that this function can't work if the output of E::encode
is an owned type.
Hence my question: How can I restrict the implementation of encode_with_generic_encoder
to only work with implementations of Encoder
where the returned type EncodedValue
is not owned but is a borrow ?
I have tried the 3 commented lines in the trait bounds, but none of them works. Is this simply not possible ?
Thanks in advance for any help !