Last active
May 19, 2023 14:45
-
-
Save the8472/3eca46614323f8446e1d88f864dae365 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(const_type_id)] | |
#![feature(const_maybe_uninit_array_assume_init)] | |
#![feature(const_maybe_uninit_write)] | |
#![feature(const_maybe_uninit_uninit_array)] | |
#![feature(maybe_uninit_array_assume_init)] | |
#![feature(maybe_uninit_uninit_array)] | |
#![feature(inline_const)] | |
#![feature(const_mut_refs)] | |
use core::mem::transmute; | |
use core::mem::MaybeUninit; | |
use std::any::TypeId; | |
use core::marker::PhantomData; | |
type TyErasedProvide = (TypeId, fn()); | |
struct ProvidedSet<Src, const N: usize> { | |
provided: [TyErasedProvide; N], | |
source: PhantomData<Src> | |
} | |
impl<Src, const N: usize> ProvidedSet<Src, N> { | |
const fn new(erased: [(PhantomData<Src>, TyErasedProvide); N]) -> Self { | |
let mut provided: [_; N] = MaybeUninit::uninit_array(); | |
let mut i = 0; | |
while i < N { | |
provided[i].write(erased[i].1); | |
i += 1; | |
} | |
// TODO: PHF the array | |
ProvidedSet { | |
provided: unsafe { MaybeUninit:: array_assume_init(provided) }, | |
source: PhantomData | |
} | |
} | |
fn get<'a, T: 'static>(&self, src: &'a Src) -> Option<&'a T> { | |
let id = TypeId::of::<T>(); | |
for (provided_id, getter) in self.provided.iter() { | |
if id == *provided_id { | |
let getter: &fn(&Src) -> &T = unsafe { transmute(getter) }; | |
return Some(getter(src)) | |
} | |
} | |
None | |
} | |
fn get_by_id<'a, T>(&self, id: TypeId, src: &'a Src) -> Option<&'a T> { | |
for (provided_id, getter) in self.provided.iter() { | |
if id == *provided_id { | |
let getter: &fn(&Src) -> &T = unsafe { transmute(getter) }; | |
return Some(getter(src)) | |
} | |
} | |
None | |
} | |
} | |
const fn provide<Src, Ty: 'static>(getter: fn(&Src) -> &Ty) -> (PhantomData<Src>, TyErasedProvide) { | |
let id = TypeId::of::<Ty>(); | |
(PhantomData::<Src>, (id, unsafe { transmute::<fn(&Src) -> &Ty, fn()>(getter)})) | |
} | |
#[derive(Debug)] | |
struct Backtrace { | |
val: String | |
} | |
struct FooError { | |
trace: Backtrace | |
} | |
const MY_PROVIDES: ProvidedSet<FooError, 1> = const { | |
// TODO: hide this behind a macro | |
ProvidedSet::new([ | |
provide(|foo: &FooError| &foo.trace) | |
]) | |
}; | |
// in the real Demand T is erased | |
struct Demand<'a, T> { | |
val: Option<&'a T>, | |
id: TypeId | |
} | |
impl<'a, T> Demand<'a, T> { | |
fn fullfill_from<Src, const N: usize>(&mut self, src: &'a Src, set: ProvidedSet<Src, N>) { | |
self.val = set.get_by_id(self.id, &src) | |
} | |
} | |
trait Provider { | |
// Required method | |
fn provide<'a, T: 'static>(&'a self, demand: &mut Demand<'a, T>); | |
} | |
impl Provider for FooError { | |
fn provide<'a, T: 'static>(&'a self, demand: &mut Demand<'a, T>) { | |
demand.fullfill_from(self, MY_PROVIDES) | |
} | |
} | |
fn main() { | |
let foo = FooError { | |
trace: Backtrace { | |
val: String::from("payload") | |
} | |
}; | |
let mut demand: Demand<'_, Backtrace> = Demand { | |
val: None, | |
id: TypeId::of::<Backtrace>() | |
}; | |
<FooError as Provider>::provide(&foo, &mut demand); | |
dbg!(demand.val); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment