1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//! Topic descriptor for auto-registration.
use serde_json::Value;
use crate::delivery_mode::{DeliveryMode, ShardConfig};
/// Descriptor for a registered topic (from `#[photon::topic]` macro).
///
/// Used for runtime lookup and schema metadata.
#[derive(Debug, Clone)]
pub struct TopicDescriptor {
/// Stable topic name (e.g., "user.notifications").
pub topic_name: &'static str,
/// Optional key field name.
pub keyed_by: Option<&'static str>,
/// Reserved JSON schema metadata placeholder.
///
/// Currently always `"{}"` from `#[photon::topic]`. **Not validated** at publish time;
/// do not infer schema enforcement from this field.
pub schema_json: &'static str,
/// Publish routing mode (broadcast default).
pub delivery: DeliveryMode,
/// Virtual shard settings when [`DeliveryMode::ConsumerGroup`].
pub shard_config: Option<ShardConfig>,
}
impl TopicDescriptor {
/// Create a broadcast topic descriptor (default delivery mode).
#[must_use]
pub const fn new(
topic_name: &'static str,
keyed_by: Option<&'static str>,
schema_json: &'static str,
) -> Self {
Self {
topic_name,
keyed_by,
schema_json,
delivery: DeliveryMode::Broadcast,
shard_config: None,
}
}
/// Create a consumer-group topic with virtual shard routing.
#[must_use]
pub const fn group(
topic_name: &'static str,
shard_count: u32,
shard_by: Option<&'static str>,
schema_json: &'static str,
) -> Self {
Self {
topic_name,
keyed_by: None,
schema_json,
delivery: DeliveryMode::ConsumerGroup,
shard_config: Some(ShardConfig::new(shard_count, shard_by)),
}
}
/// Whether publishes route to virtual shard streams.
#[must_use]
pub fn is_consumer_group(&self) -> bool {
self.delivery == DeliveryMode::ConsumerGroup
}
/// Get schema as parsed JSON.
#[must_use]
pub fn schema_value(&self) -> Option<Value> {
serde_json::from_str(self.schema_json).ok()
}
}
// Register with inventory for auto-collection
crate::inventory::collect!(TopicDescriptor);
impl quark::Registrable for TopicDescriptor {
fn registry_key(&self) -> &str {
self.topic_name
}
}