saluki_core/components/
build_context.rs

1//! Context provided to component builders.
2
3use std::fmt;
4
5use super::{ComponentContext, ComponentType};
6use crate::{
7    runtime::state::{AcquireError, ResourceLease, ResourceRegistry, ResourceSpecification},
8    support::SubsystemIdentifier,
9    topology::ComponentId,
10};
11
12/// Build-time component context.
13///
14/// Carries information about the component being built, as well as access to the resource registry in order to acquire
15/// external resources if necessary.
16#[derive(Clone)]
17pub struct BuildContext {
18    component_context: ComponentContext,
19    resource_registry: ResourceRegistry,
20}
21
22impl BuildContext {
23    /// Creates a new `BuildContext` for the given component.
24    pub fn new(component_context: ComponentContext, resource_registry: ResourceRegistry) -> Self {
25        Self {
26            component_context,
27            resource_registry,
28        }
29    }
30
31    /// Returns the context of the component being built.
32    pub fn component_context(&self) -> &ComponentContext {
33        &self.component_context
34    }
35
36    /// Returns the component identifier.
37    ///
38    /// This is the relative identifier of the component, unique within its topology but not guaranteed to be globally
39    /// unique. See [`BuildContext::identity`] for the fully qualified identity.
40    pub fn component_id(&self) -> &ComponentId {
41        self.component_context.component_id()
42    }
43
44    /// Returns the component type.
45    pub fn component_type(&self) -> ComponentType {
46        self.component_context.component_type()
47    }
48
49    /// Returns the fully qualified identity of this component.
50    ///
51    /// The returned identifier uniquely identifies the component within the process, inclusive of the topology to
52    /// which it belongs.
53    pub fn identity(&self) -> SubsystemIdentifier {
54        self.component_context.identity()
55    }
56
57    /// Acquires a resource on behalf of the component being built.
58    ///
59    /// # Errors
60    ///
61    /// If the resource is already held elsewhere in the process, or can't be created, an error is returned.
62    pub async fn acquire_resource<S: ResourceSpecification>(
63        &self, spec: S,
64    ) -> Result<ResourceLease<S::Resource>, AcquireError> {
65        self.resource_registry.acquire(&self.identity(), spec).await
66    }
67}
68
69impl fmt::Display for BuildContext {
70    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71        write!(f, "{}", self.component_context)
72    }
73}
74
75macro_rules! test_build_contexts {
76    ($($name:ident => $component_context:ident, $doc:literal;)*) => {
77        $(
78            #[doc = $doc]
79            ///
80            /// The returned context carries its own empty [`ResourceRegistry`], so resources acquired through it are
81            /// isolated to this context.
82            #[cfg(any(test, feature = "test-util"))]
83            pub fn $name<S: AsRef<str>>(component_id: S) -> Self {
84                Self::new(ComponentContext::$component_context(component_id), ResourceRegistry::new())
85            }
86        )*
87    };
88}
89
90impl BuildContext {
91    test_build_contexts! {
92        test_source => test_source, "Creates a new `BuildContext` for a source component with the given identifier, in a test topology.";
93        test_relay => test_relay, "Creates a new `BuildContext` for a relay component with the given identifier, in a test topology.";
94        test_decoder => test_decoder, "Creates a new `BuildContext` for a decoder component with the given identifier, in a test topology.";
95        test_transform => test_transform, "Creates a new `BuildContext` for a transform component with the given identifier, in a test topology.";
96        test_encoder => test_encoder, "Creates a new `BuildContext` for an encoder component with the given identifier, in a test topology.";
97        test_forwarder => test_forwarder, "Creates a new `BuildContext` for a forwarder component with the given identifier, in a test topology.";
98        test_destination => test_destination, "Creates a new `BuildContext` for a destination component with the given identifier, in a test topology.";
99    }
100}