-
-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathgroup.rs
More file actions
86 lines (70 loc) · 2.2 KB
/
group.rs
File metadata and controls
86 lines (70 loc) · 2.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use std::{fmt, ops::Deref, str::FromStr, sync::LazyLock};
use regex::Regex;
use snafu::{Snafu, ensure};
const MAX_GROUP_LENGTH: usize = 253;
static API_GROUP_REGEX: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"^(?:(?:[a-z0-9][a-z0-9-]{0,61}[a-z0-9])\.?)+$")
.expect("failed to compile API group regex")
});
/// Error variants which can be encountered when creating a new [`Group`] from
/// unparsed input.
#[derive(Debug, PartialEq, Eq, Snafu)]
pub enum ParseGroupError {
#[snafu(display("group must not be empty"))]
Empty,
#[snafu(display("group must not be longer than 253 characters"))]
TooLong,
#[snafu(display("group must be a valid DNS subdomain"))]
InvalidFormat,
}
/// A validated Kubernetes group.
///
/// The group string must follow these rules:
///
/// - must be non-empty
/// - must only contain lower case characters
/// - and must be a valid DNS subdomain
///
/// ### See
///
/// - <https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#api-conventions>
#[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
pub struct Group(String);
impl FromStr for Group {
type Err = ParseGroupError;
fn from_str(group: &str) -> Result<Self, Self::Err> {
ensure!(!group.is_empty(), EmptySnafu);
ensure!(group.len() <= MAX_GROUP_LENGTH, TooLongSnafu);
ensure!(API_GROUP_REGEX.is_match(group), InvalidFormatSnafu);
Ok(Self(group.to_owned()))
}
}
impl fmt::Display for Group {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self)
}
}
impl Deref for Group {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "serde")]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deserialize() {
let _: Group = serde_yaml::from_str("extensions.k8s.io").expect("group is valid");
}
#[test]
fn serialize() {
let group = Group("extensions.k8s.io".into());
assert_eq!(
"extensions.k8s.io\n",
serde_yaml::to_string(&group).expect("group must serialize")
);
}
}