use appcore_core::{CapabilityDescriptor, CoreId};
use appcore_distributed_contracts::PeerRecord;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CapabilityProvider {
Local {
core_id: CoreId,
descriptor: CapabilityDescriptor,
},
Remote {
peer: Box<PeerRecord>,
descriptor: CapabilityDescriptor,
preferred: bool,
},
}
impl CapabilityProvider {
pub fn descriptor(&self) -> &CapabilityDescriptor {
match self {
Self::Local { descriptor, .. } | Self::Remote { descriptor, .. } => descriptor,
}
}
pub fn core_id(&self) -> &CoreId {
match self {
Self::Local { core_id, .. } => core_id,
Self::Remote { peer, .. } => &peer.identity.core_id,
}
}
pub fn is_remote(&self) -> bool {
matches!(self, Self::Remote { .. })
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ResolutionPolicy {
pub prefer_local: bool,
pub allow_remote: bool,
}
impl Default for ResolutionPolicy {
fn default() -> Self {
Self {
prefer_local: true,
allow_remote: true,
}
}
}
pub trait CapabilitySelectionPolicy: Send + Sync {
fn select(&self, candidates: &[CapabilityProvider]) -> Option<CapabilityProvider>;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DefaultCapabilitySelectionPolicy {
pub policy: ResolutionPolicy,
}
impl CapabilitySelectionPolicy for DefaultCapabilitySelectionPolicy {
fn select(&self, candidates: &[CapabilityProvider]) -> Option<CapabilityProvider> {
if self.policy.prefer_local {
if let Some(local) = candidates
.iter()
.find(|candidate| matches!(candidate, CapabilityProvider::Local { .. }))
{
return Some(local.clone());
}
}
if self.policy.allow_remote {
if let Some(remote) = candidates.iter().find(|candidate| {
matches!(
candidate,
CapabilityProvider::Remote {
preferred: true,
..
}
)
}) {
return Some(remote.clone());
}
if let Some(remote) = candidates
.iter()
.find(|candidate| matches!(candidate, CapabilityProvider::Remote { .. }))
{
return Some(remote.clone());
}
}
candidates
.iter()
.find(|candidate| matches!(candidate, CapabilityProvider::Local { .. }))
.cloned()
}
}