rlqt_lib/entry_metadata/
labels.rs

1// Copyright (C) 2025-2026 Michael S. Klishin and Contributors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14use bitflags::bitflags;
15use serde::de::{MapAccess, Visitor};
16use serde::ser::SerializeMap;
17use serde::{Deserialize, Deserializer, Serialize, Serializer};
18use std::fmt::{self, Formatter};
19
20/// Label name constants - single source of truth for label identifiers
21pub const LABEL_UNLABELLED: &str = "unlabelled";
22pub const LABEL_ERL_PROCESS_CRASH: &str = "erl_process_crash";
23pub const LABEL_UNDEFINED_FN: &str = "undefined_fn";
24pub const LABEL_PROCESS_STOPS: &str = "process_stops";
25pub const LABEL_RAFT: &str = "raft";
26pub const LABEL_ELECTIONS: &str = "elections";
27pub const LABEL_QUEUES: &str = "queues";
28pub const LABEL_AUTO_DELETE: &str = "auto_delete";
29pub const LABEL_EXCLUSIVE: &str = "exclusive";
30pub const LABEL_CHANNEL_EXCEPTIONS: &str = "channel_exceptions";
31pub const LABEL_DELETE: &str = "delete";
32pub const LABEL_QUEUE_FEDERATION: &str = "queue_federation";
33pub const LABEL_VIRTUAL_HOSTS: &str = "virtual_hosts";
34pub const LABEL_CONNECTIONS: &str = "connections";
35pub const LABEL_ACCESS_CONTROL: &str = "access_control";
36pub const LABEL_SHOVELS: &str = "shovels";
37pub const LABEL_CQ_STORES: &str = "cq_stores";
38pub const LABEL_DISCONNECTS: &str = "disconnects";
39pub const LABEL_FEDERATION: &str = "federation";
40pub const LABEL_DELETION_PROTECTION: &str = "deletion_protection";
41pub const LABEL_MULTILINE: &str = "multiline";
42pub const LABEL_STREAMS: &str = "streams";
43pub const LABEL_LIMITS: &str = "limits";
44pub const LABEL_WORKER_POOL: &str = "worker_pool";
45pub const LABEL_PEER_DISCOVERY_CLASSIC: &str = "peer_discovery:classic";
46pub const LABEL_PLUGINS: &str = "plugins";
47pub const LABEL_EXCHANGES: &str = "exchanges";
48pub const LABEL_STARTUP_BANNER: &str = "startup_banner";
49
50/// Array of all label names in the order they're defined
51pub const LABEL_NAMES: &[&str] = &[
52    LABEL_UNLABELLED,
53    LABEL_ERL_PROCESS_CRASH,
54    LABEL_UNDEFINED_FN,
55    LABEL_PROCESS_STOPS,
56    LABEL_RAFT,
57    LABEL_ELECTIONS,
58    LABEL_QUEUES,
59    LABEL_AUTO_DELETE,
60    LABEL_EXCLUSIVE,
61    LABEL_CHANNEL_EXCEPTIONS,
62    LABEL_DELETE,
63    LABEL_QUEUE_FEDERATION,
64    LABEL_VIRTUAL_HOSTS,
65    LABEL_CONNECTIONS,
66    LABEL_ACCESS_CONTROL,
67    LABEL_SHOVELS,
68    LABEL_CQ_STORES,
69    LABEL_DISCONNECTS,
70    LABEL_FEDERATION,
71    LABEL_DELETION_PROTECTION,
72    LABEL_MULTILINE,
73    LABEL_STREAMS,
74    LABEL_LIMITS,
75    LABEL_WORKER_POOL,
76    LABEL_PEER_DISCOVERY_CLASSIC,
77    LABEL_PLUGINS,
78    LABEL_EXCHANGES,
79    LABEL_STARTUP_BANNER,
80];
81
82bitflags! {
83    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
84    pub struct LogEntryLabels: u64 {
85        const UNLABELLED          = 1 << 0;
86        const ERL_PROCESS_CRASH   = 1 << 1;
87        const UNDEFINED_FN        = 1 << 2;
88        const PROCESS_STOPS       = 1 << 3;
89        const RAFT                = 1 << 4;
90        const ELECTIONS           = 1 << 5;
91        const QUEUES              = 1 << 6;
92        const AUTO_DELETE         = 1 << 7;
93        const EXCLUSIVE           = 1 << 8;
94        const CHANNEL_EXCEPTIONS  = 1 << 9;
95        const DELETE              = 1 << 10;
96        const QUEUE_FEDERATION    = 1 << 11;
97        const VIRTUAL_HOSTS       = 1 << 12;
98        const CONNECTIONS         = 1 << 13;
99        const ACCESS_CONTROL      = 1 << 14;
100        const SHOVELS             = 1 << 15;
101        const CQ_STORES           = 1 << 16;
102        const DISCONNECTS         = 1 << 17;
103        const FEDERATION          = 1 << 18;
104        const DELETION_PROTECTION = 1 << 19;
105        const MULTILINE           = 1 << 20;
106        const STREAMS             = 1 << 21;
107        const LIMITS              = 1 << 22;
108        const WORKER_POOL         = 1 << 23;
109        const PEER_DISCOVERY_CLASSIC = 1 << 24;
110        const PLUGINS             = 1 << 25;
111        const EXCHANGES           = 1 << 26;
112        const STARTUP_BANNER      = 1 << 27;
113    }
114}
115
116impl LogEntryLabels {
117    #[inline]
118    pub fn merge(&mut self, other: Self) {
119        *self |= other;
120    }
121}
122
123impl Serialize for LogEntryLabels {
124    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
125    where
126        S: Serializer,
127    {
128        let mut map = serializer.serialize_map(None)?;
129
130        if self.contains(Self::UNLABELLED) {
131            map.serialize_entry(LABEL_UNLABELLED, &true)?;
132        }
133        if self.contains(Self::ERL_PROCESS_CRASH) {
134            map.serialize_entry(LABEL_ERL_PROCESS_CRASH, &true)?;
135        }
136        if self.contains(Self::UNDEFINED_FN) {
137            map.serialize_entry(LABEL_UNDEFINED_FN, &true)?;
138        }
139        if self.contains(Self::PROCESS_STOPS) {
140            map.serialize_entry(LABEL_PROCESS_STOPS, &true)?;
141        }
142        if self.contains(Self::RAFT) {
143            map.serialize_entry(LABEL_RAFT, &true)?;
144        }
145        if self.contains(Self::ELECTIONS) {
146            map.serialize_entry(LABEL_ELECTIONS, &true)?;
147        }
148        if self.contains(Self::QUEUES) {
149            map.serialize_entry(LABEL_QUEUES, &true)?;
150        }
151        if self.contains(Self::AUTO_DELETE) {
152            map.serialize_entry(LABEL_AUTO_DELETE, &true)?;
153        }
154        if self.contains(Self::EXCLUSIVE) {
155            map.serialize_entry(LABEL_EXCLUSIVE, &true)?;
156        }
157        if self.contains(Self::CHANNEL_EXCEPTIONS) {
158            map.serialize_entry(LABEL_CHANNEL_EXCEPTIONS, &true)?;
159        }
160        if self.contains(Self::DELETE) {
161            map.serialize_entry(LABEL_DELETE, &true)?;
162        }
163        if self.contains(Self::QUEUE_FEDERATION) {
164            map.serialize_entry(LABEL_QUEUE_FEDERATION, &true)?;
165        }
166        if self.contains(Self::VIRTUAL_HOSTS) {
167            map.serialize_entry(LABEL_VIRTUAL_HOSTS, &true)?;
168        }
169        if self.contains(Self::CONNECTIONS) {
170            map.serialize_entry(LABEL_CONNECTIONS, &true)?;
171        }
172        if self.contains(Self::ACCESS_CONTROL) {
173            map.serialize_entry(LABEL_ACCESS_CONTROL, &true)?;
174        }
175        if self.contains(Self::SHOVELS) {
176            map.serialize_entry(LABEL_SHOVELS, &true)?;
177        }
178        if self.contains(Self::CQ_STORES) {
179            map.serialize_entry(LABEL_CQ_STORES, &true)?;
180        }
181        if self.contains(Self::DISCONNECTS) {
182            map.serialize_entry(LABEL_DISCONNECTS, &true)?;
183        }
184        if self.contains(Self::FEDERATION) {
185            map.serialize_entry(LABEL_FEDERATION, &true)?;
186        }
187        if self.contains(Self::DELETION_PROTECTION) {
188            map.serialize_entry(LABEL_DELETION_PROTECTION, &true)?;
189        }
190        if self.contains(Self::MULTILINE) {
191            map.serialize_entry(LABEL_MULTILINE, &true)?;
192        }
193        if self.contains(Self::STREAMS) {
194            map.serialize_entry(LABEL_STREAMS, &true)?;
195        }
196        if self.contains(Self::LIMITS) {
197            map.serialize_entry(LABEL_LIMITS, &true)?;
198        }
199        if self.contains(Self::WORKER_POOL) {
200            map.serialize_entry(LABEL_WORKER_POOL, &true)?;
201        }
202        if self.contains(Self::PEER_DISCOVERY_CLASSIC) {
203            map.serialize_entry(LABEL_PEER_DISCOVERY_CLASSIC, &true)?;
204        }
205        if self.contains(Self::PLUGINS) {
206            map.serialize_entry(LABEL_PLUGINS, &true)?;
207        }
208        if self.contains(Self::EXCHANGES) {
209            map.serialize_entry(LABEL_EXCHANGES, &true)?;
210        }
211        if self.contains(Self::STARTUP_BANNER) {
212            map.serialize_entry(LABEL_STARTUP_BANNER, &true)?;
213        }
214
215        map.end()
216    }
217}
218
219impl<'de> Deserialize<'de> for LogEntryLabels {
220    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
221    where
222        D: Deserializer<'de>,
223    {
224        struct LabelsVisitor;
225
226        impl<'de> Visitor<'de> for LabelsVisitor {
227            type Value = LogEntryLabels;
228
229            fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
230                formatter.write_str("a map of label flags")
231            }
232
233            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
234            where
235                A: MapAccess<'de>,
236            {
237                let mut labels = LogEntryLabels::empty();
238
239                while let Some(key) = map.next_key::<String>()? {
240                    let value: bool = map.next_value()?;
241                    if value {
242                        match key.as_str() {
243                            LABEL_UNLABELLED => labels |= LogEntryLabels::UNLABELLED,
244                            LABEL_ERL_PROCESS_CRASH => labels |= LogEntryLabels::ERL_PROCESS_CRASH,
245                            LABEL_UNDEFINED_FN => labels |= LogEntryLabels::UNDEFINED_FN,
246                            LABEL_PROCESS_STOPS => labels |= LogEntryLabels::PROCESS_STOPS,
247                            LABEL_RAFT => labels |= LogEntryLabels::RAFT,
248                            LABEL_ELECTIONS => labels |= LogEntryLabels::ELECTIONS,
249                            LABEL_QUEUES => labels |= LogEntryLabels::QUEUES,
250                            LABEL_AUTO_DELETE => labels |= LogEntryLabels::AUTO_DELETE,
251                            LABEL_EXCLUSIVE => labels |= LogEntryLabels::EXCLUSIVE,
252                            LABEL_CHANNEL_EXCEPTIONS => {
253                                labels |= LogEntryLabels::CHANNEL_EXCEPTIONS
254                            }
255                            LABEL_DELETE => labels |= LogEntryLabels::DELETE,
256                            LABEL_QUEUE_FEDERATION => labels |= LogEntryLabels::QUEUE_FEDERATION,
257                            LABEL_VIRTUAL_HOSTS => labels |= LogEntryLabels::VIRTUAL_HOSTS,
258                            LABEL_CONNECTIONS => labels |= LogEntryLabels::CONNECTIONS,
259                            LABEL_ACCESS_CONTROL => labels |= LogEntryLabels::ACCESS_CONTROL,
260                            LABEL_SHOVELS => labels |= LogEntryLabels::SHOVELS,
261                            LABEL_CQ_STORES => labels |= LogEntryLabels::CQ_STORES,
262                            LABEL_DISCONNECTS => labels |= LogEntryLabels::DISCONNECTS,
263                            LABEL_FEDERATION => labels |= LogEntryLabels::FEDERATION,
264                            LABEL_DELETION_PROTECTION => {
265                                labels |= LogEntryLabels::DELETION_PROTECTION
266                            }
267                            LABEL_MULTILINE => labels |= LogEntryLabels::MULTILINE,
268                            LABEL_STREAMS => labels |= LogEntryLabels::STREAMS,
269                            LABEL_LIMITS => labels |= LogEntryLabels::LIMITS,
270                            LABEL_WORKER_POOL => labels |= LogEntryLabels::WORKER_POOL,
271                            LABEL_PEER_DISCOVERY_CLASSIC => {
272                                labels |= LogEntryLabels::PEER_DISCOVERY_CLASSIC
273                            }
274                            LABEL_PLUGINS => labels |= LogEntryLabels::PLUGINS,
275                            LABEL_EXCHANGES => labels |= LogEntryLabels::EXCHANGES,
276                            LABEL_STARTUP_BANNER => labels |= LogEntryLabels::STARTUP_BANNER,
277                            _ => {}
278                        }
279                    }
280                }
281
282                Ok(labels)
283            }
284        }
285
286        deserializer.deserialize_map(LabelsVisitor)
287    }
288}