use crate::uses::*;

pub trait Fetcher<K, T> {
	fn get(&self, _: K) -> &T;
	fn take(&self, _: K) -> T;
}

pub struct Prefetched<'a, K, T, M: Fetcher<K, T>> {
	s: UnsafeCell<mSelf<'a, K, T, M>>,
}
enum mSelf<'a, K, T, M: Fetcher<K, T>> {
	Started(Box<Option<(K, &'a M)>>),
	Done(&'a T),
}

impl<'a, K, T, M: Fetcher<K, T>> Prefetched<'a, K, T, M> {
	pub fn new(k: K, m: &'a M) -> Self {
		Self {
			s: UnsafeCell::new(Started(Box::new(Some((k, m))))),
		}
	}
	pub fn get(&self) -> &T {
		let s = unsafe { &mut *self.s.get() };
		match s {
			Done(v) => v,
			Started(b) => {
				let (k, m) = b.take().unwrap();
				let v = m.get(k);
				*s = Done(v);
				v
			}
		}
	}
	pub fn take(self) -> T {
		let s = self.s.into_inner();
		match s {
			Done(_) => ASSERT!(false, "Batched value already borrowed, can't take"),
			Started(b) => {
				let (k, m) = b.unwrap();
				m.take(k)
			}
		}
	}
}

use mSelf::{Done, Started};
