Skip to main content

ruststream_lapin/
context.rs

1//! Per-delivery context fields exposed to handlers.
2//!
3//! [`AmqpContext`] carries the AMQP delivery metadata that is not part of the payload or the
4//! headers. Request it in a handler by typing the context parameter as
5//! `Context<'_, AmqpContext>` and read individual fields with the zero-sized keys in [`keys`].
6
7use ruststream::{BuildContext, Field};
8
9use crate::message::LapinMessage;
10
11/// Native AMQP delivery metadata, built once per delivery.
12#[derive(Debug, Clone, Default, PartialEq, Eq)]
13pub struct AmqpContext {
14    exchange: String,
15    routing_key: String,
16    redelivered: bool,
17    delivery_tag: u64,
18}
19
20impl AmqpContext {
21    /// The exchange the message was published to (empty for the default exchange).
22    #[must_use]
23    pub fn exchange(&self) -> &str {
24        &self.exchange
25    }
26
27    /// The routing key the message was published with.
28    #[must_use]
29    pub fn routing_key(&self) -> &str {
30        &self.routing_key
31    }
32
33    /// Whether the broker marked the delivery as redelivered.
34    #[must_use]
35    pub fn redelivered(&self) -> bool {
36        self.redelivered
37    }
38
39    /// The channel-local delivery tag.
40    #[must_use]
41    pub fn delivery_tag(&self) -> u64 {
42        self.delivery_tag
43    }
44}
45
46impl BuildContext<LapinMessage> for AmqpContext {
47    fn build(msg: &LapinMessage) -> Self {
48        Self {
49            exchange: msg.exchange().to_owned(),
50            routing_key: msg.routing_key().to_owned(),
51            redelivered: msg.redelivered(),
52            delivery_tag: msg.delivery_tag(),
53        }
54    }
55}
56
57/// Zero-sized [`Field`] keys reading one [`AmqpContext`] field each.
58pub mod keys {
59    use super::{AmqpContext, Field};
60
61    /// Reads the source exchange name.
62    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
63    pub struct Exchange;
64
65    impl Field<AmqpContext> for Exchange {
66        type Value<'a> = &'a str;
67
68        fn get(self, src: &AmqpContext) -> &str {
69            src.exchange()
70        }
71    }
72
73    /// Reads the routing key.
74    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
75    pub struct RoutingKey;
76
77    impl Field<AmqpContext> for RoutingKey {
78        type Value<'a> = &'a str;
79
80        fn get(self, src: &AmqpContext) -> &str {
81            src.routing_key()
82        }
83    }
84
85    /// Reads the redelivered flag.
86    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
87    pub struct Redelivered;
88
89    impl Field<AmqpContext> for Redelivered {
90        type Value<'a> = bool;
91
92        fn get(self, src: &AmqpContext) -> bool {
93            src.redelivered()
94        }
95    }
96
97    /// Reads the channel-local delivery tag.
98    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
99    pub struct DeliveryTag;
100
101    impl Field<AmqpContext> for DeliveryTag {
102        type Value<'a> = u64;
103
104        fn get(self, src: &AmqpContext) -> u64 {
105            src.delivery_tag()
106        }
107    }
108}