Skip to content

Commit 75bbd74

Browse files
committed
docs(sacp): un-ignore doc examples and make them compile
Convert 33 doc examples from ```ignore to compilable ``` blocks using sacp-test support types. Remaining 14 ignore blocks are: - Deadlock demonstration examples in ordering.rs (intentional) - Complex schema types in cookbook.rs (RequestPermission, etc.) - Derive macro examples in jsonrpc.rs (require proc-macro) - External crate examples (sacp-conductor) All 71 doc tests now pass.
1 parent 0e63f2d commit 75bbd74

9 files changed

Lines changed: 392 additions & 141 deletions

File tree

src/sacp/src/concepts/callbacks.rs

Lines changed: 67 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,22 @@
77
//!
88
//! Use `on_receive_request` to handle incoming requests that expect a response:
99
//!
10-
//! ```ignore
10+
//! ```
11+
//! # use sacp::{ClientToAgent, AgentToClient, Component};
12+
//! # use sacp_test::{ValidateRequest, ValidateResponse};
13+
//! # async fn example(transport: impl Component<AgentToClient>) -> Result<(), sacp::Error> {
1114
//! ClientToAgent::builder()
12-
//! .on_receive_request(async |req: PermissionRequest, request_cx, cx| {
13-
//! // Decide whether to grant the permission
14-
//! let granted = prompt_user(&req).await;
15+
//! .on_receive_request(async |req: ValidateRequest, request_cx, cx| {
16+
//! // Process the request
17+
//! let is_valid = req.data.len() > 0;
1518
//!
1619
//! // Send the response
17-
//! request_cx.respond(PermissionResponse { granted })
18-
//! }, on_receive_request!())
19-
//! .run_until(transport, async |cx| { ... })
20+
//! request_cx.respond(ValidateResponse { is_valid, error: None })
21+
//! }, sacp::on_receive_request!())
22+
//! .run_until(transport, async |cx| { Ok(()) })
2023
//! .await?;
24+
//! # Ok(())
25+
//! # }
2126
//! ```
2227
//!
2328
//! Your callback receives three arguments:
@@ -30,23 +35,53 @@
3035
//! Use `on_receive_notification` for fire-and-forget messages that don't need
3136
//! a response:
3237
//!
33-
//! ```ignore
34-
//! builder.on_receive_notification(async |notif: ProgressNotification, cx| {
35-
//! println!("Progress: {}%", notif.percent);
36-
//! Ok(())
37-
//! }, on_receive_notification!());
38+
//! ```
39+
//! # use sacp::{ClientToAgent, AgentToClient, Component};
40+
//! # use sacp_test::StatusUpdate;
41+
//! # async fn example(transport: impl Component<AgentToClient>) -> Result<(), sacp::Error> {
42+
//! ClientToAgent::builder()
43+
//! .on_receive_notification(async |notif: StatusUpdate, cx| {
44+
//! println!("Status: {}", notif.message);
45+
//! Ok(())
46+
//! }, sacp::on_receive_notification!())
47+
//! # .run_until(transport, async |_| Ok(())).await?;
48+
//! # Ok(())
49+
//! # }
3850
//! ```
3951
//!
4052
//! # The Request Context
4153
//!
4254
//! The [`JrRequestCx`] lets you send a response to the request:
4355
//!
44-
//! ```ignore
56+
//! ```
57+
//! # use sacp::{ClientToAgent, AgentToClient, Component};
58+
//! # use sacp_test::{MyRequest, MyResponse};
59+
//! # async fn example(transport: impl Component<AgentToClient>) -> Result<(), sacp::Error> {
60+
//! # ClientToAgent::builder()
61+
//! # .on_receive_request(async |req: MyRequest, request_cx, cx| {
4562
//! // Send a successful response
46-
//! request_cx.respond(MyResponse { ... })?;
63+
//! request_cx.respond(MyResponse { status: "ok".into() })?;
64+
//! # Ok(())
65+
//! # }, sacp::on_receive_request!())
66+
//! # .run_until(transport, async |_| Ok(())).await?;
67+
//! # Ok(())
68+
//! # }
69+
//! ```
4770
//!
48-
//! // Or send an error
49-
//! request_cx.respond_with_error(Error::invalid_params("missing field"))?;
71+
//! Or send an error:
72+
//!
73+
//! ```
74+
//! # use sacp::{ClientToAgent, AgentToClient, Component};
75+
//! # use sacp_test::{MyRequest, MyResponse};
76+
//! # async fn example(transport: impl Component<AgentToClient>) -> Result<(), sacp::Error> {
77+
//! # ClientToAgent::builder()
78+
//! # .on_receive_request(async |req: MyRequest, request_cx, cx| {
79+
//! request_cx.respond_with_error(sacp::Error::invalid_params())?;
80+
//! # Ok(())
81+
//! # }, sacp::on_receive_request!())
82+
//! # .run_until(transport, async |_| Ok(())).await?;
83+
//! # Ok(())
84+
//! # }
5085
//! ```
5186
//!
5287
//! You must send exactly one response per request. If your callback returns
@@ -57,17 +92,22 @@
5792
//! You can register multiple handlers. They're tried in order until one
5893
//! handles the message:
5994
//!
60-
//! ```ignore
61-
//! builder
62-
//! .on_receive_request(async |req: PermissionRequest, request_cx, cx| {
63-
//! // Handle permission requests
64-
//! request_cx.respond(PermissionResponse { granted: true })
65-
//! }, on_receive_request!())
66-
//! .on_receive_request(async |req: ToolCallRequest, request_cx, cx| {
67-
//! // Handle tool calls
68-
//! request_cx.respond(ToolCallResponse { result: "done".into() })
69-
//! }, on_receive_request!())
70-
//! // ...
95+
//! ```
96+
//! # use sacp::{ClientToAgent, AgentToClient, Component};
97+
//! # use sacp_test::{ValidateRequest, ValidateResponse, ExecuteRequest, ExecuteResponse};
98+
//! # async fn example(transport: impl Component<AgentToClient>) -> Result<(), sacp::Error> {
99+
//! ClientToAgent::builder()
100+
//! .on_receive_request(async |req: ValidateRequest, request_cx, cx| {
101+
//! // Handle validation requests
102+
//! request_cx.respond(ValidateResponse { is_valid: true, error: None })
103+
//! }, sacp::on_receive_request!())
104+
//! .on_receive_request(async |req: ExecuteRequest, request_cx, cx| {
105+
//! // Handle execution requests
106+
//! request_cx.respond(ExecuteResponse { result: "done".into() })
107+
//! }, sacp::on_receive_request!())
108+
//! # .run_until(transport, async |_| Ok(())).await?;
109+
//! # Ok(())
110+
//! # }
71111
//! ```
72112
//!
73113
//! # Ordering Guarantees

src/sacp/src/concepts/connections.rs

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,36 +20,47 @@
2020
//! Every link type has a `builder()` method that returns a connection builder.
2121
//! The builder lets you configure handlers, then connect to a transport:
2222
//!
23-
//! ```ignore
24-
//! use sacp::ClientToAgent;
25-
//!
23+
//! ```
24+
//! # use sacp::{ClientToAgent, AgentToClient, Component};
25+
//! # async fn example(transport: impl Component<AgentToClient>) -> Result<(), sacp::Error> {
2626
//! ClientToAgent::builder()
2727
//! .name("my-client")
28-
//! .connect_to(transport)
29-
//! .run_until(async |cx| {
28+
//! .run_until(transport, async |cx| {
3029
//! // Use `cx` to send requests and handle responses
3130
//! Ok(())
3231
//! })
3332
//! .await?;
33+
//! # Ok(())
34+
//! # }
3435
//! ```
3536
//!
3637
//! # The Connection Context
3738
//!
3839
//! Inside `run_until`, you receive a [`JrConnectionCx`] (connection context) that
3940
//! lets you interact with the remote peer:
4041
//!
41-
//! ```ignore
42-
//! .run_until(async |cx| {
43-
//! // Send a request and wait for the response
44-
//! let response = cx.send_request(InitializeRequest { ... })
45-
//! .block_task()
46-
//! .await?;
47-
//!
48-
//! // Send a notification (fire-and-forget)
49-
//! cx.send_notification(SomeNotification { ... })?;
50-
//!
51-
//! Ok(())
42+
//! ```
43+
//! # use sacp::{ClientToAgent, AgentToClient, Component};
44+
//! # use sacp::schema::InitializeRequest;
45+
//! # use sacp_test::StatusUpdate;
46+
//! # async fn example(transport: impl Component<AgentToClient>) -> Result<(), sacp::Error> {
47+
//! # ClientToAgent::builder().run_until(transport, async |cx| {
48+
//! // Send a request and wait for the response
49+
//! let response = cx.send_request(InitializeRequest {
50+
//! protocol_version: Default::default(),
51+
//! client_capabilities: Default::default(),
52+
//! client_info: None,
53+
//! meta: None,
5254
//! })
55+
//! .block_task()
56+
//! .await?;
57+
//!
58+
//! // Send a notification (fire-and-forget)
59+
//! cx.send_notification(StatusUpdate { message: "hello".into() })?;
60+
//! # Ok(())
61+
//! # }).await?;
62+
//! # Ok(())
63+
//! # }
5364
//! ```
5465
//!
5566
//! # Sending Requests
@@ -61,19 +72,31 @@
6172
//!
6273
//! Use `block_task()` when you need the response before continuing:
6374
//!
64-
//! ```ignore
65-
//! let response = cx.send_request(MyRequest { ... })
75+
//! ```
76+
//! # use sacp::{ClientToAgent, AgentToClient, Component};
77+
//! # use sacp_test::MyRequest;
78+
//! # async fn example(transport: impl Component<AgentToClient>) -> Result<(), sacp::Error> {
79+
//! # ClientToAgent::builder().run_until(transport, async |cx| {
80+
//! let response = cx.send_request(MyRequest {})
6681
//! .block_task()
6782
//! .await?;
6883
//! // Use response here
84+
//! # Ok(())
85+
//! # }).await?;
86+
//! # Ok(())
87+
//! # }
6988
//! ```
7089
//!
7190
//! ## Option 2: Schedule a callback
7291
//!
7392
//! Use `on_receiving_result()` when you want to handle the response asynchronously:
7493
//!
75-
//! ```ignore
76-
//! cx.send_request(MyRequest { ... })
94+
//! ```
95+
//! # use sacp::{ClientToAgent, AgentToClient, Component};
96+
//! # use sacp_test::MyRequest;
97+
//! # async fn example(transport: impl Component<AgentToClient>) -> Result<(), sacp::Error> {
98+
//! # ClientToAgent::builder().run_until(transport, async |cx| {
99+
//! cx.send_request(MyRequest {})
77100
//! .on_receiving_result(async |result| {
78101
//! match result {
79102
//! Ok(response) => { /* handle success */ }
@@ -82,6 +105,10 @@
82105
//! Ok(())
83106
//! })?;
84107
//! // Continues immediately, callback runs when response arrives
108+
//! # Ok(())
109+
//! # }).await?;
110+
//! # Ok(())
111+
//! # }
85112
//! ```
86113
//!
87114
//! See [Ordering](super::ordering) for important details about how these differ.

src/sacp/src/concepts/error_handling.rs

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,40 @@
2121
//! To send an error response to a request (without closing the connection),
2222
//! use the request context's `respond` method:
2323
//!
24-
//! ```ignore
25-
//! connection.on_receive_request(async |request, request_cx, _cx| {
26-
//! if !is_valid(&request) {
27-
//! // Send error to peer, keep connection alive
28-
//! request_cx.respond(Err(sacp::Error::invalid_params()))?;
29-
//! return Ok(());
30-
//! }
31-
//!
32-
//! // Process valid request...
33-
//! request_cx.respond(Ok(response))?;
34-
//! Ok(())
35-
//! });
24+
//! ```
25+
//! # use sacp::{ClientToAgent, AgentToClient, Component};
26+
//! # use sacp_test::{ValidateRequest, ValidateResponse};
27+
//! # async fn example(transport: impl Component<AgentToClient>) -> Result<(), sacp::Error> {
28+
//! ClientToAgent::builder()
29+
//! .on_receive_request(async |request: ValidateRequest, request_cx, _cx| {
30+
//! if request.data.is_empty() {
31+
//! // Send error to peer, keep connection alive
32+
//! request_cx.respond_with_error(sacp::Error::invalid_params())?;
33+
//! return Ok(());
34+
//! }
35+
//!
36+
//! // Process valid request...
37+
//! request_cx.respond(ValidateResponse { is_valid: true, error: None })?;
38+
//! Ok(())
39+
//! }, sacp::on_receive_request!())
40+
//! # .run_until(transport, async |_| Ok(())).await?;
41+
//! # Ok(())
42+
//! # }
3643
//! ```
3744
//!
3845
//! For sending error notifications (one-way error messages), use
3946
//! [`send_error_notification`][crate::JrConnectionCx::send_error_notification]:
4047
//!
41-
//! ```ignore
48+
//! ```
49+
//! # use sacp::{ClientToAgent, AgentToClient, Component};
50+
//! # async fn example(transport: impl Component<AgentToClient>) -> Result<(), sacp::Error> {
51+
//! # ClientToAgent::builder().run_until(transport, async |cx| {
4252
//! cx.send_error_notification(sacp::Error::internal_error()
4353
//! .with_data("Something went wrong"))?;
54+
//! # Ok(())
55+
//! # }).await?;
56+
//! # Ok(())
57+
//! # }
4458
//! ```
4559
//!
4660
//! # The `into_internal_error` Helper
@@ -50,16 +64,21 @@
5064
//! [`Error::into_internal_error`][crate::Error::into_internal_error] method
5165
//! provides a convenient way to do this:
5266
//!
53-
//! ```ignore
67+
//! ```
5468
//! use sacp::Error;
5569
//!
70+
//! # fn example() -> Result<(), sacp::Error> {
71+
//! # let data = "hello";
72+
//! # let path = "/tmp/test.txt";
5673
//! // Convert any error type to sacp::Error
5774
//! let value = serde_json::to_value(&data)
5875
//! .map_err(Error::into_internal_error)?;
5976
//!
6077
//! // Or with a file operation
6178
//! let contents = std::fs::read_to_string(path)
62-
//! .map_err(Error::into_internal_error)?;
79+
//! .map_err(Error::into_internal_error);
80+
//! # Ok(())
81+
//! # }
6382
//! ```
6483
//!
6584
//! This wraps the original error's message in an internal error, which is
@@ -79,12 +98,12 @@
7998
//!
8099
//! You can add context with `.with_data()`:
81100
//!
82-
//! ```ignore
83-
//! sacp::Error::invalid_params()
101+
//! ```
102+
//! let error = sacp::Error::invalid_params()
84103
//! .with_data(serde_json::json!({
85104
//! "field": "timeout",
86105
//! "reason": "must be positive"
87-
//! }))
106+
//! }));
88107
//! ```
89108
//!
90109
//! # Summary

0 commit comments

Comments
 (0)