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/// * `connect`: [TCP Socket Connect Handler](https://developers.cloudflare.com/workers/runtime-apis/tcp-sockets/)
72/// * `start`: merely creates a [wasm-bindgen start function](https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-rust-exports/start.html)
73/// * `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
74///
75/// The macro is expanded into a different function signature, depending on the attributes used
76///
77/// # Fetch
78///
79/// 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:
80///
81/// ```rust
82/// async fn fetch(req: impl From<web_sys::Request>, env: Env, ctx: Context) -> Result<impl Into<web_sys::Response>, impl Into<Box<dyn Error>>>
83/// ```
84///
85/// In other words, it takes some "request" object that can be derived *from* a `web_sys::Request` (into whatever concrete Request type you like),
86/// and returns some "response" object that can be converted *into* a `web_sys::Response` (from whatever concrete Response type you like).
87/// Error types can be any type that implements [`std::error::Error`].
88///
89/// In practice, the "request" and "response" objects are usually one of these concrete types, supported out of the box:
90///
91/// ### worker::{Request, Response}
92///
93/// ```rust
94/// #[event(fetch, respond_with_errors)]
95/// async fn main(req: worker::Request, env: Env, ctx: Context) -> Result<worker::Response> {
96/// worker::Response::ok("Hello World (worker type)")
97/// }
98/// ```
99///
100/// ### web_sys::{Request, Response}
101///
102/// ```rust
103/// #[event(fetch, respond_with_errors)]
104/// async fn main(req: web_sys::Request, env: Env, ctx: Context) -> Result<web_sys::Response> {
105/// Ok(web_sys::Response::new_with_opt_str(Some("Hello World (native type)".into())).unwrap())
106/// }
107/// ```
108///
109/// ### axum (with `http` feature)
110///
111/// ```rust
112/// #[event(fetch)]
113/// async fn fetch(req: HttpRequest, env: Env, ctx: Context) -> Result<http::Response<axum::body::Body>> {
114/// Ok(router().call(req).await?)
115/// }
116/// ```
117#[proc_macro_attribute]
118pub fn event(attr: TokenStream, item: TokenStream) -> TokenStream {
119 event::expand_macro(attr, item)
120}
121
122#[proc_macro_attribute]
123/// Convert an async function which is `!Send` to be `Send`.
124///
125/// This is useful for implementing async handlers in frameworks which
126/// expect the handler to be `Send`, such as `axum`.
127///
128/// ```rust
129/// #[worker::send]
130/// async fn foo() {
131/// // JsFuture is !Send
132/// let fut = JsFuture::from(promise);
133/// fut.await
134/// }
135/// ```
136pub fn send(attr: TokenStream, stream: TokenStream) -> TokenStream {
137 send::expand_macro(attr, stream)
138}
139
140#[doc(hidden)]
141#[proc_macro_attribute]
142pub fn consume(_: TokenStream, _: TokenStream) -> TokenStream {
143 TokenStream::new()
144}