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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Handler metadata collected by the router and consumed by `ruststream-asyncapi`.
use std::{any::type_name, borrow::Cow, marker::PhantomData};
/// Descriptive metadata for a registered subscriber handler.
///
/// Collected by the router so downstream tools (`AsyncAPI` generator, dashboards, CLI) can
/// describe the service without re-parsing source code.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct HandlerMetadata {
/// Broker name / subject the handler is bound to.
pub name: Cow<'static, str>,
/// Optional broker-provided routing key, when the broker distinguishes from `name`.
pub routing_key: Option<Cow<'static, str>>,
/// Type name of the decoded input value, as captured at registration time.
pub input_type: &'static str,
/// Type name of the response value, when the handler produces one (e.g. request / reply).
pub output_type: Option<&'static str>,
/// Free-form human description, typically pulled from a doc comment on the handler.
pub description: Option<Cow<'static, str>>,
/// The input type's JSON Schema, serialized, when the type implements
/// [`schemars::JsonSchema`] (captured under the `asyncapi` feature). Feeds the `AsyncAPI`
/// message payload schema.
pub payload_schema: Option<String>,
/// The input type's [`Message`](crate::Message) name, when it implements that trait. Overrides
/// the `input_type`-derived name in the `AsyncAPI` document.
pub message_name: Option<Cow<'static, str>>,
/// The input type's [`Message`](crate::Message) description, when it implements that trait.
/// Feeds the `AsyncAPI` message description.
pub message_description: Option<Cow<'static, str>>,
}
impl HandlerMetadata {
/// Constructs metadata for a raw-bytes handler bound to a name.
#[must_use]
pub fn raw(name: impl Into<Cow<'static, str>>) -> Self {
Self {
name: name.into(),
routing_key: None,
input_type: "bytes",
output_type: None,
description: None,
payload_schema: None,
message_name: None,
message_description: None,
}
}
/// Constructs metadata for a typed handler. The input type name is captured via
/// [`std::any::type_name`].
#[must_use]
pub fn typed<T>(name: impl Into<Cow<'static, str>>) -> Self {
let _ = PhantomData::<T>;
Self {
name: name.into(),
routing_key: None,
input_type: type_name::<T>(),
output_type: None,
description: None,
payload_schema: None,
message_name: None,
message_description: None,
}
}
/// Builder-style setter for the handler description.
#[must_use]
pub fn with_description(mut self, description: impl Into<Cow<'static, str>>) -> Self {
self.description = Some(description.into());
self
}
/// Builder-style setter for the broker routing key.
#[must_use]
pub fn with_routing_key(mut self, key: impl Into<Cow<'static, str>>) -> Self {
self.routing_key = Some(key.into());
self
}
/// Builder-style setter for the response type name.
#[must_use]
pub fn with_output_type(mut self, name: &'static str) -> Self {
self.output_type = Some(name);
self
}
/// Builder-style setter for the serialized input payload schema.
#[must_use]
pub fn with_payload_schema(mut self, schema: impl Into<String>) -> Self {
self.payload_schema = Some(schema.into());
self
}
/// Builder-style setter for the [`Message`](crate::Message) name of the input type.
#[must_use]
pub fn with_message_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.message_name = Some(name.into());
self
}
/// Builder-style setter for the [`Message`](crate::Message) description of the input type.
#[must_use]
pub fn with_message_description(mut self, description: impl Into<Cow<'static, str>>) -> Self {
self.message_description = Some(description.into());
self
}
/// Attaches the optional descriptive fields that every generated definition trait exposes
/// with identical signatures (`description`, `input_schema`, `message_name`,
/// `message_description`). Shared tail of the per-definition metadata builders.
#[must_use]
pub(crate) fn with_def_details(
mut self,
description: Option<&str>,
input_schema: Option<String>,
message_name: Option<&'static str>,
message_description: Option<&'static str>,
) -> Self {
if let Some(description) = description {
self = self.with_description(description.to_owned());
}
if let Some(schema) = input_schema {
self = self.with_payload_schema(schema);
}
if let Some(name) = message_name {
self = self.with_message_name(name);
}
if let Some(description) = message_description {
self = self.with_message_description(description);
}
self
}
}