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}