use thiserror::Error;
use crate::{
epoch,
num::IdLimit,
store::{Lifecycle, slots},
tag,
};
#[derive(Debug)]
pub(crate) struct Config<F, S> {
first: F,
second: S,
}
impl<F, S> Config<F, S> {
pub(crate) fn new(first: F, second: S) -> Self {
Self { first, second }
}
}
impl<F, S> slots::SlotsConfig for Config<F, S>
where
F: slots::SlotsConfig,
S: slots::SlotsConfig,
{
type Slots = Cons<F::Slots, S::Slots>;
type Error = ConsError<F::Error, S::Error>;
unsafe fn build(
self,
handle: epoch::RegistryHandle,
tags: &tag::Authoritative,
) -> Result<Self::Slots, Self::Error> {
let first = unsafe { self.first.build(handle.clone(), tags) }.map_err(ConsError::First)?;
let second = unsafe { self.second.build(handle, tags) }.map_err(ConsError::Second)?;
let first_limit = slots::Slots::id_limit(&first);
let second_limit = slots::Slots::id_limit(&second);
if first_limit != second_limit {
return Err(ConsError::MismatchLimits {
first: first_limit,
second: second_limit,
});
}
Ok(Cons::new(first, second))
}
}
#[derive(Debug, Error)]
pub(crate) enum ConsError<F, S> {
#[error("couldn't construct first slots")]
First(#[source] F),
#[error("couldn't construct second slots")]
Second(#[source] S),
#[error(
"id-limit for first ({}) not equal to the id-limit for second ({})",
first,
second
)]
MismatchLimits { first: IdLimit, second: IdLimit },
}
#[derive(Debug)]
pub(crate) struct Cons<F, S> {
first: F,
second: S,
}
impl<F, S> Cons<F, S> {
fn new(first: F, second: S) -> Self {
Self { first, second }
}
pub(crate) fn first(&self) -> &F {
&self.first
}
pub(crate) fn second(&self) -> &S {
&self.second
}
}
impl<F, S> slots::Slots for Cons<F, S>
where
F: slots::Slots,
S: slots::Slots,
{
type Exclusive<'a> = Exclusive<F::Exclusive<'a>, S::Exclusive<'a>>;
fn id_limit(&self) -> IdLimit {
self.first.id_limit()
}
unsafe fn acquire(&self, i: u32, _: Lifecycle) -> Self::Exclusive<'_> {
unsafe {
Exclusive::new(
self.first.acquire(i, Lifecycle::new()),
self.second.acquire(i, Lifecycle::new()),
)
}
}
unsafe fn retire(&self, i: u32, _: Lifecycle) {
unsafe {
self.first.retire(i, Lifecycle::new());
self.second.retire(i, Lifecycle::new());
}
}
unsafe fn reclaim(&self, i: u32, _: Lifecycle) {
unsafe {
self.first.reclaim(i, Lifecycle::new());
self.second.reclaim(i, Lifecycle::new());
}
}
}
#[derive(Debug)]
pub(crate) struct Exclusive<F, S> {
first: F,
second: S,
}
impl<F, S> Exclusive<F, S> {
fn new(first: F, second: S) -> Self {
Self { first, second }
}
pub(crate) fn first(&mut self) -> &mut F {
&mut self.first
}
pub(crate) fn second(&mut self) -> &mut S {
&mut self.second
}
}
impl<F, S> slots::Exclusive for Exclusive<F, S>
where
F: slots::Exclusive,
S: slots::Exclusive,
{
fn publish(self, _: Lifecycle) {
self.first.publish(Lifecycle::new());
self.second.publish(Lifecycle::new());
}
fn freeze(self, _: Lifecycle) {
self.first.freeze(Lifecycle::new());
self.second.freeze(Lifecycle::new());
}
fn abort(self, _: Lifecycle) {
self.first.abort(Lifecycle::new());
self.second.abort(Lifecycle::new());
}
}