use super::{ClusterError, PhantomData, RendezvousId, fmt};
mod bucket;
pub(crate) use bucket::ResolverBucket;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DecisionArm {
Left,
Right,
}
impl DecisionArm {
#[inline]
pub(crate) const fn index(self) -> u8 {
match self {
Self::Left => 0,
Self::Right => 1,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum ResolverOp {
Reject,
ResolveDecision,
SetResolver,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum ResolverErrorKind {
Reject,
Cluster(ClusterError),
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct ResolverError {
pub(crate) op: ResolverOp,
kind: ResolverErrorKind,
}
impl fmt::Debug for ResolverError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut debug = formatter.debug_struct("ResolverError");
debug.field("operation", &self.op_name());
debug.field("kind", &self.kind).finish()
}
}
impl ResolverError {
#[inline]
pub fn reject() -> Self {
Self {
op: ResolverOp::Reject,
kind: ResolverErrorKind::Reject,
}
}
#[inline]
pub(crate) fn cluster(error: ClusterError) -> Self {
Self {
op: ResolverOp::SetResolver,
kind: ResolverErrorKind::Cluster(error),
}
}
#[inline]
pub(crate) const fn with_operation(mut self, op: ResolverOp) -> Self {
self.op = op;
self
}
#[inline]
const fn op_name(&self) -> &'static str {
match self.op {
ResolverOp::Reject => "reject",
ResolverOp::ResolveDecision => "resolve_decision",
ResolverOp::SetResolver => "set_resolver",
}
}
}
impl From<ClusterError> for ResolverError {
#[inline]
fn from(error: ClusterError) -> Self {
Self::cluster(error)
}
}
#[repr(C)]
#[derive(Clone, Copy)]
struct DecisionResolverStatePayload<S> {
state: *const S,
pub(crate) resolver: fn(&S) -> Result<DecisionArm, ResolverError>,
}
#[derive(Clone, Copy)]
struct DecisionResolverStorage {
payload: DecisionResolverStatePayload<()>,
}
impl DecisionResolverStorage {
#[inline]
fn erase<S>(payload: DecisionResolverStatePayload<S>) -> Self {
const {
assert!(
core::mem::size_of::<DecisionResolverStatePayload<S>>()
== core::mem::size_of::<DecisionResolverStatePayload<()>>()
);
assert!(
core::mem::align_of::<DecisionResolverStatePayload<S>>()
== core::mem::align_of::<DecisionResolverStatePayload<()>>()
);
}
Self {
payload: unsafe {
core::mem::transmute_copy(&payload)
},
}
}
#[inline]
unsafe fn restore<S>(self) -> DecisionResolverStatePayload<S> {
const {
assert!(
core::mem::size_of::<DecisionResolverStatePayload<S>>()
== core::mem::size_of::<DecisionResolverStatePayload<()>>()
);
assert!(
core::mem::align_of::<DecisionResolverStatePayload<S>>()
== core::mem::align_of::<DecisionResolverStatePayload<()>>()
);
}
unsafe {
core::mem::transmute_copy(&self.payload)
}
}
}
#[derive(Clone, Copy)]
pub(crate) struct ErasedResolverRef<'cfg> {
storage: DecisionResolverStorage,
dispatch: unsafe fn(DecisionResolverStorage) -> Result<DecisionArm, ResolverError>,
_marker: PhantomData<&'cfg ()>,
}
impl<'cfg> ErasedResolverRef<'cfg> {
#[inline]
pub(crate) fn resolve_decision(self) -> Result<DecisionArm, ResolverError> {
unsafe {
(self.dispatch)(self.storage)
.map_err(|error| error.with_operation(ResolverOp::ResolveDecision))
}
}
}
#[derive(Clone, Copy)]
pub struct ResolverRef<'cfg, const RESOLVER_ID: u16> {
inner: ErasedResolverRef<'cfg>,
}
impl<'cfg, const RESOLVER_ID: u16> ResolverRef<'cfg, RESOLVER_ID> {
#[inline]
pub fn decision_state<S: 'cfg>(
state: &'cfg S,
resolver: fn(&S) -> Result<DecisionArm, ResolverError>,
) -> Self {
let payload = DecisionResolverStatePayload {
state: core::ptr::from_ref(state),
resolver,
};
Self {
inner: ErasedResolverRef {
storage: DecisionResolverStorage::erase(payload),
dispatch: dispatch_decision_state::<S>,
_marker: PhantomData,
},
}
}
#[inline]
pub fn decide(self) -> Result<DecisionArm, ResolverError> {
self.inner.resolve_decision()
}
#[inline]
pub(crate) const fn erase(self) -> ErasedResolverRef<'cfg> {
self.inner
}
}
unsafe fn dispatch_decision_state<S>(
storage: DecisionResolverStorage,
) -> Result<DecisionArm, ResolverError> {
let payload = unsafe { storage.restore::<S>() };
let state =
unsafe { &*payload.state };
(payload.resolver)(state)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct DynamicResolverKey {
pub(crate) rv: RendezvousId,
pub(crate) scope: crate::global::const_dsl::ScopeId,
}
impl DynamicResolverKey {
pub(crate) const fn new(rv: RendezvousId, scope: crate::global::const_dsl::ScopeId) -> Self {
Self { rv, scope }
}
}
#[derive(Clone, Copy)]
pub(crate) struct DynamicResolverEntry<'cfg> {
pub(crate) resolver_ref: ErasedResolverRef<'cfg>,
pub(crate) resolver_id: u16,
}