@@ -13,13 +13,29 @@ use std::task::{Context, Poll};
13
13
use futures:: future:: { BoxFuture , Ready as ReadyFuture } ;
14
14
use futures:: ready;
15
15
use http:: { Request , Response , StatusCode } ;
16
+ use paste:: paste;
16
17
use tower:: Service ;
17
18
18
19
use super :: Handler ;
19
20
use crate :: macros:: all_events;
20
21
use crate :: { Error , Event , RequestParser } ;
21
22
22
23
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
23
39
#[ must_use]
24
40
#[ project = WrapErrorFutureProject ]
25
41
#[ derive( Debug ) ]
44
60
}
45
61
}
46
62
63
+ /// handleされなかった[`Event`]の受け皿となる[`Service`]です。
64
+ ///
65
+ /// [`Event`]: crate::Event
66
+ /// [`Service`]: tower::Service
47
67
#[ must_use]
48
68
#[ derive( Debug , Clone , Copy , Default , Hash ) ]
49
69
pub struct Sink {
70
+ // ユーザーが直接構築できないように
50
71
_priv : PhantomData < ( ) > ,
51
72
}
52
73
@@ -70,6 +91,9 @@ impl<T> Service<T> for Sink {
70
91
}
71
92
}
72
93
94
+ /// [`Event`]と`State`の直積です。
95
+ ///
96
+ /// [`Event`]: crate::Event
73
97
#[ must_use]
74
98
#[ derive( Debug , Clone ) ]
75
99
pub struct EventWithState < State > {
@@ -90,6 +114,12 @@ impl<State> From<EventWithState<State>> for (State, Event) {
90
114
}
91
115
}
92
116
117
+ /// 内部の`Service`に`State`を渡す[`Service`]です。
118
+ ///
119
+ /// `WithState::call`の度に`State`がcloneされるため、`State`は[`Clone`]を実装する必要があります。
120
+ ///
121
+ /// [`Service`]: tower::Service
122
+ /// [`Clone`]: std::clone::Clone
93
123
#[ must_use]
94
124
#[ derive( Debug , Clone ) ]
95
125
pub struct WithState < State , Service > {
@@ -145,23 +175,74 @@ macro_rules! all_event_service {
145
175
(
146
176
$( $e: ident ) ,*
147
177
) => {
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
+ } ) *
155
189
} ;
156
190
}
157
191
158
192
all_events ! { all_event_service}
159
193
160
194
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] + '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
161
211
pub fn new ( parser : crate :: RequestParser , service : Service ) -> Self {
162
212
Self { service, parser }
163
213
}
164
214
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
165
246
pub fn with_state < State > ( self , state : State ) -> Handler < WithState < State , Service > > {
166
247
let Self { service, parser } = self ;
167
248
Handler {
@@ -172,6 +253,9 @@ impl<Service> Handler<Service> {
172
253
}
173
254
174
255
impl RequestParser {
256
+ /// [イベントハンドラ](crate::Handler)に変換します。
257
+ ///
258
+ /// **Note**: この関数は`tower`featureが有効になっている時のみ提供されます。
175
259
pub fn into_handler ( self ) -> Handler < Sink > {
176
260
Handler :: new ( self , Sink :: new ( ) )
177
261
}
@@ -181,9 +265,31 @@ macro_rules! all_handler_on_events {
181
265
(
182
266
$( $e: ident ) ,*
183
267
) => {
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 + '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
+ ) * }
187
293
} ;
188
294
}
189
295
0 commit comments