cloud_sdk/operation/
operation_id.rs1use core::fmt;
4
5pub const MAX_OPERATION_ID_BYTES: usize = 128;
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum OperationIdError {
11 Empty,
13 TooLong,
15 InvalidByte,
17}
18
19impl fmt::Display for OperationIdError {
20 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
21 formatter.write_str(match self {
22 Self::Empty => "operation identifier is empty",
23 Self::TooLong => "operation identifier is too long",
24 Self::InvalidByte => "operation identifier contains an invalid byte",
25 })
26 }
27}
28
29impl core::error::Error for OperationIdError {}
30
31#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
33pub struct OperationId(&'static str);
34
35impl OperationId {
36 pub const fn new(value: &'static str) -> Result<Self, OperationIdError> {
38 if value.is_empty() {
39 return Err(OperationIdError::Empty);
40 }
41 if value.len() > MAX_OPERATION_ID_BYTES {
42 return Err(OperationIdError::TooLong);
43 }
44 let mut remaining = value.as_bytes();
45 while let Some((byte, tail)) = remaining.split_first() {
46 if !byte.is_ascii_lowercase() && !byte.is_ascii_digit() && *byte != b'_' {
47 return Err(OperationIdError::InvalidByte);
48 }
49 remaining = tail;
50 }
51 Ok(Self(value))
52 }
53
54 #[must_use]
56 pub const fn as_str(self) -> &'static str {
57 self.0
58 }
59}
60
61#[macro_export]
71macro_rules! operation_id {
72 ($value:literal) => {{
73 const VALUE: $crate::operation::OperationId =
74 match $crate::operation::OperationId::new($value) {
75 Ok(value) => value,
76 Err(_) => panic!("invalid operation identifier literal"),
77 };
78 VALUE
79 }};
80}
81
82#[cfg(test)]
83mod tests {
84 use super::{OperationId, OperationIdError};
85
86 const GET_SERVER: OperationId = operation_id!("get_server");
87
88 #[test]
89 fn accepts_source_style_identifiers_and_rejects_ambiguous_text() {
90 assert_eq!(GET_SERVER.as_str(), "get_server");
91 assert_eq!(
92 OperationId::new("get_server").map(OperationId::as_str),
93 Ok("get_server")
94 );
95 assert_eq!(OperationId::new(""), Err(OperationIdError::Empty));
96 assert_eq!(
97 OperationId::new("Get-Server"),
98 Err(OperationIdError::InvalidByte)
99 );
100 }
101}