1use std::str::FromStr;
4
5use buffa::Enumeration;
6use serde::{Deserialize, Serialize};
7
8use crate::UnknownVariant;
9
10#[derive(
16 Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
17)]
18#[serde(rename_all = "snake_case")]
19#[repr(i32)]
20#[non_exhaustive]
21pub enum Severity {
22 #[default]
24 Unspecified = 0,
25 Trace = 1,
27 Debug = 2,
29 Info = 3,
31 Warn = 4,
33 Error = 5,
35 Fatal = 6,
37}
38
39impl Severity {
40 #[must_use]
42 pub const fn as_str(self) -> &'static str {
43 match self {
44 Self::Unspecified => "unspecified",
45 Self::Trace => "trace",
46 Self::Debug => "debug",
47 Self::Info => "info",
48 Self::Warn => "warn",
49 Self::Error => "error",
50 Self::Fatal => "fatal",
51 }
52 }
53
54 #[must_use]
59 pub const fn otlp_number(self) -> i32 {
60 match self {
61 Self::Unspecified => 0,
62 Self::Trace => 1,
63 Self::Debug => 5,
64 Self::Info => 9,
65 Self::Warn => 13,
66 Self::Error => 17,
67 Self::Fatal => 21,
68 }
69 }
70}
71
72impl Enumeration for Severity {
73 fn from_i32(value: i32) -> Option<Self> {
74 match value {
75 0 => Some(Self::Unspecified),
76 1 => Some(Self::Trace),
77 2 => Some(Self::Debug),
78 3 => Some(Self::Info),
79 4 => Some(Self::Warn),
80 5 => Some(Self::Error),
81 6 => Some(Self::Fatal),
82 _ => None,
83 }
84 }
85
86 fn to_i32(&self) -> i32 {
87 *self as i32
88 }
89
90 fn proto_name(&self) -> &'static str {
91 match self {
92 Self::Unspecified => "SEVERITY_UNSPECIFIED",
93 Self::Trace => "SEVERITY_TRACE",
94 Self::Debug => "SEVERITY_DEBUG",
95 Self::Info => "SEVERITY_INFO",
96 Self::Warn => "SEVERITY_WARN",
97 Self::Error => "SEVERITY_ERROR",
98 Self::Fatal => "SEVERITY_FATAL",
99 }
100 }
101
102 fn from_proto_name(name: &str) -> Option<Self> {
103 match name {
104 "SEVERITY_UNSPECIFIED" => Some(Self::Unspecified),
105 "SEVERITY_TRACE" => Some(Self::Trace),
106 "SEVERITY_DEBUG" => Some(Self::Debug),
107 "SEVERITY_INFO" => Some(Self::Info),
108 "SEVERITY_WARN" => Some(Self::Warn),
109 "SEVERITY_ERROR" => Some(Self::Error),
110 "SEVERITY_FATAL" => Some(Self::Fatal),
111 _ => None,
112 }
113 }
114
115 fn values() -> &'static [Self] {
116 &[
117 Self::Unspecified,
118 Self::Trace,
119 Self::Debug,
120 Self::Info,
121 Self::Warn,
122 Self::Error,
123 Self::Fatal,
124 ]
125 }
126}
127
128impl FromStr for Severity {
129 type Err = UnknownVariant;
130
131 fn from_str(s: &str) -> Result<Self, Self::Err> {
132 match s.to_ascii_lowercase().as_str() {
133 "trace" => Ok(Self::Trace),
134 "debug" => Ok(Self::Debug),
135 "info" => Ok(Self::Info),
136 "warn" | "warning" => Ok(Self::Warn),
137 "error" | "err" => Ok(Self::Error),
138 "fatal" => Ok(Self::Fatal),
139 _ => Err(UnknownVariant {
140 kind: "Severity",
141 value: s.to_string(),
142 }),
143 }
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn test_should_round_trip_via_i32() {
153 for v in Severity::values() {
154 assert_eq!(Severity::from_i32(v.to_i32()), Some(*v));
155 }
156 }
157
158 #[test]
159 fn test_should_order_correctly() {
160 assert!(Severity::Info < Severity::Warn);
161 assert!(Severity::Error < Severity::Fatal);
162 }
163
164 #[test]
165 fn test_should_map_otlp_numbers() {
166 assert_eq!(Severity::Info.otlp_number(), 9);
167 assert_eq!(Severity::Fatal.otlp_number(), 21);
168 }
169
170 #[test]
171 fn test_should_parse_aliases() {
172 assert_eq!("warning".parse::<Severity>().unwrap(), Severity::Warn);
173 assert_eq!("err".parse::<Severity>().unwrap(), Severity::Error);
174 }
175}