diidi_travel_common_error/
code.rs1use serde::{Deserialize, Serialize};
6use std::borrow::Cow;
7use std::fmt;
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(transparent)]
11pub struct ErrorCode(Cow<'static, str>);
12
13impl ErrorCode {
14 pub const fn from_static(code: &'static str) -> Self {
16 Self(Cow::Borrowed(code))
17 }
18
19 pub fn new(code: impl Into<String>) -> Self {
21 Self(Cow::Owned(code.into()))
22 }
23
24 pub fn as_str(&self) -> &str {
25 &self.0
26 }
27}
28
29impl fmt::Display for ErrorCode {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 f.write_str(&self.0)
32 }
33}
34
35impl From<&'static str> for ErrorCode {
36 fn from(s: &'static str) -> Self {
37 Self::from_static(s)
38 }
39}
40
41impl From<String> for ErrorCode {
42 fn from(s: String) -> Self {
43 Self::new(s)
44 }
45}
46
47pub const UNSPECIFIED: ErrorCode = ErrorCode::from_static("unspecified");
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn const_constructor_is_zero_alloc() {
56 const CODE: ErrorCode = ErrorCode::from_static("user.not_found");
57 assert_eq!(CODE.as_str(), "user.not_found");
58 }
59
60 #[test]
61 fn runtime_constructor_works() {
62 let code = ErrorCode::new(format!("user.{}", "not_found"));
63 assert_eq!(code.as_str(), "user.not_found");
64 }
65
66 #[test]
67 fn serializes_as_string() {
68 let code = ErrorCode::from_static("payment.declined");
69 let json = serde_json::to_string(&code).unwrap();
70 assert_eq!(json, "\"payment.declined\"");
71 let back: ErrorCode = serde_json::from_str(&json).unwrap();
72 assert_eq!(back, code);
73 }
74}