pgtask_core/
identifier.rs1use std::{fmt, num::NonZeroU32, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4use thiserror::Error;
5use uuid::Uuid;
6
7const MAX_QUEUE_NAME_BYTES: usize = 128;
8const MAX_TASK_NAME_BYTES: usize = 255;
9
10#[derive(Clone, Debug, Error, Eq, PartialEq)]
11pub enum NameError {
12 #[error("{kind} must not be empty")]
13 Empty { kind: &'static str },
14 #[error("{kind} must be at most {maximum} bytes, got {actual}")]
15 TooLong {
16 kind: &'static str,
17 maximum: usize,
18 actual: usize,
19 },
20 #[error("{kind} contains unsupported character {character:?}")]
21 UnsupportedCharacter { kind: &'static str, character: char },
22}
23
24fn validate_name(value: &str, kind: &'static str, maximum: usize) -> Result<(), NameError> {
25 if value.is_empty() {
26 return Err(NameError::Empty { kind });
27 }
28 if value.len() > maximum {
29 return Err(NameError::TooLong {
30 kind,
31 maximum,
32 actual: value.len(),
33 });
34 }
35 if let Some(character) = value
36 .chars()
37 .find(|character| !(character.is_ascii_alphanumeric() || matches!(character, '.' | '_' | ':' | '-')))
38 {
39 return Err(NameError::UnsupportedCharacter { kind, character });
40 }
41 Ok(())
42}
43
44macro_rules! name_type {
45 ($name:ident, $kind:literal, $maximum:expr) => {
46 #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
47 #[serde(try_from = "String", into = "String")]
48 pub struct $name(String);
49
50 impl $name {
51 pub fn new(value: impl Into<String>) -> Result<Self, NameError> {
52 let value = value.into();
53 validate_name(&value, $kind, $maximum)?;
54 Ok(Self(value))
55 }
56
57 pub fn as_str(&self) -> &str {
58 &self.0
59 }
60 }
61
62 impl AsRef<str> for $name {
63 fn as_ref(&self) -> &str {
64 self.as_str()
65 }
66 }
67
68 impl fmt::Display for $name {
69 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
70 formatter.write_str(self.as_str())
71 }
72 }
73
74 impl TryFrom<String> for $name {
75 type Error = NameError;
76
77 fn try_from(value: String) -> Result<Self, Self::Error> {
78 Self::new(value)
79 }
80 }
81
82 impl From<$name> for String {
83 fn from(value: $name) -> Self {
84 value.0
85 }
86 }
87 };
88}
89
90name_type!(QueueName, "queue name", MAX_QUEUE_NAME_BYTES);
91name_type!(ScheduleName, "schedule name", MAX_TASK_NAME_BYTES);
92name_type!(SignalName, "signal name", MAX_TASK_NAME_BYTES);
93name_type!(StepName, "step name", MAX_TASK_NAME_BYTES);
94name_type!(TaskName, "task name", MAX_TASK_NAME_BYTES);
95
96impl Default for QueueName {
97 fn default() -> Self {
98 Self("default".to_owned())
99 }
100}
101
102macro_rules! uuid_type {
103 ($name:ident) => {
104 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
105 #[serde(transparent)]
106 pub struct $name(Uuid);
107
108 impl $name {
109 pub fn new() -> Self {
110 Self(Uuid::now_v7())
111 }
112
113 pub const fn from_uuid(value: Uuid) -> Self {
114 Self(value)
115 }
116
117 pub const fn as_uuid(self) -> Uuid {
118 self.0
119 }
120 }
121
122 impl Default for $name {
123 fn default() -> Self {
124 Self::new()
125 }
126 }
127
128 impl fmt::Display for $name {
129 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
130 self.0.fmt(formatter)
131 }
132 }
133
134 impl FromStr for $name {
135 type Err = uuid::Error;
136
137 fn from_str(value: &str) -> Result<Self, Self::Err> {
138 Uuid::parse_str(value).map(Self)
139 }
140 }
141
142 impl From<$name> for Uuid {
143 fn from(value: $name) -> Self {
144 value.0
145 }
146 }
147 };
148}
149
150uuid_type!(TaskId);
151uuid_type!(ScheduleId);
152uuid_type!(WorkerId);
153uuid_type!(LeaseToken);
154
155#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
156#[serde(transparent)]
157pub struct HandlerVersion(NonZeroU32);
158
159impl HandlerVersion {
160 pub const fn new(value: NonZeroU32) -> Self {
161 Self(value)
162 }
163
164 pub const fn get(self) -> u32 {
165 self.0.get()
166 }
167}
168
169impl Default for HandlerVersion {
170 fn default() -> Self {
171 Self(NonZeroU32::MIN)
172 }
173}