wasmcloud_control_interface/types/
link.rs

1//! Data types and structure used when managing links on a wasmCloud lattice
2
3use serde::{Deserialize, Serialize};
4
5/// A link definition between a source and target component (component or provider) on a given
6/// interface.
7///
8/// An [`Link`] connects one component's import to another
9/// component's export, specifying the configuration each component needs in order to execute
10/// the request, and represents an operator's intent to allow the source to invoke the target.
11///
12/// This link definition is *distinct* from the one in `wasmcloud_core`, in that it is
13/// represents a link at the point in time *before* it's configuration is fully resolved
14#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize, Hash)]
15#[non_exhaustive]
16pub struct Link {
17    /// Source identifier for the link
18    pub(crate) source_id: String,
19    /// Target for the link, which can be a unique identifier or (future) a routing group
20    pub(crate) target: String,
21    /// Name of the link. Not providing this is equivalent to specifying "default"
22    #[serde(default = "default_link_name")]
23    pub(crate) name: String,
24    /// WIT namespace of the link operation, e.g. `wasi` in `wasi:keyvalue/readwrite.get`
25    pub(crate) wit_namespace: String,
26    /// WIT package of the link operation, e.g. `keyvalue` in `wasi:keyvalue/readwrite.get`
27    pub(crate) wit_package: String,
28    /// WIT Interfaces to be used for the link, e.g. `readwrite`, `atomic`, etc.
29    pub(crate) interfaces: Vec<String>,
30    /// List of named configurations to provide to the source upon request
31    #[serde(default)]
32    pub(crate) source_config: Vec<String>,
33    /// List of named configurations to provide to the target upon request
34    #[serde(default)]
35    pub(crate) target_config: Vec<String>,
36}
37
38impl Link {
39    #[must_use]
40    pub fn source_id(&self) -> &str {
41        &self.source_id
42    }
43
44    #[must_use]
45    pub fn target(&self) -> &str {
46        &self.target
47    }
48
49    #[must_use]
50    pub fn name(&self) -> &str {
51        &self.name
52    }
53
54    #[must_use]
55    pub fn wit_namespace(&self) -> &str {
56        &self.wit_namespace
57    }
58
59    #[must_use]
60    pub fn wit_package(&self) -> &str {
61        &self.wit_package
62    }
63
64    #[must_use]
65    pub fn interfaces(&self) -> &Vec<String> {
66        &self.interfaces
67    }
68
69    #[must_use]
70    pub fn source_config(&self) -> &Vec<String> {
71        &self.source_config
72    }
73
74    #[must_use]
75    pub fn target_config(&self) -> &Vec<String> {
76        &self.target_config
77    }
78
79    #[must_use]
80    pub fn builder() -> LinkBuilder {
81        LinkBuilder::default()
82    }
83}
84
85/// Builder that produces [`Link`]s
86#[derive(Clone, Debug, Default, Eq, PartialEq)]
87#[non_exhaustive]
88pub struct LinkBuilder {
89    source_id: Option<String>,
90    target: Option<String>,
91    name: Option<String>,
92    wit_namespace: Option<String>,
93    wit_package: Option<String>,
94    interfaces: Option<Vec<String>>,
95    source_config: Option<Vec<String>>,
96    target_config: Option<Vec<String>>,
97}
98
99impl LinkBuilder {
100    #[must_use]
101    pub fn source_id(mut self, v: &str) -> Self {
102        self.source_id = Some(v.into());
103        self
104    }
105
106    #[must_use]
107    pub fn target(mut self, v: &str) -> Self {
108        self.target = Some(v.into());
109        self
110    }
111
112    #[must_use]
113    pub fn name(mut self, v: &str) -> Self {
114        self.name = Some(v.into());
115        self
116    }
117
118    #[must_use]
119    pub fn wit_namespace(mut self, v: &str) -> Self {
120        self.wit_namespace = Some(v.into());
121        self
122    }
123
124    #[must_use]
125    pub fn wit_package(mut self, v: &str) -> Self {
126        self.wit_package = Some(v.into());
127        self
128    }
129
130    #[must_use]
131    pub fn interfaces(mut self, v: Vec<String>) -> Self {
132        self.interfaces = Some(v);
133        self
134    }
135
136    #[must_use]
137    pub fn source_config(mut self, v: Vec<String>) -> Self {
138        self.source_config = Some(v);
139        self
140    }
141
142    #[must_use]
143    pub fn target_config(mut self, v: Vec<String>) -> Self {
144        self.target_config = Some(v);
145        self
146    }
147
148    pub fn build(self) -> crate::Result<Link> {
149        Ok(Link {
150            source_id: self
151                .source_id
152                .ok_or_else(|| "source id is required for creating links".to_string())?,
153            target: self
154                .target
155                .ok_or_else(|| "target is required for creating links".to_string())?,
156            name: self
157                .name
158                .ok_or_else(|| "name is required for creating links".to_string())?,
159            wit_namespace: self
160                .wit_namespace
161                .ok_or_else(|| "WIT namespace is required for creating links".to_string())?,
162            wit_package: self
163                .wit_package
164                .ok_or_else(|| "WIT package is required for creating links".to_string())?,
165            interfaces: self.interfaces.unwrap_or_default(),
166            source_config: self.source_config.unwrap_or_default(),
167            target_config: self.target_config.unwrap_or_default(),
168        })
169    }
170}
171
172/// Helper function to provide a default link name
173pub(crate) fn default_link_name() -> String {
174    "default".to_string()
175}
176
177#[cfg(test)]
178mod tests {
179
180    use super::Link;
181
182    #[test]
183    fn link_builder() {
184        assert_eq!(
185            Link {
186                source_id: "source_id".into(),
187                target: "target".into(),
188                name: "name".into(),
189                wit_namespace: "wit_namespace".into(),
190                wit_package: "wit_package".into(),
191                interfaces: vec!["i".into()],
192                source_config: vec!["sc".into()],
193                target_config: vec!["tc".into()]
194            },
195            Link::builder()
196                .source_id("source_id")
197                .target("target")
198                .name("name")
199                .wit_namespace("wit_namespace")
200                .wit_package("wit_package")
201                .interfaces(vec!["i".into()])
202                .source_config(vec!["sc".into()])
203                .target_config(vec!["tc".into()])
204                .build()
205                .unwrap()
206        );
207    }
208}