Skip to content

Instantly share code, notes, and snippets.

@the8472
Last active May 19, 2023 14:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save the8472/3eca46614323f8446e1d88f864dae365 to your computer and use it in GitHub Desktop.
Save the8472/3eca46614323f8446e1d88f864dae365 to your computer and use it in GitHub Desktop.
#![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