use crate::bedrock::sandbox_construction::ComponentSandbox;
use crate::capability_source::{BuiltinCapabilities, NamespaceCapabilities};
use crate::environment;
use crate::error::ComponentInstanceError;
use crate::policy::GlobalPolicyChecker;
use crate::resolving::{ComponentAddress, ComponentResolutionContext};
use async_trait::async_trait;
use cm_rust::{CapabilityDecl, CollectionDecl, ExposeDecl, OfferDecl, OfferSource, UseDecl};
use cm_types::{Name, Url};
use derivative::Derivative;
use moniker::{ChildName, ExtendedMoniker, Moniker};
use sandbox::{WeakInstanceToken, WeakInstanceTokenAny};
use std::clone::Clone;
use std::sync::{Arc, Weak};
#[async_trait]
pub trait ComponentInstanceInterface: Sized + Send + Sync {
type TopInstance: TopInstanceInterface + Send + Sync;
fn as_weak(self: &Arc<Self>) -> WeakComponentInstanceInterface<Self> {
WeakComponentInstanceInterface::new(self)
}
fn child_moniker(&self) -> Option<&ChildName>;
fn moniker(&self) -> &Moniker;
fn url(&self) -> &Url;
fn environment(&self) -> &environment::Environment<Self>;
fn config_parent_overrides(&self) -> Option<&Vec<cm_rust::ConfigOverride>>;
fn policy_checker(&self) -> &GlobalPolicyChecker;
fn component_id_index(&self) -> &component_id_index::Index;
fn try_get_parent(&self) -> Result<ExtendedInstanceInterface<Self>, ComponentInstanceError>;
async fn lock_resolved_state<'a>(
self: &'a Arc<Self>,
) -> Result<Box<dyn ResolvedInstanceInterface<Component = Self> + 'a>, ComponentInstanceError>;
async fn component_sandbox(
self: &Arc<Self>,
) -> Result<ComponentSandbox, ComponentInstanceError>;
async fn find_extended_instance(
self: &Arc<Self>,
moniker: &ExtendedMoniker,
) -> Result<ExtendedInstanceInterface<Self>, ComponentInstanceError> {
match moniker {
ExtendedMoniker::ComponentInstance(moniker) => {
Ok(ExtendedInstanceInterface::Component(self.find_absolute(moniker).await?))
}
ExtendedMoniker::ComponentManager => {
Ok(ExtendedInstanceInterface::AboveRoot(self.find_above_root()?))
}
}
}
async fn find_absolute(
self: &Arc<Self>,
target_moniker: &Moniker,
) -> Result<Arc<Self>, ComponentInstanceError> {
let mut current = self.clone();
while !target_moniker.has_prefix(current.moniker()) {
match current.try_get_parent()? {
ExtendedInstanceInterface::AboveRoot(_) => panic!(
"the current component ({}) must be root, but it's not a prefix for {}",
current.moniker(),
&target_moniker
),
ExtendedInstanceInterface::Component(parent) => current = parent,
}
}
while current.moniker() != target_moniker {
let remaining_path = target_moniker.strip_prefix(current.moniker()).expect(
"previous loop will only exit when current.moniker() is a prefix of target_moniker",
);
for moniker_part in remaining_path.path().iter() {
let child = current.lock_resolved_state().await?.get_child(moniker_part).ok_or(
ComponentInstanceError::InstanceNotFound {
moniker: current.moniker().child(moniker_part.clone()),
},
)?;
current = child;
}
}
Ok(current)
}
fn find_above_root(self: &Arc<Self>) -> Result<Arc<Self::TopInstance>, ComponentInstanceError> {
let mut current = self.clone();
loop {
match current.try_get_parent()? {
ExtendedInstanceInterface::AboveRoot(top_instance) => return Ok(top_instance),
ExtendedInstanceInterface::Component(parent) => current = parent,
}
}
}
}
pub trait ResolvedInstanceInterface: Send + Sync {
type Component;
fn uses(&self) -> Vec<UseDecl>;
fn exposes(&self) -> Vec<ExposeDecl>;
fn offers(&self) -> Vec<OfferDecl>;
fn capabilities(&self) -> Vec<CapabilityDecl>;
fn collections(&self) -> Vec<CollectionDecl>;
fn get_child(&self, moniker: &ChildName) -> Option<Arc<Self::Component>>;
fn children_in_collection(&self, collection: &Name) -> Vec<(ChildName, Arc<Self::Component>)>;
fn address(&self) -> ComponentAddress;
fn context_to_resolve_children(&self) -> Option<ComponentResolutionContext>;
}
pub trait ResolvedInstanceInterfaceExt: ResolvedInstanceInterface {
fn offer_source_exists(&self, source: &OfferSource) -> bool {
match source {
OfferSource::Framework
| OfferSource::Self_
| OfferSource::Parent
| OfferSource::Void => true,
OfferSource::Child(cm_rust::ChildRef { name, collection }) => {
let child_moniker = match ChildName::try_new(
name.as_str(),
collection.as_ref().map(|c| c.as_str()),
) {
Ok(m) => m,
Err(_) => return false,
};
self.get_child(&child_moniker).is_some()
}
OfferSource::Collection(collection_name) => {
self.collections().into_iter().any(|collection| collection.name == *collection_name)
}
OfferSource::Capability(capability_name) => self
.capabilities()
.into_iter()
.any(|capability| capability.name() == capability_name),
}
}
}
impl<T: ResolvedInstanceInterface> ResolvedInstanceInterfaceExt for T {}
impl<T> ResolvedInstanceInterface for T
where
T: std::ops::Deref + Send + Sync,
T::Target: ResolvedInstanceInterface,
{
type Component = <T::Target as ResolvedInstanceInterface>::Component;
fn uses(&self) -> Vec<UseDecl> {
T::Target::uses(&*self)
}
fn exposes(&self) -> Vec<ExposeDecl> {
T::Target::exposes(&*self)
}
fn offers(&self) -> Vec<cm_rust::OfferDecl> {
T::Target::offers(&*self)
}
fn capabilities(&self) -> Vec<cm_rust::CapabilityDecl> {
T::Target::capabilities(&*self)
}
fn collections(&self) -> Vec<cm_rust::CollectionDecl> {
T::Target::collections(&*self)
}
fn get_child(&self, moniker: &ChildName) -> Option<Arc<Self::Component>> {
T::Target::get_child(&*self, moniker)
}
fn children_in_collection(&self, collection: &Name) -> Vec<(ChildName, Arc<Self::Component>)> {
T::Target::children_in_collection(&*self, collection)
}
fn address(&self) -> ComponentAddress {
T::Target::address(&*self)
}
fn context_to_resolve_children(&self) -> Option<ComponentResolutionContext> {
T::Target::context_to_resolve_children(&*self)
}
}
#[derive(Derivative)]
#[derivative(Clone(bound = ""), Default(bound = ""), Debug)]
pub struct WeakComponentInstanceInterface<C: ComponentInstanceInterface> {
#[derivative(Debug = "ignore")]
inner: Weak<C>,
pub moniker: Moniker,
}
impl<C: ComponentInstanceInterface> WeakComponentInstanceInterface<C> {
pub fn new(component: &Arc<C>) -> Self {
Self { inner: Arc::downgrade(component), moniker: component.moniker().clone() }
}
pub fn invalid() -> Self {
Self { inner: Weak::new(), moniker: Moniker::new(vec![]) }
}
pub fn upgrade(&self) -> Result<Arc<C>, ComponentInstanceError> {
self.inner
.upgrade()
.ok_or_else(|| ComponentInstanceError::instance_not_found(self.moniker.clone()))
}
}
impl<C: ComponentInstanceInterface> From<&Arc<C>> for WeakComponentInstanceInterface<C> {
fn from(component: &Arc<C>) -> Self {
Self { inner: Arc::downgrade(component), moniker: component.moniker().clone() }
}
}
impl<C: ComponentInstanceInterface + 'static> TryFrom<WeakInstanceToken>
for WeakComponentInstanceInterface<C>
{
type Error = ();
fn try_from(
weak_component_token: WeakInstanceToken,
) -> Result<WeakComponentInstanceInterface<C>, Self::Error> {
let weak_extended: WeakExtendedInstanceInterface<C> = weak_component_token.try_into()?;
match weak_extended {
WeakExtendedInstanceInterface::Component(weak_component) => Ok(weak_component),
WeakExtendedInstanceInterface::AboveRoot(_) => Err(()),
}
}
}
impl<C: ComponentInstanceInterface + 'static> PartialEq for WeakComponentInstanceInterface<C> {
fn eq(&self, other: &Self) -> bool {
self.inner.ptr_eq(&other.inner) && self.moniker == other.moniker
}
}
#[derive(Debug, Clone)]
pub enum ExtendedInstanceInterface<C: ComponentInstanceInterface> {
Component(Arc<C>),
AboveRoot(Arc<C::TopInstance>),
}
#[derive(Derivative)]
#[derivative(Clone(bound = ""), Debug(bound = ""))]
pub enum WeakExtendedInstanceInterface<C: ComponentInstanceInterface> {
Component(WeakComponentInstanceInterface<C>),
AboveRoot(Weak<C::TopInstance>),
}
impl<C: ComponentInstanceInterface + 'static> WeakInstanceTokenAny
for WeakExtendedInstanceInterface<C>
{
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl<C: ComponentInstanceInterface> WeakExtendedInstanceInterface<C> {
pub fn upgrade(&self) -> Result<ExtendedInstanceInterface<C>, ComponentInstanceError> {
match self {
WeakExtendedInstanceInterface::Component(p) => {
Ok(ExtendedInstanceInterface::Component(p.upgrade()?))
}
WeakExtendedInstanceInterface::AboveRoot(p) => {
Ok(ExtendedInstanceInterface::AboveRoot(
p.upgrade().ok_or_else(ComponentInstanceError::cm_instance_unavailable)?,
))
}
}
}
pub fn extended_moniker(&self) -> ExtendedMoniker {
match self {
Self::Component(p) => ExtendedMoniker::ComponentInstance(p.moniker.clone()),
Self::AboveRoot(_) => ExtendedMoniker::ComponentManager,
}
}
}
impl<C: ComponentInstanceInterface> From<&ExtendedInstanceInterface<C>>
for WeakExtendedInstanceInterface<C>
{
fn from(extended: &ExtendedInstanceInterface<C>) -> Self {
match extended {
ExtendedInstanceInterface::Component(component) => {
WeakExtendedInstanceInterface::Component(WeakComponentInstanceInterface::new(
component,
))
}
ExtendedInstanceInterface::AboveRoot(top_instance) => {
WeakExtendedInstanceInterface::AboveRoot(Arc::downgrade(top_instance))
}
}
}
}
impl<C: ComponentInstanceInterface + 'static> TryFrom<WeakInstanceToken>
for WeakExtendedInstanceInterface<C>
{
type Error = ();
fn try_from(
weak_component_token: WeakInstanceToken,
) -> Result<WeakExtendedInstanceInterface<C>, Self::Error> {
weak_component_token
.inner
.as_any()
.downcast_ref::<WeakExtendedInstanceInterface<C>>()
.cloned()
.ok_or(())
}
}
pub trait TopInstanceInterface: Sized + std::fmt::Debug {
fn namespace_capabilities(&self) -> &NamespaceCapabilities;
fn builtin_capabilities(&self) -> &BuiltinCapabilities;
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::bedrock::sandbox_construction::ComponentSandbox;
#[derive(Debug)]
pub struct TestTopInstance {}
impl TopInstanceInterface for TestTopInstance {
fn namespace_capabilities(&self) -> &NamespaceCapabilities {
todo!()
}
fn builtin_capabilities(&self) -> &BuiltinCapabilities {
todo!()
}
}
pub struct TestComponent {}
#[async_trait]
impl ComponentInstanceInterface for TestComponent {
type TopInstance = TestTopInstance;
fn child_moniker(&self) -> Option<&ChildName> {
todo!()
}
fn moniker(&self) -> &Moniker {
todo!()
}
fn url(&self) -> &Url {
todo!()
}
fn environment(&self) -> &crate::environment::Environment<Self> {
todo!()
}
fn config_parent_overrides(&self) -> Option<&Vec<cm_rust::ConfigOverride>> {
todo!()
}
fn policy_checker(&self) -> &GlobalPolicyChecker {
todo!()
}
fn component_id_index(&self) -> &component_id_index::Index {
todo!()
}
fn try_get_parent(
&self,
) -> Result<ExtendedInstanceInterface<Self>, ComponentInstanceError> {
todo!()
}
async fn lock_resolved_state<'a>(
self: &'a Arc<Self>,
) -> Result<Box<dyn ResolvedInstanceInterface<Component = Self> + 'a>, ComponentInstanceError>
{
todo!()
}
async fn component_sandbox(
self: &Arc<Self>,
) -> Result<ComponentSandbox, ComponentInstanceError> {
todo!()
}
}
}