1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::{fmt, str::FromStr};
5use std::error::Error;
6
7#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
9pub enum ThreadIdLabel {
10 Label(String),
12 Number(u64),
14}
15
16impl ThreadIdLabel {
17 pub fn label(value: impl AsRef<str>) -> Result<Self, ThreadIdLabelError> {
23 let trimmed = value.as_ref().trim();
24
25 if trimmed.is_empty() {
26 return Err(ThreadIdLabelError::Empty);
27 }
28
29 Ok(Self::Label(trimmed.to_string()))
30 }
31
32 #[must_use]
34 pub const fn number(value: u64) -> Self {
35 Self::Number(value)
36 }
37
38 #[must_use]
40 pub fn as_label(&self) -> Option<&str> {
41 match self {
42 Self::Label(value) => Some(value),
43 Self::Number(_) => None,
44 }
45 }
46
47 #[must_use]
49 pub const fn as_number(&self) -> Option<u64> {
50 match self {
51 Self::Label(_) => None,
52 Self::Number(value) => Some(*value),
53 }
54 }
55}
56
57impl fmt::Display for ThreadIdLabel {
58 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
59 match self {
60 Self::Label(value) => formatter.write_str(value),
61 Self::Number(value) => value.fmt(formatter),
62 }
63 }
64}
65
66impl FromStr for ThreadIdLabel {
67 type Err = ThreadIdLabelError;
68
69 fn from_str(value: &str) -> Result<Self, Self::Err> {
70 Self::label(value)
71 }
72}
73
74#[derive(Clone, Copy, Debug, Eq, PartialEq)]
76pub enum ThreadIdLabelError {
77 Empty,
79}
80
81impl fmt::Display for ThreadIdLabelError {
82 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
83 match self {
84 Self::Empty => formatter.write_str("thread ID label cannot be empty"),
85 }
86 }
87}
88
89impl Error for ThreadIdLabelError {}
90
91#[cfg(test)]
92mod tests {
93 use super::{ThreadIdLabel, ThreadIdLabelError};
94
95 #[test]
96 fn accepts_non_empty_labels() {
97 let label = ThreadIdLabel::label(" worker-1 ").unwrap();
98
99 assert_eq!(label.as_label(), Some("worker-1"));
100 assert_eq!(label.to_string(), "worker-1");
101 }
102
103 #[test]
104 fn rejects_empty_labels() {
105 assert_eq!(ThreadIdLabel::label(" "), Err(ThreadIdLabelError::Empty));
106 }
107
108 #[test]
109 fn stores_numeric_identifiers() {
110 let label = ThreadIdLabel::number(12);
111
112 assert_eq!(label.as_number(), Some(12));
113 assert_eq!(label.to_string(), "12");
114 }
115}