photon_macros/lib.rs
1//! Proc macros for Photon pub/sub.
2//!
3//! ## Entry points
4//!
5//! - [`topic`] — typed publish/subscribe on a struct; submits a topic descriptor to inventory
6//! - [`subscribe`] — registers a handler; requires [`Photon::start_executor`](https://docs.rs/uf-photon/latest/photon/struct.Photon.html#method.start_executor) at boot
7//!
8//! Attribute tables: [`photon::config`](https://docs.rs/uf-photon/latest/photon/config/).
9//! Getting started: [declare topics](https://docs.rs/uf-photon/latest/photon/#3-declare-topics-and-handlers).
10
11#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
12use proc_macro::TokenStream;
13
14mod subscribe;
15mod topic;
16
17/// Marks a struct as a Photon topic, generating typed publish/subscribe APIs.
18///
19/// Registers a topic descriptor in Quark inventory. With
20/// [`PhotonBuilder::auto_registry`](https://docs.rs/uf-photon/latest/photon/struct.PhotonBuilder.html#method.auto_registry),
21/// the host discovers it at boot. Prefer `EventType { … }.publish_on(&photon)` with an explicit
22/// [`Photon`](https://docs.rs/uf-photon/latest/photon/struct.Photon.html) handle.
23///
24/// | Attribute | Purpose |
25/// |-----------|---------|
26/// | `name = "…"` | Topic stream name (required) |
27/// | `keyed_by = "field"` | Partition key field on the struct |
28/// | `shards = N` | Virtual shard count for consumer groups |
29///
30/// Full attribute reference: [`photon::config`](https://docs.rs/uf-photon/latest/photon/config/#photon-topic).
31/// Getting started: [Embedded](https://docs.rs/uf-photon/latest/photon/#embedded-one-binary).
32///
33/// # Usage
34///
35/// ```ignore
36/// use futures::StreamExt;
37/// use photon::{topic, Photon, SubscribeOpts};
38///
39/// #[topic(name = "user.notifications", keyed_by = "user_id")]
40/// pub struct NotificationPushed {
41/// pub user_id: String,
42/// }
43///
44/// # async fn demo(photon: &Photon) -> photon::Result<()> {
45/// NotificationPushed { user_id: "u1".into() }
46/// .publish_on(photon)
47/// .await?;
48///
49/// let mut stream = NotificationPushed::subscribe_on(
50/// photon,
51/// SubscribeOpts::default_ephemeral(),
52/// )
53/// .await?;
54/// if let Some(Ok(envelope)) = stream.next().await {
55/// let _ = envelope.payload.user_id;
56/// }
57/// # Ok(())
58/// # }
59/// ```
60#[proc_macro_attribute]
61pub fn topic(attr: TokenStream, item: TokenStream) -> TokenStream {
62 topic::topic_impl(attr, item)
63}
64
65/// Marks a function as a subscription handler registered via inventory.
66///
67/// The host must call
68/// [`Photon::start_executor`](https://docs.rs/uf-photon/latest/photon/struct.Photon.html#method.start_executor)
69/// (Embedded hosts and Brokered **workers**) so inventory-registered handlers run. Publishers that
70/// only emit events can omit the executor.
71///
72/// | Attribute | Purpose |
73/// |-----------|---------|
74/// | `topic = "…"` | Topic name to consume (required) |
75/// | `durable = "name"` | Checkpointed subscription name |
76/// | `group = "id"` | Consumer-group load balancing |
77///
78/// Full attribute reference: [`photon::config`](https://docs.rs/uf-photon/latest/photon/config/#photon-subscribe).
79/// Getting started: [Brokered worker](https://docs.rs/uf-photon/latest/photon/#worker-binary).
80///
81/// # Usage (v1 — `Box<dyn Actor>`)
82///
83/// ```ignore
84/// use photon::{topic, subscribe, Actor, Result};
85///
86/// #[topic(name = "user.notifications")]
87/// pub struct NotificationPushed {
88/// pub user_id: String,
89/// }
90///
91/// #[subscribe(topic = "user.notifications", durable = "push-worker")]
92/// async fn on_notification(
93/// _actor: Box<dyn Actor>,
94/// _event: NotificationPushed,
95/// ) -> Result<()> {
96/// Ok(())
97/// }
98/// ```
99///
100/// # Actor bindings (v2)
101///
102/// The first parameter must be a simple identifier typed as one of:
103///
104/// - `Box<dyn Actor>` — reconstruct as-is (v1)
105/// - `Arc<dyn Actor>` — `Arc::from(reconstruct()?)`
106/// - `Box<Concrete>` / `Arc<Concrete>` — downcast via `Actor::into_any`; failure maps to
107/// `PhotonError::Identity`
108///
109/// # Optional injectables (v2)
110///
111/// After `(actor, payload)` you may add trailing parameters detected by type path:
112///
113/// - `&Event` — transport event (metadata + raw JSON)
114/// - `HandlerCtx` — delivery metadata (`event_id`, `topic_name`, `topic_key`, `seq`)
115///
116/// Unknown trailing types are rejected at compile time.
117///
118/// The handler must be `async` and return `photon::Result<()>`. Runnable: `subscribe_v2`.
119#[proc_macro_attribute]
120pub fn subscribe(attr: TokenStream, item: TokenStream) -> TokenStream {
121 subscribe::subscribe_impl(attr, item)
122}