Skip to main content

ckb_sentry_types/
project_id.rs

1use std::convert::TryFrom;
2use std::fmt;
3use std::str::FromStr;
4
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7
8/// Raised if a project ID cannot be parsed from a string.
9#[derive(Debug, Error, PartialEq, Eq, PartialOrd, Ord)]
10pub enum ParseProjectIdError {
11    /// Raised if the value is not an integer in the supported range.
12    #[error("invalid value for project id")]
13    InvalidValue,
14    /// Raised if an empty value is parsed.
15    #[error("empty or missing project id")]
16    EmptyValue,
17}
18
19/// Represents a project ID.
20#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Deserialize, Serialize)]
21pub struct ProjectId(u64);
22
23impl ProjectId {
24    /// Creates a new project ID from its numeric value.
25    #[inline]
26    pub fn new(id: u64) -> Self {
27        Self(id)
28    }
29
30    /// Returns the numeric value of this project id.
31    #[inline]
32    pub fn value(self) -> u64 {
33        self.0
34    }
35}
36
37impl fmt::Display for ProjectId {
38    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39        write!(f, "{}", self.value())
40    }
41}
42
43macro_rules! impl_from {
44    ($ty:ty) => {
45        impl From<$ty> for ProjectId {
46            #[inline]
47            fn from(val: $ty) -> Self {
48                Self::new(val as u64)
49            }
50        }
51    };
52}
53
54impl_from!(u8);
55impl_from!(u16);
56impl_from!(u32);
57impl_from!(u64);
58
59macro_rules! impl_try_from {
60    ($ty:ty) => {
61        impl TryFrom<$ty> for ProjectId {
62            type Error = ParseProjectIdError;
63
64            #[inline]
65            fn try_from(val: $ty) -> Result<Self, Self::Error> {
66                match u64::try_from(val) {
67                    Ok(id) => Ok(Self::new(id)),
68                    Err(_) => Err(ParseProjectIdError::InvalidValue),
69                }
70            }
71        }
72    };
73}
74
75impl_try_from!(usize);
76impl_try_from!(i8);
77impl_try_from!(i16);
78impl_try_from!(i32);
79impl_try_from!(i64);
80
81impl FromStr for ProjectId {
82    type Err = ParseProjectIdError;
83
84    fn from_str(s: &str) -> Result<ProjectId, ParseProjectIdError> {
85        if s.is_empty() {
86            return Err(ParseProjectIdError::EmptyValue);
87        }
88
89        match s.parse::<u64>() {
90            Ok(val) => Ok(ProjectId::new(val)),
91            Err(_) => Err(ParseProjectIdError::InvalidValue),
92        }
93    }
94}
95
96#[cfg(test)]
97mod test {
98    use super::*;
99
100    #[test]
101    fn test_basic_api() {
102        let id: ProjectId = "42".parse().unwrap();
103        assert_eq!(id, ProjectId::new(42));
104        assert_eq!(
105            "42xxx".parse::<ProjectId>(),
106            Err(ParseProjectIdError::InvalidValue)
107        );
108        assert_eq!(
109            "".parse::<ProjectId>(),
110            Err(ParseProjectIdError::EmptyValue)
111        );
112        assert_eq!(ProjectId::new(42).to_string(), "42");
113
114        assert_eq!(serde_json::to_string(&ProjectId::new(42)).unwrap(), "42");
115        assert_eq!(
116            serde_json::from_str::<ProjectId>("42").unwrap(),
117            ProjectId::new(42)
118        );
119    }
120}