worker_macros/
lib.rs

1mod durable_object;
2mod event;
3mod send;
4
5use proc_macro::TokenStream;
6
7/// Integrate the struct with the Workers Runtime as Durable Object.\
8/// Requires the `DurableObject` trait with the durable_object attribute macro on the struct.
9///
10/// ## Example
11///
12/// ```rust
13/// #[durable_object]
14/// pub struct Chatroom {
15///     users: Vec<User>,
16///     messages: Vec<Message>,
17///     state: State,
18///     env: Env, // access `Env` across requests, use inside `fetch`
19/// }
20///
21/// impl DurableObject for Chatroom {
22///     fn new(state: State, env: Env) -> Self {
23///         Self {
24///             users: vec![],
25///             messages: vec![],
26///             state,
27///             env,
28///         }
29///     }
30///
31///     async fn fetch(&self, _req: Request) -> Result<Response> {
32///         // do some work when a worker makes a request to this DO
33///         Response::ok(&format!("{} active users.", self.users.len()))
34///     }
35/// }
36/// ```
37///
38/// ## Note
39///
40/// By default all durable object events are enabled.
41/// Arguments may be provided to the macro to only generate the desired events, and reduce the generated JS & Wasm output:
42///
43/// * `fetch`: simple `fetch` target
44/// * `alarm`: with [Alarms API](https://developers.cloudflare.com/durable-objects/examples/alarms-api/)
45/// * `websocket`: [WebSocket server](https://developers.cloudflare.com/durable-objects/examples/websocket-hibernation-server/)
46///
47/// ```rust
48/// #[durable_object(fetch)]
49/// pub struct Chatroom {
50///     users: Vec<User>,
51///     messages: Vec<Message>,
52///     state: State,
53///     env: Env, // access `Env` across requests, use inside `fetch`
54/// }
55/// ```
56#[proc_macro_attribute]
57pub fn durable_object(attr: TokenStream, item: TokenStream) -> TokenStream {
58    durable_object::expand_macro(attr.into(), item.into())
59        .unwrap_or_else(syn::Error::into_compile_error)
60        .into()
61}
62
63/// The `event` macro is used to denote a [Worker handler](https://developers.cloudflare.com/workers/runtime-apis/handlers/), essentially binding from
64/// the JS runtime to a Rust function.
65///
66/// As of right now, the following attributes are supported:
67/// * `fetch`: [Fetch Handler](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/)
68/// * `scheduled`: [Scheduled Handler](https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/)
69/// * `queue`: [Queue Handler](https://developers.cloudflare.com/queues/reference/javascript-apis/#consumer)
70///   * This attribute is only available when the `queue` feature is enabled.
71/// * `start`: merely creates a [wasm-bindgen start function](https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-rust-exports/start.html)
72/// * `respond_with_errors`: if this attribute is present, the function will return a `Response` object with a 500 status code and the status text of the error message, if an error occurs
73///
74/// The macro is expanded into a different function signature, depending on the attributes used
75///
76/// # Fetch
77///
78/// At a high-level, the `fetch` handler is used to handle incoming HTTP requests. The function signature for a `fetch` handler is conceptually something like:
79///  
80/// ```rust
81/// async fn fetch(req: impl From<web_sys::Request>, env: Env, ctx: Context) -> Result<impl Into<web_sys::Response>, impl Into<Box<dyn Error>>>
82/// ```
83///
84/// In other words, it takes some "request" object that can be derived *from* a `web_sys::Request` (into whatever concrete Request type you like),
85/// and returns some "response" object that can be converted *into* a `web_sys::Response` (from whatever concrete Response type you like).
86/// Error types can be any type that implements [`std::error::Error`].
87///
88/// In practice, the "request" and "response" objects are usually one of these concrete types, supported out of the box:
89///
90/// ### worker::{Request, Response}
91///
92/// ```rust
93/// #[event(fetch, respond_with_errors)]
94/// async fn main(req: worker::Request, env: Env, ctx: Context) -> Result<worker::Response> {
95///   worker::Response::ok("Hello World (worker type)")
96/// }
97/// ```
98///
99/// ### web_sys::{Request, Response}
100///
101/// ```rust
102/// #[event(fetch, respond_with_errors)]
103/// async fn main(req: web_sys::Request, env: Env, ctx: Context) -> Result<web_sys::Response> {
104///   Ok(web_sys::Response::new_with_opt_str(Some("Hello World (native type)".into())).unwrap())
105/// }
106/// ```
107///
108/// ### axum (with `http` feature)
109///
110/// ```rust
111///  #[event(fetch)]
112/// async fn fetch(req: HttpRequest, env: Env, ctx: Context) -> Result<http::Response<axum::body::Body>> {
113///   Ok(router().call(req).await?)
114/// }
115/// ```
116#[proc_macro_attribute]
117pub fn event(attr: TokenStream, item: TokenStream) -> TokenStream {
118    event::expand_macro(attr, item)
119}
120
121#[proc_macro_attribute]
122/// Convert an async function which is `!Send` to be `Send`.
123///
124/// This is useful for implementing async handlers in frameworks which
125/// expect the handler to be `Send`, such as `axum`.
126///
127/// ```rust
128/// #[worker::send]
129/// async fn foo() {
130///     // JsFuture is !Send
131///     let fut = JsFuture::from(promise);
132///     fut.await
133/// }
134/// ```
135pub fn send(attr: TokenStream, stream: TokenStream) -> TokenStream {
136    send::expand_macro(attr, stream)
137}
138
139#[doc(hidden)]
140#[proc_macro_attribute]
141pub fn consume(_: TokenStream, _: TokenStream) -> TokenStream {
142    TokenStream::new()
143}