Skip to main content

liminal_sdk/
channel.rs

1use core::future::Future;
2
3use futures_core::Stream;
4use serde::Serialize;
5use serde::de::DeserializeOwned;
6
7use crate::{PressureResponse, SchemaValidate, SdkError};
8
9/// Application-facing typed channel API.
10///
11/// `ChannelHandle` intentionally exposes typed messages only. It does not expose
12/// envelopes, byte buffers, protocol frames, publisher identifiers, or transport
13/// handles; embedded and remote implementations perform any necessary
14/// serialization and schema validation behind this trait.
15///
16/// # Object safety
17///
18/// This trait is not object-safe because its methods are generic over message
19/// types and because subscriptions/replies are represented with generic
20/// associated return types. Use concrete handle types behind generic bounds such
21/// as `H: ChannelHandle`, or define an application enum over the concrete handle
22/// implementations that need to be selected at runtime. Future SDK layers may
23/// add an explicitly erased adapter without weakening the typed API here.
24///
25/// ```compile_fail
26/// use liminal_sdk::ChannelHandle;
27/// use serde::Serialize;
28///
29/// #[derive(Serialize)]
30/// struct OnlySerializable {
31///     id: String,
32/// }
33///
34/// fn publish_without_schema<H>(handle: &H, message: OnlySerializable)
35/// where
36///     H: ChannelHandle,
37/// {
38///     let _ = handle.publish(message);
39/// }
40/// ```
41pub trait ChannelHandle: core::fmt::Debug + Send + Sync {
42    /// Stream returned by [`subscribe`](Self::subscribe) for message type `M`.
43    type Subscription<M>: Stream<Item = Result<M, SdkError>>
44    where
45        M: DeserializeOwned;
46
47    /// Future returned by [`request_reply`](Self::request_reply) for reply type `Resp`.
48    type ReplyFuture<'a, Resp>: Future<Output = Result<Resp, SdkError>> + 'a
49    where
50        Self: 'a,
51        Resp: DeserializeOwned + 'a;
52
53    /// Publishes a typed message to the channel.
54    ///
55    /// The message type must be serializable and must declare schema metadata;
56    /// a merely serializable value is rejected at compile time. The returned
57    /// [`PressureResponse`] reports whether the bus accepted, deferred, or
58    /// rejected the publish attempt.
59    ///
60    /// # Errors
61    ///
62    /// Returns [`SdkError`] when the concrete channel implementation cannot
63    /// serialize, validate, or submit the message for delivery.
64    fn publish<M>(&self, message: M) -> Result<PressureResponse, SdkError>
65    where
66        M: Serialize + SchemaValidate;
67
68    /// Subscribes to typed channel messages.
69    ///
70    /// Subscription and delivery failures are surfaced to the application as
71    /// [`SdkError`] items in the returned stream.
72    fn subscribe<M>(&self) -> Self::Subscription<M>
73    where
74        M: DeserializeOwned;
75
76    /// Sends a typed request and resolves with a typed reply.
77    ///
78    /// The request type must be serializable and schema-declared. The reply type
79    /// must be owned after deserialization so callers never borrow transport
80    /// buffers managed by an SDK implementation.
81    ///
82    /// # Errors
83    ///
84    /// The returned future resolves to [`SdkError`] when the concrete channel
85    /// implementation cannot send the request, observe the reply, or deserialize
86    /// the reply payload.
87    fn request_reply<Req, Resp>(&self, request: Req) -> Self::ReplyFuture<'_, Resp>
88    where
89        Req: Serialize + SchemaValidate,
90        Resp: DeserializeOwned;
91}