Skip to main content

lenso_capability_http_endpoint/
generated.rs

1// @generated by lenso-contract-codegen; do not edit.
2use std::{fmt, rc::Rc};
3use futures::future::LocalBoxFuture;
4use lenso_kernel::{InvocationContext, NativeRequestEndpoint, NativeRequestFuture, NativeRequestHandle, PluginDependencies, RequestCapability, RuntimeFailure};
5
6use lenso_plugin_authoring::{BoundCapabilityClient, CapabilityClient, CapabilityClientMany};
7pub const CAPABILITY_ID: &str = "lenso.http.endpoint@1";
8pub const DESCRIPTOR_VERSION: &str = "1.1.0";
9pub const PORTABLE: bool = true;
10pub const CROSS_LANE_TRANSFER: bool = true;
11pub const ENDPOINT_CAPABILITY_ID: &str = CAPABILITY_ID;
12pub const ENDPOINT_DESCRIPTOR_VERSION: &str = DESCRIPTOR_VERSION;
13
14#[doc(hidden)]
15#[macro_export]
16macro_rules! __lenso_provided_endpoint { () => { "{\"capability_id\":\"lenso.http.endpoint@1\",\"descriptor_version\":\"1.1.0\",\"operations\":[\"describe\",\"handle\"],\"operation_kinds\":{},\"default_admission\":{\"queue_capacity\":0,\"max_concurrency\":1},\"operation_admissions\":{},\"event_admission\":null,\"cross_lane_transfer\":true}" }; }
17
18#[doc(hidden)]
19#[macro_export]
20macro_rules! __lenso_required_endpoint_client { () => { "{\"capability_id\":\"lenso.http.endpoint@1\",\"descriptor_version\":\"1.1.0\",\"cardinality\":\"one\"}" }; }
21
22#[doc(hidden)]
23#[macro_export]
24macro_rules! __lenso_required_many_endpoint_client { () => { "{\"capability_id\":\"lenso.http.endpoint@1\",\"descriptor_version\":\"1.1.0\",\"cardinality\":\"many\"}" }; }
25
26pub const DESCRIBE_OPERATION: &str = "describe";
27pub const HANDLE_OPERATION: &str = "handle";
28
29pub use lenso_contract_runtime::{Bytes, UnknownDomainError};
30use lenso_contract_runtime::{decode_portable_json, encode_portable_json};
31
32#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
33pub struct DescribeRequest {
34
35}
36
37#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
38pub struct DescribeResponse {
39    #[serde(rename = "routes")]
40    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
41    pub routes: Vec<DescribeResponseRoutesItem>,
42}
43
44#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
45pub struct DescribeResponseRoutesItem {
46    #[serde(rename = "method")]
47    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
48    pub method: String,
49    #[serde(rename = "openapi")]
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub openapi: Option<std::collections::BTreeMap<String, serde_json::Value>>,
52    #[serde(rename = "path")]
53    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
54    pub path: String,
55    #[serde(rename = "route_id")]
56    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
57    pub route_id: String,
58}
59
60#[derive(Clone, Debug, PartialEq)]
61pub enum DescribeError {
62    InvalidConfiguration,
63    Unknown(UnknownDomainError),
64}
65
66#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
67pub struct HandleRequest {
68    #[serde(rename = "body")]
69    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
70    pub body: Bytes,
71    #[serde(rename = "credential")]
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub credential: Option<HandleRequestCredential>,
74    #[serde(rename = "headers")]
75    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
76    pub headers: Vec<HandleRequestHeadersItem>,
77    #[serde(rename = "method")]
78    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
79    pub method: String,
80    #[serde(rename = "path")]
81    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
82    pub path: String,
83    #[serde(rename = "path_parameters")]
84    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
85    pub path_parameters: Vec<HandleRequestPathParametersItem>,
86    #[serde(rename = "query")]
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub query: Option<String>,
89    #[serde(rename = "request_id")]
90    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
91    pub request_id: String,
92    #[serde(rename = "route_id")]
93    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
94    pub route_id: String,
95}
96
97#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
98pub struct HandleRequestCredential {
99    #[serde(rename = "scheme")]
100    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
101    pub scheme: String,
102    #[serde(rename = "value")]
103    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
104    pub value: String,
105}
106
107#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
108pub struct HandleRequestHeadersItem {
109    #[serde(rename = "name")]
110    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
111    pub name: String,
112    #[serde(rename = "value")]
113    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
114    pub value: String,
115}
116
117#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
118pub struct HandleRequestPathParametersItem {
119    #[serde(rename = "name")]
120    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
121    pub name: String,
122    #[serde(rename = "value")]
123    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
124    pub value: String,
125}
126
127#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
128pub struct HandleResponse {
129    #[serde(rename = "body")]
130    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
131    pub body: Bytes,
132    #[serde(rename = "headers")]
133    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
134    pub headers: Vec<HandleResponseHeadersItem>,
135    #[serde(rename = "status")]
136    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
137    pub status: i64,
138}
139
140#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
141pub struct HandleResponseHeadersItem {
142    #[serde(rename = "name")]
143    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
144    pub name: String,
145    #[serde(rename = "value")]
146    #[serde(deserialize_with = "lenso_contract_runtime::serde::deserialize_required")]
147    pub value: String,
148}
149
150#[derive(Clone, Debug, PartialEq)]
151pub enum HandleError {
152    Rejected,
153    Unknown(UnknownDomainError),
154}
155
156#[derive(Debug)]
157pub struct EndpointDescribe;
158impl RequestCapability for EndpointDescribe {
159    type Request = DescribeRequest;
160    type Response = DescribeResponse;
161    type DomainError = DescribeError;
162    const ID: &'static str = CAPABILITY_ID;
163    const DESCRIPTOR_VERSION: &'static str = DESCRIPTOR_VERSION;
164
165    fn invoke_native(endpoint: &dyn NativeRequestEndpoint, operation: &str, request: Self::Request, context: InvocationContext) -> NativeRequestFuture<Self> {
166        if operation != DESCRIBE_OPERATION {
167            return lenso_kernel::invoke_typed_or_erased_native_request::<Self>(endpoint, operation, request, context);
168        }
169        let Some(typed_endpoint) = endpoint
170            .typed_endpoint()
171            .and_then(|endpoint| endpoint.downcast_ref::<EndpointRequestEndpoint>())
172        else {
173            return lenso_kernel::invoke_typed_or_erased_native_request::<Self>(endpoint, operation, request, context);
174        };
175        Rc::clone(&typed_endpoint.provider).describe(context, request)
176    }
177}
178
179#[derive(Debug)]
180pub struct EndpointHandle;
181impl RequestCapability for EndpointHandle {
182    type Request = HandleRequest;
183    type Response = HandleResponse;
184    type DomainError = HandleError;
185    const ID: &'static str = CAPABILITY_ID;
186    const DESCRIPTOR_VERSION: &'static str = DESCRIPTOR_VERSION;
187
188    fn invoke_native(endpoint: &dyn NativeRequestEndpoint, operation: &str, request: Self::Request, context: InvocationContext) -> NativeRequestFuture<Self> {
189        if operation != HANDLE_OPERATION {
190            return lenso_kernel::invoke_typed_or_erased_native_request::<Self>(endpoint, operation, request, context);
191        }
192        let Some(typed_endpoint) = endpoint
193            .typed_endpoint()
194            .and_then(|endpoint| endpoint.downcast_ref::<EndpointRequestEndpoint>())
195        else {
196            return lenso_kernel::invoke_typed_or_erased_native_request::<Self>(endpoint, operation, request, context);
197        };
198        Rc::clone(&typed_endpoint.provider).handle(context, request)
199    }
200}
201
202impl serde::Serialize for DescribeError {
203    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
204    where
205        S: serde::Serializer,
206    {
207        use serde::ser::SerializeMap;
208        match self {
209            Self::InvalidConfiguration => serializer.serialize_str("invalid_configuration"),
210            Self::Unknown(value) => {
211                let mut map = serializer.serialize_map(Some(1 + usize::from(value.payload.is_some()) + value.extra.len()))?;
212                map.serialize_entry("code", &value.code)?;
213                if let Some(payload) = &value.payload {
214                    map.serialize_entry("payload", payload)?;
215                }
216                for (key, extra) in &value.extra {
217                    map.serialize_entry(key, extra)?;
218                }
219                map.end()
220            },
221        }
222    }
223}
224
225impl<'de> serde::Deserialize<'de> for DescribeError {
226    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
227    where
228        D: serde::Deserializer<'de>,
229    {
230        let value = <serde_json::Value as serde::Deserialize>::deserialize(deserializer)?;
231        match value {
232            serde_json::Value::String(code) => match code.as_str() {
233                "invalid_configuration" => Ok(Self::InvalidConfiguration),
234                _ => Ok(Self::Unknown(UnknownDomainError { code, payload: None, extra: std::collections::BTreeMap::new() })),
235            },
236            serde_json::Value::Object(mut object) => {
237                let Some(code) = object.remove("code").and_then(|value| value.as_str().map(ToOwned::to_owned)) else {
238                    return Err(serde::de::Error::custom("Domain Error object is missing a string code"));
239                };
240                let payload = object.remove("payload");
241                let extra = object.into_iter().collect::<std::collections::BTreeMap<_, _>>();
242                Ok(Self::Unknown(UnknownDomainError { code, payload, extra }))
243            }
244            other => Err(serde::de::Error::custom(format!("Domain Error must be a string or object, got {other}"))),
245        }
246    }
247}
248
249impl serde::Serialize for HandleError {
250    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
251    where
252        S: serde::Serializer,
253    {
254        use serde::ser::SerializeMap;
255        match self {
256            Self::Rejected => serializer.serialize_str("rejected"),
257            Self::Unknown(value) => {
258                let mut map = serializer.serialize_map(Some(1 + usize::from(value.payload.is_some()) + value.extra.len()))?;
259                map.serialize_entry("code", &value.code)?;
260                if let Some(payload) = &value.payload {
261                    map.serialize_entry("payload", payload)?;
262                }
263                for (key, extra) in &value.extra {
264                    map.serialize_entry(key, extra)?;
265                }
266                map.end()
267            },
268        }
269    }
270}
271
272impl<'de> serde::Deserialize<'de> for HandleError {
273    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
274    where
275        D: serde::Deserializer<'de>,
276    {
277        let value = <serde_json::Value as serde::Deserialize>::deserialize(deserializer)?;
278        match value {
279            serde_json::Value::String(code) => match code.as_str() {
280                "rejected" => Ok(Self::Rejected),
281                _ => Ok(Self::Unknown(UnknownDomainError { code, payload: None, extra: std::collections::BTreeMap::new() })),
282            },
283            serde_json::Value::Object(mut object) => {
284                let Some(code) = object.remove("code").and_then(|value| value.as_str().map(ToOwned::to_owned)) else {
285                    return Err(serde::de::Error::custom("Domain Error object is missing a string code"));
286                };
287                let payload = object.remove("payload");
288                let extra = object.into_iter().collect::<std::collections::BTreeMap<_, _>>();
289                Ok(Self::Unknown(UnknownDomainError { code, payload, extra }))
290            }
291            other => Err(serde::de::Error::custom(format!("Domain Error must be a string or object, got {other}"))),
292        }
293    }
294}
295
296pub fn encode_describe_request(value: &DescribeRequest) -> Result<String, serde_json::Error> { encode_portable_json(value) }
297pub fn decode_describe_request(wire: &str) -> Result<DescribeRequest, serde_json::Error> { decode_portable_json(wire) }
298pub fn encode_describe_response(value: &DescribeResponse) -> Result<String, serde_json::Error> { encode_portable_json(value) }
299pub fn decode_describe_response(wire: &str) -> Result<DescribeResponse, serde_json::Error> { decode_portable_json(wire) }
300pub fn encode_describe_error(value: &DescribeError) -> Result<String, serde_json::Error> { encode_portable_json(value) }
301pub fn decode_describe_error(wire: &str) -> Result<DescribeError, serde_json::Error> { decode_portable_json(wire) }
302
303pub fn encode_handle_request(value: &HandleRequest) -> Result<String, serde_json::Error> { encode_portable_json(value) }
304pub fn decode_handle_request(wire: &str) -> Result<HandleRequest, serde_json::Error> { decode_portable_json(wire) }
305pub fn encode_handle_response(value: &HandleResponse) -> Result<String, serde_json::Error> { encode_portable_json(value) }
306pub fn decode_handle_response(wire: &str) -> Result<HandleResponse, serde_json::Error> { decode_portable_json(wire) }
307pub fn encode_handle_error(value: &HandleError) -> Result<String, serde_json::Error> { encode_portable_json(value) }
308pub fn decode_handle_error(wire: &str) -> Result<HandleError, serde_json::Error> { decode_portable_json(wire) }
309
310#[doc(hidden)]
311pub trait __LensoIntoEndpointDescribeResult {
312    fn __lenso_into_result(self) -> Result<Result<DescribeResponse, DescribeError>, RuntimeFailure>;
313}
314impl __LensoIntoEndpointDescribeResult for Result<DescribeResponse, DescribeError> {
315    fn __lenso_into_result(self) -> Result<Result<DescribeResponse, DescribeError>, RuntimeFailure> { Ok(self) }
316}
317impl __LensoIntoEndpointDescribeResult for Result<Result<DescribeResponse, DescribeError>, RuntimeFailure> {
318    fn __lenso_into_result(self) -> Result<Result<DescribeResponse, DescribeError>, RuntimeFailure> { self }
319}
320impl __LensoIntoEndpointDescribeResult for Result<DescribeResponse, lenso_plugin_authoring::PluginError<DescribeError, RuntimeFailure>> {
321    fn __lenso_into_result(self) -> Result<Result<DescribeResponse, DescribeError>, RuntimeFailure> {
322        match self {
323            Ok(value) => Ok(Ok(value)),
324            Err(lenso_plugin_authoring::PluginError::Domain(error)) => Ok(Err(error)),
325            Err(lenso_plugin_authoring::PluginError::Runtime(error)) => Err(error),
326        }
327    }
328}
329impl __LensoIntoEndpointDescribeResult for Result<DescribeResponse, EndpointDescribeInvocationError> {
330    fn __lenso_into_result(self) -> Result<Result<DescribeResponse, DescribeError>, RuntimeFailure> {
331        match self {
332            Ok(value) => Ok(Ok(value)),
333            Err(EndpointDescribeInvocationError::Domain(error)) => Ok(Err(error)),
334            Err(EndpointDescribeInvocationError::Runtime(error)) => Err(error),
335        }
336    }
337}
338
339#[doc(hidden)]
340pub trait __LensoIntoEndpointHandleResult {
341    fn __lenso_into_result(self) -> Result<Result<HandleResponse, HandleError>, RuntimeFailure>;
342}
343impl __LensoIntoEndpointHandleResult for Result<HandleResponse, HandleError> {
344    fn __lenso_into_result(self) -> Result<Result<HandleResponse, HandleError>, RuntimeFailure> { Ok(self) }
345}
346impl __LensoIntoEndpointHandleResult for Result<Result<HandleResponse, HandleError>, RuntimeFailure> {
347    fn __lenso_into_result(self) -> Result<Result<HandleResponse, HandleError>, RuntimeFailure> { self }
348}
349impl __LensoIntoEndpointHandleResult for Result<HandleResponse, lenso_plugin_authoring::PluginError<HandleError, RuntimeFailure>> {
350    fn __lenso_into_result(self) -> Result<Result<HandleResponse, HandleError>, RuntimeFailure> {
351        match self {
352            Ok(value) => Ok(Ok(value)),
353            Err(lenso_plugin_authoring::PluginError::Domain(error)) => Ok(Err(error)),
354            Err(lenso_plugin_authoring::PluginError::Runtime(error)) => Err(error),
355        }
356    }
357}
358impl __LensoIntoEndpointHandleResult for Result<HandleResponse, EndpointHandleInvocationError> {
359    fn __lenso_into_result(self) -> Result<Result<HandleResponse, HandleError>, RuntimeFailure> {
360        match self {
361            Ok(value) => Ok(Ok(value)),
362            Err(EndpointHandleInvocationError::Domain(error)) => Ok(Err(error)),
363            Err(EndpointHandleInvocationError::Runtime(error)) => Err(error),
364        }
365    }
366}
367
368pub trait EndpointProvider: fmt::Debug + 'static {
369    fn describe(&self, context: InvocationContext, request: DescribeRequest) -> NativeRequestFuture<EndpointDescribe>;
370    fn handle(&self, context: InvocationContext, request: HandleRequest) -> NativeRequestFuture<EndpointHandle>;
371}
372
373#[doc(hidden)]
374#[macro_export]
375macro_rules! __lenso_native_lower_endpoint {
376    ($plugin:ty, $support:path) => {
377        use $support as __LensoNativeSupportEndpoint;
378        impl $crate::EndpointProvider for $plugin {
379        fn describe(&self, context: __LensoNativeSupportEndpoint::InvocationContext, request: $crate::DescribeRequest) -> __LensoNativeSupportEndpoint::NativeRequestFuture<$crate::EndpointDescribe> {
380            let plugin = self.clone();
381            ::std::boxed::Box::pin(async move {
382                let result = <$plugin>::describe(&plugin, context, request).await;
383                $crate::__LensoIntoEndpointDescribeResult::__lenso_into_result(result)
384            })
385        }
386        fn handle(&self, context: __LensoNativeSupportEndpoint::InvocationContext, request: $crate::HandleRequest) -> __LensoNativeSupportEndpoint::NativeRequestFuture<$crate::EndpointHandle> {
387            let plugin = self.clone();
388            ::std::boxed::Box::pin(async move {
389                let result = <$plugin>::handle(&plugin, context, request).await;
390                $crate::__LensoIntoEndpointHandleResult::__lenso_into_result(result)
391            })
392        }
393        }
394    };
395}
396
397#[derive(Debug)]
398struct EndpointRequestEndpoint { provider: Rc<dyn EndpointProvider> }
399
400#[derive(Debug)]
401pub struct EndpointEndpoint<P: EndpointProvider> { provider: Rc<P>, request_endpoint: EndpointRequestEndpoint }
402impl<P: EndpointProvider> EndpointEndpoint<P> {
403    pub fn new(provider: P) -> Self {
404        let provider = Rc::new(provider);
405        let request_provider: Rc<dyn EndpointProvider> = provider.clone();
406        Self { provider, request_endpoint: EndpointRequestEndpoint { provider: request_provider } }
407    }
408}
409
410impl<P: EndpointProvider> NativeRequestEndpoint for EndpointEndpoint<P> {
411    fn capability_id(&self) -> &'static str { CAPABILITY_ID }
412    fn descriptor_version(&self) -> &'static str { DESCRIPTOR_VERSION }
413    fn operations(&self) -> &'static [&'static str] { &[
414        DESCRIBE_OPERATION,
415        HANDLE_OPERATION,
416    ] }
417    fn typed_endpoint(&self) -> Option<&dyn std::any::Any> { Some(&self.request_endpoint) }
418    fn invoke(&self, operation: &str, request: Box<dyn std::any::Any>, context: InvocationContext) -> LocalBoxFuture<'static, Result<Result<Box<dyn std::any::Any>, Box<dyn std::any::Any>>, RuntimeFailure>> {
419        match operation {
420            DESCRIBE_OPERATION => {
421                let Ok(request) = request.downcast::<DescribeRequest>() else {
422                    return Box::pin(futures::future::ready(Err(RuntimeFailure::ProtocolViolation { capability: CAPABILITY_ID })));
423                };
424                let invocation = Rc::clone(&self.provider).describe(context, *request);
425                Box::pin(async move {
426                    invocation.await.map(|result| {
427                        result
428                            .map(|value| Box::new(value) as Box<dyn std::any::Any>)
429                            .map_err(|error| Box::new(error) as Box<dyn std::any::Any>)
430                    })
431                })
432            },
433            HANDLE_OPERATION => {
434                let Ok(request) = request.downcast::<HandleRequest>() else {
435                    return Box::pin(futures::future::ready(Err(RuntimeFailure::ProtocolViolation { capability: CAPABILITY_ID })));
436                };
437                let invocation = Rc::clone(&self.provider).handle(context, *request);
438                Box::pin(async move {
439                    invocation.await.map(|result| {
440                        result
441                            .map(|value| Box::new(value) as Box<dyn std::any::Any>)
442                            .map_err(|error| Box::new(error) as Box<dyn std::any::Any>)
443                    })
444                })
445            }
446            _ => Box::pin(futures::future::ready(Err(RuntimeFailure::UnknownOperation { capability: CAPABILITY_ID, operation: operation.to_owned() }))),
447        }
448    }
449}
450
451#[doc(hidden)]
452#[macro_export]
453macro_rules! __lenso_native_endpoints_endpoint {
454    ($provider:expr, $support:path) => {{
455        use $support as __LensoNativeSupport;
456        let endpoint = ::std::rc::Rc::new($crate::EndpointEndpoint::new($provider));
457        (
458            vec![endpoint.clone() as ::std::rc::Rc<dyn __LensoNativeSupport::NativeRequestEndpoint>],
459            vec![],
460            vec![],
461        )
462    }};
463}
464
465#[doc(hidden)]
466#[macro_export]
467macro_rules! __lenso_native_provide_endpoint {
468    ($provider:expr, $lifecycle:expr, $support:path) => {{
469        use $support as __LensoNativeSupport;
470        let (request_endpoints, stream_endpoints, event_endpoints) =
471            $crate::__lenso_native_endpoints_endpoint!($provider, $support);
472        __LensoNativeSupport::NativePluginInstance::with_all_endpoints(
473            request_endpoints,
474            stream_endpoints,
475            event_endpoints,
476            $lifecycle,
477        )
478    }};
479}
480
481#[derive(Debug)]
482pub struct EndpointClient {
483    describe: NativeRequestHandle<EndpointDescribe>,
484    handle: NativeRequestHandle<EndpointHandle>,
485}
486impl EndpointClient {
487    pub fn from_dependencies(dependencies: &PluginDependencies) -> Result<Self, RuntimeFailure> {
488        <Self as CapabilityClient>::from_dependencies(dependencies)
489    }
490
491    pub async fn describe(&self, request: DescribeRequest) -> Result<DescribeResponse, EndpointDescribeInvocationError> {
492        self.describe.invoke(DESCRIBE_OPERATION, request).await
493            .map_err(EndpointDescribeInvocationError::Runtime)?
494            .map_err(EndpointDescribeInvocationError::Domain)
495    }
496
497    pub async fn describe_with_context(&self, context: InvocationContext, request: DescribeRequest) -> Result<DescribeResponse, EndpointDescribeInvocationError> {
498        self.describe.invoke_with_context(DESCRIBE_OPERATION, context, request).await
499            .map_err(EndpointDescribeInvocationError::Runtime)?
500            .map_err(EndpointDescribeInvocationError::Domain)
501    }
502
503    pub async fn handle(&self, request: HandleRequest) -> Result<HandleResponse, EndpointHandleInvocationError> {
504        self.handle.invoke(HANDLE_OPERATION, request).await
505            .map_err(EndpointHandleInvocationError::Runtime)?
506            .map_err(EndpointHandleInvocationError::Domain)
507    }
508
509    pub async fn handle_with_context(&self, context: InvocationContext, request: HandleRequest) -> Result<HandleResponse, EndpointHandleInvocationError> {
510        self.handle.invoke_with_context(HANDLE_OPERATION, context, request).await
511            .map_err(EndpointHandleInvocationError::Runtime)?
512            .map_err(EndpointHandleInvocationError::Domain)
513    }
514}
515
516impl CapabilityClient for EndpointClient {
517    type Dependencies = PluginDependencies;
518    type Error = RuntimeFailure;
519
520    const CAPABILITY_ID: &'static str = CAPABILITY_ID;
521    const DESCRIPTOR_VERSION: &'static str = DESCRIPTOR_VERSION;
522
523    fn from_dependencies(dependencies: &PluginDependencies) -> Result<Self, RuntimeFailure> {
524        Ok(Self {
525            describe: dependencies.one::<EndpointDescribe>()?,
526            handle: dependencies.one::<EndpointHandle>()?,
527        })
528    }
529
530    fn already_connected() -> RuntimeFailure {
531        RuntimeFailure::PluginFailure {
532            detail: format!("Capability Port {CAPABILITY_ID} was connected more than once"),
533        }
534    }
535}
536
537impl CapabilityClientMany for EndpointClient {
538    fn many_from_dependencies(
539        dependencies: &PluginDependencies,
540    ) -> Result<Vec<BoundCapabilityClient<Self>>, RuntimeFailure> {
541        dependencies
542            .bindings()
543            .iter()
544            .filter(|binding| binding.capability_id() == CAPABILITY_ID)
545            .map(|binding| {
546                Ok(BoundCapabilityClient::new(
547                    binding.provider_instance(),
548                    Self {
549                    describe: binding.handle().ok_or(RuntimeFailure::Unavailable { capability: CAPABILITY_ID })?.typed::<EndpointDescribe>()?,
550                    handle: binding.handle().ok_or(RuntimeFailure::Unavailable { capability: CAPABILITY_ID })?.typed::<EndpointHandle>()?,
551                    },
552                ))
553            })
554            .collect()
555    }
556}
557
558#[derive(Clone, Debug, PartialEq)]
559pub enum EndpointDescribeInvocationError {
560    Domain(DescribeError),
561    Runtime(RuntimeFailure),
562}
563#[derive(Clone, Debug, PartialEq)]
564pub enum EndpointHandleInvocationError {
565    Domain(HandleError),
566    Runtime(RuntimeFailure),
567}