Skip to content

Commit 9b17d5b

Browse files
committed
feat(sacp): implement Component for JrConnectionBuilder
JrConnectionBuilder now implements Component<H::Link>, allowing it to be used anywhere a Component is expected. This enables more compositional patterns where connection builders can be passed directly to functions expecting components.
1 parent a0d194e commit 9b17d5b

2 files changed

Lines changed: 66 additions & 1 deletion

File tree

src/sacp/src/jsonrpc.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,19 @@ impl<H: JrMessageHandler, R: JrResponder<H::Link>> JrConnectionBuilder<H, R> {
11881188
}
11891189
}
11901190

1191+
impl<H, R> Component<H::Link> for JrConnectionBuilder<H, R>
1192+
where
1193+
H: JrMessageHandler + 'static,
1194+
R: JrResponder<H::Link> + 'static,
1195+
{
1196+
async fn serve(
1197+
self,
1198+
client: impl Component<<H::Link as JrLink>::ConnectsTo>,
1199+
) -> Result<(), crate::Error> {
1200+
self.connect_to(client)?.serve().await
1201+
}
1202+
}
1203+
11911204
/// A JSON-RPC connection with an active transport.
11921205
///
11931206
/// This type represents a `JrConnectionBuilder` that has been connected to a transport

src/sacp/tests/jsonrpc_connection_builder.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
//! handler claims them.
66
77
use sacp::link::UntypedLink;
8+
use sacp::util::run_until;
89
use sacp::{
9-
JrConnectionCx, JrMessage, JrNotification, JrRequest, JrRequestCx, JrResponse,
10+
Component, JrConnectionCx, JrMessage, JrNotification, JrRequest, JrRequestCx, JrResponse,
1011
JrResponsePayload,
1112
};
1213
use serde::{Deserialize, Serialize};
@@ -623,3 +624,54 @@ async fn test_handler_claims_notification() {
623624
})
624625
.await;
625626
}
627+
628+
// ============================================================================
629+
// Test 6: JrConnectionBuilder implements Component
630+
// ============================================================================
631+
632+
#[tokio::test]
633+
async fn test_connection_builder_as_component() -> Result<(), sacp::Error> {
634+
// Create duplex streams
635+
let (server_stream, client_stream) = tokio::io::duplex(8192);
636+
let (server_read, server_write) = tokio::io::split(server_stream);
637+
let (client_read, client_write) = tokio::io::split(client_stream);
638+
639+
// Create a connection builder (server side)
640+
let server_builder = UntypedLink::builder().on_receive_request(
641+
async |request: FooRequest,
642+
request_cx: JrRequestCx<FooResponse>,
643+
_cx: JrConnectionCx<UntypedLink>| {
644+
request_cx.respond(FooResponse {
645+
result: format!("component: {}", request.value),
646+
})
647+
},
648+
sacp::on_receive_request!(),
649+
);
650+
651+
// Create ByteStreams for both sides
652+
let server_transport =
653+
sacp::ByteStreams::new(server_write.compat_write(), server_read.compat());
654+
let client_transport =
655+
sacp::ByteStreams::new(client_write.compat_write(), client_read.compat());
656+
657+
// Use JrConnectionBuilder as a Component via run_until
658+
run_until(
659+
// This uses Component::serve on JrConnectionBuilder
660+
Component::<UntypedLink>::serve(server_builder, server_transport),
661+
async move {
662+
// Client side
663+
UntypedLink::builder()
664+
.run_until(client_transport, async |cx| {
665+
let response = recv(cx.send_request(FooRequest {
666+
value: "test".to_string(),
667+
}))
668+
.await?;
669+
670+
assert_eq!(response.result, "component: test");
671+
Ok(())
672+
})
673+
.await
674+
},
675+
)
676+
.await
677+
}

0 commit comments

Comments
 (0)