Skip to content

Commit 6a5d602

Browse files
authored
Merge pull request #236 from H1rono/doc-handler
handlerまわりのdocs
2 parents ccac54c + c34b098 commit 6a5d602

File tree

4 files changed

+144
-17
lines changed

4 files changed

+144
-17
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ include = ["/src", "/examples", "/README.md", "/LICENSE"]
1919
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
2020

2121
[package.metadata.docs.rs]
22-
features = ["http"]
22+
features = ["tower"]
2323

2424
[dependencies]
2525
serde = { version = "1.0", features = ["derive"] }

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ feature | 機能 | バージョン
7373
`uuid` | ペイロードのUUID値が[`uuid::Uuid`](https://docs.rs/uuid/latest/uuid/struct.Uuid.html)型に | [v0.4.0](https://github.com/H1rono/traq-bot-http-rs/releases/tag/v0.4.0)から
7474
`time` | ペイロードのタイムスタンプ値([RFC3339 format](https://tools.ietf.org/html/rfc3339#section-5.6))が[`time::OffsetDateTime`](https://docs.rs/time/latest/time/struct.OffsetDateTime.html)型に | [v0.5.0](https://github.com/H1rono/traq-bot-http-rs/releases/tag/v0.5.0)から
7575
`chrono` | ペイロードのタイムスタンプ値が[`chrono::DateTime<chrono::Utc>`](https://docs.rs/chrono/latest/chrono/struct.DateTime.html)型に | [v0.6.0](https://github.com/H1rono/traq-bot-http-rs/releases/tag/v0.6.0)から
76-
`http` | [`http::Request`](https://docs.rs/http/latest/http/request/struct.Request.html)型のサポート | [v0.10.0](https://github.com/H1rono/traq-bot-http-rs/releases/tag/v0.10.0)
76+
`http` | [`http::Request`](https://docs.rs/http/latest/http/request/struct.Request.html)型のサポート | [v0.10.0](https://github.com/H1rono/traq-bot-http-rs/releases/tag/v0.10.0)から
77+
`tower` | [`Handler`](https://docs.rs/traq-bot-http/latest/traq_bot_http/struct.Handler.html)構造体 | [v0.10.1](https://github.com/H1rono/traq-bot-http-rs/releases/tag/v0.10.1)から
7778

7879
`time`よりも`chrono`の方が優先されます
7980

src/handler.rs

+116-10
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,29 @@ use std::task::{Context, Poll};
1313
use futures::future::{BoxFuture, Ready as ReadyFuture};
1414
use futures::ready;
1515
use http::{Request, Response, StatusCode};
16+
use paste::paste;
1617
use tower::Service;
1718

1819
use super::Handler;
1920
use crate::macros::all_events;
2021
use crate::{Error, Event, RequestParser};
2122

2223
pin_project_lite::pin_project! {
24+
/// <code>impl Future<Output = Result<(), [Error]>></code>
25+
///
26+
/// `F: Future<Output = Result<(), E>>`を受け取り、エラー型`E`を[`Error`]に変換した[`Future`]を返します。
27+
/// 以下のコードと同様です。
28+
///
29+
/// ```ignore
30+
/// use futures::{TryFutureExt};
31+
///
32+
/// async fn f() -> Result<(), E> { ... }
33+
///
34+
/// let wrap_error = f().map_err(|e| -> traq_bot_http::Error { ... });
35+
/// ```
36+
///
37+
/// [`Future`]: std::future::Future
38+
/// [`Error`]: crate::Error
2339
#[must_use]
2440
#[project = WrapErrorFutureProject]
2541
#[derive(Debug)]
@@ -44,9 +60,14 @@ where
4460
}
4561
}
4662

63+
/// handleされなかった[`Event`]の受け皿となる[`Service`]です。
64+
///
65+
/// [`Event`]: crate::Event
66+
/// [`Service`]: tower::Service
4767
#[must_use]
4868
#[derive(Debug, Clone, Copy, Default, Hash)]
4969
pub struct Sink {
70+
// ユーザーが直接構築できないように
5071
_priv: PhantomData<()>,
5172
}
5273

@@ -70,6 +91,9 @@ impl<T> Service<T> for Sink {
7091
}
7192
}
7293

94+
/// [`Event`]と`State`の直積です。
95+
///
96+
/// [`Event`]: crate::Event
7397
#[must_use]
7498
#[derive(Debug, Clone)]
7599
pub struct EventWithState<State> {
@@ -90,6 +114,12 @@ impl<State> From<EventWithState<State>> for (State, Event) {
90114
}
91115
}
92116

117+
/// 内部の`Service`に`State`を渡す[`Service`]です。
118+
///
119+
/// `WithState::call`の度に`State`がcloneされるため、`State`は[`Clone`]を実装する必要があります。
120+
///
121+
/// [`Service`]: tower::Service
122+
/// [`Clone`]: std::clone::Clone
93123
#[must_use]
94124
#[derive(Debug, Clone)]
95125
pub struct WithState<State, Service> {
@@ -145,23 +175,74 @@ macro_rules! all_event_service {
145175
(
146176
$( $e:ident ),*
147177
) => {
148-
$(
149-
$crate::macros::event_service! {
150-
#[must_use]
151-
#[derive(Debug, Clone)]
152-
pub $e
153-
}
154-
)*
178+
$( $crate::macros::event_service! {
179+
#[doc = paste! { concat!(
180+
"[`", stringify!([< $e:camel Payload >]), "`]をhandleする[`Service`]です。\n\n",
181+
"[`Service`]: tower::Service\n",
182+
"[`", stringify!([< $e:camel Payload >]), "`]: ",
183+
"crate::payloads::", stringify!([< $e:camel Payload >]),
184+
)}]
185+
#[must_use]
186+
#[derive(Debug, Clone)]
187+
pub $e
188+
} )*
155189
};
156190
}
157191

158192
all_events! {all_event_service}
159193

160194
impl<Service> Handler<Service> {
195+
/// 新しくイベントハンドラを作成します。`service`は以下の条件を満たす必要があります。
196+
///
197+
/// - <code>[Service]<[Event]></code>, [`Clone`]を実装している
198+
/// - [`'static`]
199+
/// - `Service::Response`が`()`と等しい
200+
/// - `Service::Error`が<code>Into<Box<dyn [Error] + [Send] + [Sync] + &#39;static>></code>を実装している
201+
/// - `Service::Future`が[`Send`]を実装している
202+
///
203+
/// [Service]: tower::Service
204+
/// [Event]: crate::Event
205+
/// [`Clone`]: std::clone::Clone
206+
/// [`'static`]: https://doc.rust-lang.org/rust-by-example/scope/lifetime/static_lifetime.html#trait-bound
207+
/// [Error]: std::error::Error
208+
/// [Send]: std::marker::Send
209+
/// [Sync]: std::marker::Sync
210+
/// [`Send`]: std::marker::Send
161211
pub fn new(parser: crate::RequestParser, service: Service) -> Self {
162212
Self { service, parser }
163213
}
164214

215+
/// イベントハンドラに`State`を追加します。`State`は以下の条件を満たす必要があります。
216+
///
217+
/// - [`Clone`], [`Send`]を実装している
218+
/// - [`'static`]
219+
///
220+
/// # Example
221+
///
222+
/// ```
223+
/// use std::convert::Infallible;
224+
///
225+
/// use tower::service_fn;
226+
/// use traq_bot_http::{payloads, RequestParser};
227+
///
228+
/// async fn on_ping(state: i32, payload: payloads::PingPayload) -> Result<(), Infallible> {
229+
/// println!("state: {state}, payload: {payload:?}");
230+
/// Ok(())
231+
/// }
232+
///
233+
/// let parser = RequestParser::new("verification_token");
234+
/// let handler = parser
235+
/// .into_handler()
236+
/// // これはinvalidです; with_stateはstateを使用するハンドラより後に置く必要があります
237+
/// // .with_state(0)
238+
/// .on_ping(service_fn(|(state, payload)| on_ping(state, payload)))
239+
/// .with_state(0);
240+
/// # let _ = handler;
241+
/// ```
242+
///
243+
/// [`Clone`]: std::clone::Clone
244+
/// [`Send`]: std::marker::Send
245+
/// [`'static`]: https://doc.rust-lang.org/rust-by-example/scope/lifetime/static_lifetime.html#trait-bound
165246
pub fn with_state<State>(self, state: State) -> Handler<WithState<State, Service>> {
166247
let Self { service, parser } = self;
167248
Handler {
@@ -172,6 +253,9 @@ impl<Service> Handler<Service> {
172253
}
173254

174255
impl RequestParser {
256+
/// [イベントハンドラ](crate::Handler)に変換します。
257+
///
258+
/// **Note**: この関数は`tower`featureが有効になっている時のみ提供されます。
175259
pub fn into_handler(self) -> Handler<Sink> {
176260
Handler::new(self, Sink::new())
177261
}
@@ -181,9 +265,31 @@ macro_rules! all_handler_on_events {
181265
(
182266
$( $e:ident ),*
183267
) => {
184-
$crate::macros::handler_on_events! {
185-
$( pub $e; )*
186-
}
268+
$crate::macros::handler_on_events! { $(
269+
#[doc = paste! { concat!(
270+
"[`", stringify!([< $e:camel Payload >]), "`]をhandleする[`Service`]を登録します。\n\n",
271+
"引数の型`Service2`は`Service<Req>` traitを実装し、さらに以下の条件を満たす必要があります。\n\n",
272+
"- [`Clone`], [`Send`]を実装している\n",
273+
"- [`'static`]\n",
274+
"- `Req`が次のうちいずれかと等しい\n",
275+
" - [`", stringify!([< $e:camel Payload >]), "`]\n",
276+
" - `(", stringify!([< $e:camel Payload >]), ",)`\n",
277+
" - `(State, ", stringify!([< $e:camel Payload >]), ")` ",
278+
"(`State`に関しては[`Handler::with_state`]を参照してください)\n",
279+
"- `Service2::Response`が`()`と等しい\n",
280+
"- `Service2::Error`が<code>Into<Box<dyn [Error] + Send + Sync + &#39;static>></code>を実装している\n",
281+
"- `Service2::Future`が[`Send`]を実装している\n\n",
282+
"[`Service`]: tower::Service\n",
283+
"[`", stringify!([< $e:camel Payload >]), "`]: ",
284+
"crate::payloads::", stringify!([< $e:camel Payload >]), "\n",
285+
"[`Clone`]: std::clone::Clone\n",
286+
"[`Send`]: std::marker::Send\n",
287+
"[`'static`]: https://doc.rust-lang.org/rust-by-example/scope/lifetime/static_lifetime.html#trait-bound\n",
288+
"[`Handler::with_state`]: crate::Handler::with_state\n",
289+
"[Error]: std::error::Error\n",
290+
)}]
291+
pub $e;
292+
)* }
187293
};
188294
}
189295

src/lib.rs

+25-5
Original file line numberDiff line numberDiff line change
@@ -29,32 +29,52 @@ pub struct RequestParser {
2929
}
3030

3131
#[cfg(feature = "tower")]
32-
/// axumライクなhandler APIを提供します。[`handler`]モジュールのドキュメントも併せて読んでください
32+
/// イベントハンドラです
3333
///
3434
/// # Example
3535
///
3636
/// ```
37+
/// use std::convert::Infallible;
38+
///
3739
/// use tower::service_fn;
3840
/// use traq_bot_http::{payloads, RequestParser};
3941
///
40-
/// async fn on_ping((state, payload): (i32, payloads::PingPayload)) -> Result<(), std::convert::Infallible> {
42+
/// async fn on_ping((state, payload): (i32, payloads::PingPayload)) -> Result<(), Infallible> {
4143
/// println!("state: {state:?}, ping: {payload:?}");
4244
/// // assert_eq!(state, 0);
43-
/// Ok::<(), std::convert::Infallible>(())
45+
/// Ok(())
4446
/// }
4547
///
46-
/// let parser = RequestParser::new("traqbotverificationtoken");
48+
/// let parser = RequestParser::new("verification_token");
4749
/// let handler = parser
4850
/// .into_handler()
4951
/// .on_ping(service_fn(on_ping))
5052
/// .with_state(0i32);
5153
/// # let _ = handler;
5254
/// ```
5355
///
56+
/// # Composing Handler
57+
///
58+
/// [`Handler`] はメソッドチェーンにより構成されます。使用可能なメソッドは以下の通りです。
59+
///
60+
/// - [`.on_*<S>(S)`]
61+
/// - `*`には [`EventKind`] の variant が `snake_case` で入ります。
62+
/// - 例: [`Handler::on_message_created`]
63+
/// - [`.with_state<S>(S)`]
64+
///
65+
/// 適切に構成された [`Handler`] は [`Service`] trait を実装します。各メソッドのドキュメントを参照してください。
66+
///
67+
/// **[`Handler`] の構成時にはコンパイルエラーが出ない可能性があります** 。
68+
/// [`Service`] trait を使用するライブラリ (axum 等) の条件も確認してください。
69+
///
5470
/// # Note
55-
/// この構造体の型パラメータは**unstable**です。`Handler<T>`における`T`は予告なく変化する可能性があります。
71+
///
72+
/// この構造体の型パラメータは **unstable** です。`Handler<T>`における`T`は予告なく変化する可能性があります。
5673
///
5774
/// [`handler`]: crate::handler
75+
/// [`Service`]: tower::Service
76+
/// [`.on_*<S>(S)`]: crate::Handler::on_ping
77+
/// [`.with_state<S>(S)`]: crate::Handler::with_state
5878
#[must_use]
5979
#[derive(Debug, Clone)]
6080
pub struct Handler<Service> {

0 commit comments

Comments
 (0)