hibana 0.9.2

Session-typed choreographic programming for no_std Rust protocols, inspired by affine MPST
Documentation
use super::{
    ClusterError, DecisionArm, DynamicResolverEntry, DynamicResolverKey, RendezvousId, ResolverRef,
    SessionCluster,
};
impl<'cfg, T> SessionCluster<'cfg, T>
where
    T: crate::transport::Transport + 'cfg,
{
    fn ensure_dynamic_resolver_capacity(
        &self,
        rv_id: RendezvousId,
        additional_entries: usize,
    ) -> Result<(), ClusterError> {
        if additional_entries == 0 {
            return Ok(());
        }
        self.with_storage_mut(|core| {
            core.locals
                .ensure_dynamic_resolver_capacity(rv_id, additional_entries)
        })
    }

    pub(crate) fn dynamic_resolver(
        &self,
        key: DynamicResolverKey,
    ) -> Option<&DynamicResolverEntry<'cfg>> {
        /* SAFETY: resolver references are read through the cluster-owned registry after key validation. */
        unsafe { (*self.storage_ref_ptr()).locals.dynamic_resolver(key) }
    }

    pub(crate) fn set_resolver<const RESOLVER: u16, const ROLE: u8>(
        &self,
        rv_id: RendezvousId,
        program: &crate::runtime::program::RoleProgram<ROLE>,
        resolver: ResolverRef<'cfg, RESOLVER>,
    ) -> Result<(), ClusterError> {
        self.with_resident_program_ref(rv_id, program, |compiled| {
            let mut matched_sites = 0usize;
            let mut missing_sites = 0usize;
            for site in compiled.route_resolver_sites_for(RESOLVER) {
                matched_sites += 1;
                let site_scope = site.scope();
                if site_scope.is_none() {
                    return Err(ClusterError::ResolverReject {
                        resolver_id: RESOLVER,
                    });
                }
                let key = DynamicResolverKey::new(rv_id, site_scope);
                if self.dynamic_resolver(key).is_none() {
                    missing_sites += 1;
                }
            }
            if matched_sites == 0 {
                return Err(ClusterError::ResolverReject {
                    resolver_id: RESOLVER,
                });
            }
            self.ensure_dynamic_resolver_capacity(rv_id, missing_sites)?;
            for site in compiled.route_resolver_sites_for(RESOLVER) {
                self.register_dynamic_resolver_resolver(
                    rv_id,
                    site.resolver_id(),
                    site.scope(),
                    resolver,
                )?;
            }
            Ok(())
        })
    }

    pub(crate) fn register_dynamic_resolver_resolver<const RESOLVER: u16>(
        &self,
        rv_id: RendezvousId,
        resolver_id: u16,
        scope: crate::global::const_dsl::ScopeId,
        resolver_ref: ResolverRef<'cfg, RESOLVER>,
    ) -> Result<(), ClusterError> {
        let key = DynamicResolverKey::new(rv_id, scope);
        if resolver_id != RESOLVER {
            return Err(ClusterError::ResolverReject {
                resolver_id: RESOLVER,
            });
        }
        if scope.is_none() {
            return Err(ClusterError::ResolverReject {
                resolver_id: RESOLVER,
            });
        }
        let entry = DynamicResolverEntry {
            resolver_ref: resolver_ref.erase(),
            resolver_id,
        };
        if self.dynamic_resolver(key).is_none() {
            self.ensure_dynamic_resolver_capacity(rv_id, 1)?;
        }
        self.with_storage_mut(|core| core.locals.insert_dynamic_resolver(key, entry))
    }

    pub(crate) fn resolve_dynamic_resolver(
        &self,
        rv_id: RendezvousId,
        scope: crate::global::const_dsl::ScopeId,
        resolver_id: u16,
    ) -> Result<DecisionArm, ClusterError> {
        let key = DynamicResolverKey::new(rv_id, scope);
        let Some(entry) = self.dynamic_resolver(key) else {
            return Err(ClusterError::DynamicResolverInvariant { resolver_id });
        };
        if entry.resolver_id != resolver_id {
            return Err(ClusterError::DynamicResolverInvariant { resolver_id });
        }

        let arm = entry
            .resolver_ref
            .resolve_decision()
            .map_err(|_| ClusterError::ResolverReject { resolver_id })?;
        Ok(arm)
    }
}