The following works:
/// With GATs this would be:
/// ```
/// trait WithLifetime { type T<'__>; }
/// ```
trait WithLifetime<'__> {
type T;
}
/// Convenience trait alias.
trait TakesLifetime
: for<'any> WithLifetime<'any>
{
const __: () = {
impl<T : ?Sized> TakesLifetime for T where Self
: for<'any> WithLifetime<'any>
{}
};
}
// iterator that parses data from an owned vector, one at a time
struct ParseFrom<F, T : TakesLifetime> {
parser: F,
data: Vec<u8>,
offset: usize,
marker: ::core::marker::PhantomData<fn(&()) -> <T as WithLifetime<'_>>::T>,
}
// need to specify lifetime 'a manually in F, so that T can also use it
// (otherwise we'd get forall<'a>, which is not what we want!)
impl<'a, F, T : TakesLifetime> ParseFrom<F, T>
where
F : Fn(&'a [u8]) -> Option<(&'a [u8], <T as WithLifetime<'a>>::T)>,
{
fn next (self: &'a mut Self)
-> Option<<T as WithLifetime<'a>>::T>
{
if let Some((rest, x)) = (self.parser)(&self.data[self.offset..]) {
self.offset += self.data.len() - rest.len();
Some(x)
} else {
None
}
}
}
// simple parser: take n-byte slices
fn take<const COUNT: usize> (input: &'_ [u8])
-> Option<(&'_ [u8], &'_ [u8])>
{
if input.len() >= COUNT {
Some((&input[COUNT ..], &input[0 .. COUNT]))
} else {
None
}
}
fn main ()
{
/// `&Referee`
struct Ref_<Referee : ?Sized + 'static>(
::core::marker::PhantomData<Referee>,
);
impl<'lt, Referee : ?Sized> WithLifetime<'lt> for Ref_<Referee> {
type T = &'lt Referee;
}
let mut p = ParseFrom::<_, Ref_<_>> {
// take 1-byte slices
parser: take::<1>,
data: vec![42, 27, 0, 0, 0],
offset: 0,
marker: std::marker::PhantomData,
};
println!("parsed: {:?}", p.next());
println!("parsed: {:?}", p.next());
}
-
Playground (stable Rust version)
-
Also note that at this point the 'a
lifetime in the trait impl
should be usable in higher-order position (impl<F, T>… where F : for<'a> …
), but when that many higher-order lifetimes and bounds are involved, the current trait solver gets confused and starts spitting out non-sense / refusing to compile correct code, so it turns out that having the 'a
lifetime not be higher-order in the impl
is a convenient way to circumvent that
.