1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
// #![include_doc("../README.ja.md", start)]
//! # jsoncall
//!
//! [](https://crates.io/crates/jsoncall)
//! [](https://docs.rs/jsoncall/)
//! [](https://github.com/frozenlib/jsoncall/actions)
//!
//! 型を活用したシンプルな非同期 JSON-RPC 2.0 ライブラリ
//!
//! ## 概要
//!
//! `jsoncall`は Rust の型を最大限に活用したシンプルな非同期 [JSON-RPC 2.0] ライブラリです。
//!
//! 特に [Language Server Protocol] や [Model Context Protocol] のような
//! クライアントがサーバーを起動するタイプのアプリケーションを容易に作成できるようにすることを目的としています。
//!
//! ## 特徴
//!
//! - [`tokio`] と `async/await` による非同期のサポート
//! - [`serde`] を利用し、強く型付けされたリクエストとレスポンスを利用可能
//! - [`typify`] によって JSON Schema から Rust の型を生成すれば JSON Schema で定義された RPC も容易に実装可能
//! - キャンセル処理のサポート基盤あり
//! - [Language Server Protocol] や [Model Context Protocol] のキャンセル処理を実装可能
//! - エラーハンドリングの充実
//! - [`anyhow`] や `Box<dyn Error>` のように任意のエラーを格納でき、それに加えて外部に送信すべき情報とそうでない情報を区別する機能を持つエラー型を用意
//! - 双方向通信のサポート
//! - 通知(Notification)のサポート
//! - トランスポートは `tokio` の `AsyncBufRead` と `AsyncWrite` を実装した型であれば何でも可
//! - 標準入出力を使用したトランスポートは `Session::from_stdio` と `Session::from_command` ですぐに利用できる
//! - 小規模な理解しやすい API セット
//!
//! ## インストール
//!
//! Cargo.toml に以下を追加してください:
//!
//! ```toml
//! [dependencies]
//! jsoncall = "0.0.3"
//! ```
//!
//! ## 使用方法
//!
//! ### サーバーの実装例
//!
//! ```rust
//! use serde::{Deserialize, Serialize};
//! use jsoncall::{Handler, Params, RequestContext, Response, Result, Session, SessionOptions};
//!
//! #[derive(Debug, Serialize, Deserialize)]
//! struct HelloRequest {
//! name: String,
//! }
//!
//! #[derive(Debug, Serialize, Deserialize)]
//! struct HelloResponse {
//! message: String,
//! }
//!
//! struct HelloHandler;
//!
//! impl Handler for HelloHandler {
//! fn request(&mut self, method: &str, params: Params, cx: RequestContext) -> Result<Response> {
//! match method {
//! "hello" => cx.handle(self.hello(params.to()?)),
//! _ => cx.method_not_found(),
//! }
//! }
//! }
//!
//! impl HelloHandler {
//! fn hello(&self, r: HelloRequest) -> Result<HelloResponse> {
//! Ok(HelloResponse {
//! message: format!("Hello, {}!", r.name),
//! })
//! }
//! }
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//! // 標準入出力を使用してサーバーを起動
//! Ok(Session::from_stdio(HelloHandler, &SessionOptions::default()).wait().await?)
//! }
//! ```
//!
//! ### クライアントの使用例
//!
//! ```rust
//! use serde::{Deserialize, Serialize};
//! use tokio::process::Command;
//! use jsoncall::{Result, Session, SessionOptions};
//!
//! #[derive(Debug, Serialize, Deserialize)]
//! struct HelloRequest {
//! name: String,
//! }
//!
//! #[derive(Debug, Serialize, Deserialize)]
//! struct HelloResponse {
//! message: String,
//! }
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//! // サーバープロセスを起動してセッションを作成
//! let client = Session::from_command(
//! (),
//! Command::new("cargo").args(["run", "--example", "stdio_server"]),
//! &SessionOptions::default(),
//! )?;
//!
//! // リクエストの送信
//! let response: HelloResponse = client
//! .request(
//! "hello",
//! Some(&HelloRequest {
//! name: "world".to_string(),
//! }),
//! )
//! .await?;
//!
//! println!("{:?}", response);
//! Ok(())
//! }
//! ```
//!
//! ### 非同期ハンドラーの例
//!
//! ```rust
//! use jsoncall::{Handler, Params, RequestContext, Result, Response};
//!
//! struct ExampleHandler;
//!
//! impl Handler for ExampleHandler {
//! fn request(&mut self, method: &str, params: Params, cx: RequestContext) -> Result<Response> {
//! match method {
//! "add" => {
//! let params: (i32, i32) = params.to()?;
//! cx.handle_async(async move {
//! tokio::time::sleep(std::time::Duration::from_secs(1)).await;
//! Ok(params.0 + params.1)
//! })
//! }
//! _ => cx.method_not_found(),
//! }
//! }
//! }
//! ```
//!
//! ## ライセンス
//!
//! This project is dual licensed under Apache-2.0/MIT. See the two LICENSE-\* files for details.
//!
//! ## Contribution
//!
//! Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
//!
//! [JSON-RPC 2.0]: https://www.jsonrpc.org/specification
//! [`tokio`]: https://github.com/tokio-rs/tokio
//! [`serde`]: https://github.com/serde-rs/serde
//! [`typify`]: https://github.com/oxidecomputer/typify
//! [`anyhow`]: https://github.com/dtolnay/anyhow
//! [Language Server Protocol]: https://microsoft.github.io/language-server-protocol/
//! [Model Context Protocol]: https://modelcontextprotocol.io/introduction
// #![include_doc("../README.ja.md", end)]
// #![include_doc("../README.md", start)]
//! # jsoncall
//!
//! [](https://crates.io/crates/jsoncall)
//! [](https://docs.rs/jsoncall/)
//! [](https://github.com/frozenlib/jsoncall/actions)
//!
//! A simple asynchronous JSON-RPC 2.0 library leveraging Rust's type system
//!
//! ## Overview
//!
//! `jsoncall` is a simple asynchronous [JSON-RPC 2.0] library that maximizes the use of Rust's type system.
//!
//! It is specifically designed to facilitate the creation of applications where the client launches the server, such as the [Language Server Protocol] and [Model Context Protocol].
//!
//! ## Features
//!
//! - Asynchronous support using [`tokio`] and `async/await`
//! - Strongly typed requests and responses using [`serde`]
//! - Easy implementation of JSON Schema-defined RPCs by generating Rust types using [`typify`]
//! - Built-in support for cancellation handling
//! - Enables implementation of cancellation for [Language Server Protocol] and [Model Context Protocol]
//! - Comprehensive error handling
//! - Provides error types that can store any error like [`anyhow`] or `Box<dyn Error>`, with additional functionality to distinguish between information that should be sent externally and information that should not
//! - Bidirectional communication support
//! - Notification support
//! - Transport layer supports any type implementing `tokio`'s `AsyncBufRead` and `AsyncWrite` traits
//! - Standard I/O transport is readily available through `Session::from_stdio` and `Session::from_command`
//! - Small, understandable API set
//!
//! ## Installation
//!
//! Add the following to your Cargo.toml:
//!
//! ```toml
//! [dependencies]
//! jsoncall = "0.0.3"
//! ```
//!
//! ## Usage
//!
//! ### Server Implementation Example
//!
//! ```rust
//! use serde::{Deserialize, Serialize};
//! use jsoncall::{Handler, Params, RequestContext, Response, Result, Session, SessionOptions};
//!
//! #[derive(Debug, Serialize, Deserialize)]
//! struct HelloRequest {
//! name: String,
//! }
//!
//! #[derive(Debug, Serialize, Deserialize)]
//! struct HelloResponse {
//! message: String,
//! }
//!
//! struct HelloHandler;
//!
//! impl Handler for HelloHandler {
//! fn request(&mut self, method: &str, params: Params, cx: RequestContext) -> Result<Response> {
//! match method {
//! "hello" => cx.handle(self.hello(params.to()?)),
//! _ => cx.method_not_found(),
//! }
//! }
//! }
//!
//! impl HelloHandler {
//! fn hello(&self, r: HelloRequest) -> Result<HelloResponse> {
//! Ok(HelloResponse {
//! message: format!("Hello, {}!", r.name),
//! })
//! }
//! }
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//! // Start server using standard I/O
//! Ok(Session::from_stdio(HelloHandler, &SessionOptions::default()).wait().await?)
//! }
//! ```
//!
//! ### Client Usage Example
//!
//! ```rust
//! use serde::{Deserialize, Serialize};
//! use tokio::process::Command;
//! use jsoncall::{Result, Session, SessionOptions};
//!
//! #[derive(Debug, Serialize, Deserialize)]
//! struct HelloRequest {
//! name: String,
//! }
//!
//! #[derive(Debug, Serialize, Deserialize)]
//! struct HelloResponse {
//! message: String,
//! }
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//! // Launch server process and create session
//! let client = Session::from_command(
//! (),
//! Command::new("cargo").args(["run", "--example", "stdio_server"]),
//! &SessionOptions::default(),
//! )?;
//!
//! // Send request
//! let response: HelloResponse = client
//! .request(
//! "hello",
//! Some(&HelloRequest {
//! name: "world".to_string(),
//! }),
//! )
//! .await?;
//!
//! println!("{:?}", response);
//! Ok(())
//! }
//! ```
//!
//! ### Asynchronous Handler Example
//!
//! ```rust
//! use jsoncall::{Handler, Params, RequestContext, Result, Response};
//!
//! struct ExampleHandler;
//!
//! impl Handler for ExampleHandler {
//! fn request(&mut self, method: &str, params: Params, cx: RequestContext) -> Result<Response> {
//! match method {
//! "add" => {
//! let params: (i32, i32) = params.to()?;
//! cx.handle_async(async move {
//! tokio::time::sleep(std::time::Duration::from_secs(1)).await;
//! Ok(params.0 + params.1)
//! })
//! }
//! _ => cx.method_not_found(),
//! }
//! }
//! }
//! ```
//!
//! ## License
//!
//! This project is dual licensed under Apache-2.0/MIT. See the two LICENSE-\* files for details.
//!
//! ## Contribution
//!
//! Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
//!
//! [JSON-RPC 2.0]: https://www.jsonrpc.org/specification
//! [`tokio`]: https://github.com/tokio-rs/tokio
//! [`serde`]: https://github.com/serde-rs/serde
//! [`typify`]: https://github.com/oxidecomputer/typify
//! [`anyhow`]: https://github.com/dtolnay/anyhow
//! [Language Server Protocol]: https://microsoft.github.io/language-server-protocol/
//! [Model Context Protocol]: https://modelcontextprotocol.io/introduction
// #![include_doc("../README.md", end)]