blob: fc56ebdc71d4ae7812e2a60faf486c6be18c3847 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::{
capability_source::{BuiltinCapabilities, NamespaceCapabilities},
environment,
error::ComponentInstanceError,
policy::GlobalPolicyChecker,
resolving::{ComponentAddress, ComponentResolutionContext},
},
async_trait::async_trait,
cm_moniker::InstancedMoniker,
cm_rust::{CapabilityDecl, CollectionDecl, ExposeDecl, OfferDecl, OfferSource, UseDecl},
cm_types::{Name, Url},
derivative::Derivative,
moniker::{ChildName, ExtendedMoniker, Moniker, MonikerBase},
std::{
clone::Clone,
sync::{Arc, Weak},
},
};
/// A trait providing a representation of a component instance.
#[async_trait]
pub trait ComponentInstanceInterface: Sized + Send + Sync {
type TopInstance: TopInstanceInterface + Send + Sync;
/// Returns a new `WeakComponentInstanceInterface<Self>` pointing to `self`.
fn as_weak(self: &Arc<Self>) -> WeakComponentInstanceInterface<Self> {
WeakComponentInstanceInterface::new(self)
}
/// Returns this `ComponentInstanceInterface`'s child moniker, if it is
/// not the root instance.
fn child_moniker(&self) -> Option<&ChildName>;
/// Returns this `ComponentInstanceInterface`'s instanced moniker
fn instanced_moniker(&self) -> &InstancedMoniker;
/// Returns this `ComponentInstanceInterface`'s moniker.
fn moniker(&self) -> &Moniker;
/// Returns this `ComponentInstanceInterface`'s component URL.
fn url(&self) -> &Url;
/// Returns a representation of this `ComponentInstanceInterface`'s environment.
fn environment(&self) -> &environment::Environment<Self>;
/// Returns configuration overrides applied to this component by its parent.
fn config_parent_overrides(&self) -> Option<&Vec<cm_rust::ConfigOverride>>;
/// Returns the `GlobalPolicyChecker` for this component instance.
fn policy_checker(&self) -> &GlobalPolicyChecker;
/// Returns the component ID index for this component instance.
fn component_id_index(&self) -> &component_id_index::Index;
/// Gets the parent, if it still exists, or returns an `InstanceNotFound` error.
fn try_get_parent(&self) -> Result<ExtendedInstanceInterface<Self>, ComponentInstanceError>;
/// Locks and returns a lazily-resolved and populated
/// `ResolvedInstanceInterface`. Returns an `InstanceNotFound` error if the
/// instance is destroyed. The instance will remain locked until the result
/// is dropped.
///
/// NOTE: The `Box<dyn>` in the return type is necessary, because the type
/// of the result depends on the lifetime of the `self` reference. The
/// proposed "generic associated types" feature would let us define this
/// statically.
async fn lock_resolved_state<'a>(
self: &'a Arc<Self>,
) -> Result<Box<dyn ResolvedInstanceInterface<Component = Self> + 'a>, ComponentInstanceError>;
}
/// A trait providing a representation of a resolved component instance.
pub trait ResolvedInstanceInterface: Send + Sync {
/// Type representing a (unlocked and potentially unresolved) component instance.
type Component;
/// Current view of this component's `uses` declarations.
fn uses(&self) -> Vec<UseDecl>;
/// Current view of this component's `exposes` declarations.
fn exposes(&self) -> Vec<ExposeDecl>;
/// Current view of this component's `offers` declarations.
fn offers(&self) -> Vec<OfferDecl>;
/// Current view of this component's `capabilities` declarations.
fn capabilities(&self) -> Vec<CapabilityDecl>;
/// Current view of this component's `collections` declarations.
fn collections(&self) -> Vec<CollectionDecl>;
/// Returns a live child of this instance.
fn get_child(&self, moniker: &ChildName) -> Option<Arc<Self::Component>>;
/// Returns a vector of the live children in `collection`.
fn children_in_collection(&self, collection: &Name) -> Vec<(ChildName, Arc<Self::Component>)>;
/// Returns the resolver-ready location of the component, which is either
/// an absolute component URL or a relative path URL with context.
fn address(&self) -> ComponentAddress;
/// Returns the context to be used to resolve a component from a path
/// relative to this component (for example, a component in a subpackage).
/// If `None`, the resolver cannot resolve relative path component URLs.
fn context_to_resolve_children(&self) -> Option<ComponentResolutionContext>;
}
/// An extension trait providing functionality for any model of a resolved
/// component.
pub trait ResolvedInstanceInterfaceExt: ResolvedInstanceInterface {
/// Returns true if the given offer source refers to a valid entity, e.g., a
/// child that exists, a declared collection, etc.
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 {}
// Elsewhere we need to implement `ResolvedInstanceInterface` for `&T` and
// `MappedMutexGuard<_, _, T>`, where `T : ResolvedComponentInstance`. We can't
// implement the latter outside of this crate because of the "orphan rule". So
// here we implement it for all `Deref`s.
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)
}
}
/// A wrapper for a weak reference to a type implementing `ComponentInstanceInterface`. Provides the
/// moniker of the component instance, which is useful for error reporting if the original
/// component instance has been destroyed.
#[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() }
}
/// Returns a new weak component instance that will always fail to upgrade.
pub fn invalid() -> Self {
Self { inner: Weak::new(), moniker: Moniker::new(vec![]) }
}
/// Attempts to upgrade this `WeakComponentInterface<C>` into an `Arc<C>`, if the
/// original component instance interface `C` has not been destroyed.
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() }
}
}
/// Either a type implementing `ComponentInstanceInterface` or its `TopInstance`.
#[derive(Debug, Clone)]
pub enum ExtendedInstanceInterface<C: ComponentInstanceInterface> {
Component(Arc<C>),
AboveRoot(Arc<C::TopInstance>),
}
/// A type implementing `ComponentInstanceInterface` or its `TopInstance`, as a weak pointer.
#[derive(Derivative)]
#[derivative(Clone(bound = ""), Debug(bound = ""))]
pub enum WeakExtendedInstanceInterface<C: ComponentInstanceInterface> {
Component(WeakComponentInstanceInterface<C>),
AboveRoot(Weak<C::TopInstance>),
}
impl<C: ComponentInstanceInterface> WeakExtendedInstanceInterface<C> {
/// Attempts to upgrade this `WeakExtendedInstanceInterface<C>` into an
/// `ExtendedInstanceInterface<C>`, if the original extended instance has not been destroyed.
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(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))
}
}
}
}
/// A special instance identified with the top of the tree, i.e. component manager's instance.
pub trait TopInstanceInterface: Sized + std::fmt::Debug {
fn namespace_capabilities(&self) -> &NamespaceCapabilities;
fn builtin_capabilities(&self) -> &BuiltinCapabilities;
}
#[cfg(test)]
pub mod tests {
use super::*;
#[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 instanced_moniker(&self) -> &InstancedMoniker {
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!()
}
}
}