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}