Skip to content

Instantly share code, notes, and snippets.

@Dessix
Last active July 7, 2022 03:47
Show Gist options
  • Save Dessix/43460ba941a8ce81cfac93af97e4439a to your computer and use it in GitHub Desktop.
Save Dessix/43460ba941a8ce81cfac93af97e4439a to your computer and use it in GitHub Desktop.
Rust Dependency Extraction (Not working, requires HRTB)
use frunk::{hlist::Selector, indices::Here};
trait Has<A> {
fn get(&self) -> &A;
}
impl<A, S> Has<A> for S
where
S: Selector<A, Here>,
{
fn get(&self) -> &A {
<S as Selector<A, Here>>::get(&self)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum Outcome {
Good,
Bad,
}
trait Extract<'a, Deps> {
fn extract(&'a self) -> Deps;
}
trait Run<'a, Ext, Deps> {
fn run(&'a self, ext: &'a Ext) -> Outcome;
}
impl<'a, Ext> Extract<'a, ()> for Ext {
fn extract(&'a self) -> () {
()
}
}
impl<'a, Ext: 'a, T, R> Extract<'a, (&'a T, R)> for Ext
where
Ext: Has<T> + Extract<'a, R>,
{
fn extract(&'a self) -> (&'a T, R) {
(self.get(), <Ext as Extract<'a, R>>::extract(self))
}
}
impl<'a, Ext: 'a, D, F> Run<'a, Ext, D> for F
where
Ext: Extract<'a, D>,
F: Fn(D) -> Outcome,
{
fn run(&'a self, exts: &'a Ext) -> Outcome {
self(<Ext as Extract<'a, D>>::extract(&exts))
}
}
fn my_simple_handler(req: (&u16, ())) -> Outcome {
let (a, ()) = req;
if *a == 42 {
Outcome::Good
} else {
Outcome::Bad
}
}
fn my_handler(req: (&u8, (&u32, (&u16, ())))) -> Outcome {
let (a, (b, (c, ()))) = req;
println!("{} {} {}", a, b, c);
if *a as u32 + *b as u32 + *c as u32 == 42 {
Outcome::Good
} else {
Outcome::Bad
}
}
fn main() {
println!("Hello, world!");
// Assert that unit extraction is valid
let _extract_unit: &dyn Extract<()> = &frunk::hlist![1u8, 2u32, 3u16];
// Assert that singlet extraction is valid
// Note that this works at all because `Here` is used as the fixed index to Extract
// If we allowed type inference, this would theoretically work, but we'd have to supply
// a *set* of indecies, which must all be inferred in reverse.
//
// This would be trivially solved by value-HRTBs, if I am not mistaken,
// but these are currently unsupported by Rust.
let _extract_single: &dyn Extract<(&u8, ())> = &frunk::hlist![1u8];
// Assert that an HList actually presents the given type
// This, again, works because `Here` is used, as above with `_extract_single`.
let outcome_simple = Run::run(&my_simple_handler, &frunk::hlist![1u16]);
// This would work if we could extract multiple but we need to deep-infer indecies
let outcome = Run::run(&my_handler, &frunk::hlist![1u8, 2u32, 3u16]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment