use o3::{
base::{cell::region, marker::ThreadBound},
buffer::segments,
};
use crate::body::{
buffered,
credit::{Amount, Origin},
};
mod bind;
#[derive(Clone, Copy, Debug)]
pub struct Stored {
_private: (),
}
impl Stored {
pub(in crate::body) const fn new() -> Self {
Self { _private: () }
}
}
pub struct Account {
retained: Amount,
_thread: ThreadBound,
}
impl Account {
pub const fn new() -> Self {
Self {
retained: Amount::new(0, segments::Count::EMPTY),
_thread: ThreadBound::NEW,
}
}
pub const fn retained(&self) -> Amount {
self.retained
}
pub fn scope<R>(
&mut self,
run: impl for<'id> FnOnce(Ledger<'_, region::Identity<'id>>) -> R,
) -> R {
region::Token::scope(|token| {
run(Ledger {
retained: &mut self.retained,
origin: token.proof(),
})
})
}
}
impl Default for Account {
fn default() -> Self {
Self::new()
}
}
pub struct Ledger<'a, O: Origin> {
retained: &'a mut Amount,
origin: O,
}
impl<O: Origin> Ledger<'_, O> {
pub const fn retained(&self) -> Amount {
*self.retained
}
pub unsafe fn bind<T: Bind<Origin = Stored>>(&self, value: T) -> T::Bound<O> {
unsafe { value.bind(self.origin) }
}
pub unsafe fn bind_mut<'a, S>(
&self,
state: &'a mut buffered::State<S>,
) -> buffered::Loan<'a, S, O> {
buffered::Loan {
state,
_origin: self.origin,
}
}
pub unsafe fn store<T: Bind<Origin = O>>(&self, value: T) -> T::Bound<Stored> {
unsafe { value.bind(Stored::new()) }
}
pub(in crate::body) fn origin(&self) -> O {
self.origin
}
pub(in crate::body) fn amount(&mut self) -> &mut Amount {
self.retained
}
}
pub unsafe trait Bind {
type Origin: Origin;
type Bound<O: Origin>;
unsafe fn bind<O: Origin>(self, origin: O) -> Self::Bound<O>;
}
const _: () = {
assert!(size_of::<Stored>() == 0);
assert!(size_of::<Account>() == size_of::<Amount>());
assert!(size_of::<Ledger<'static, region::Identity<'static>>>() == size_of::<&mut Amount>());
assert!(
size_of::<buffered::Loan<'static, (), region::Identity<'static>>>()
== size_of::<&mut buffered::State<()>>()
);
};