1use serde::Serializer;
2use std::str::FromStr;
3
4#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
6#[serde(rename_all = "camelCase")]
7pub struct ProjectTeam {
8 project_number: String,
10 team: Team,
12}
13
14#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
16#[serde(rename_all = "lowercase")]
17pub enum Team {
18 Editors,
20 Owners,
22 Viewers,
24}
25
26impl std::fmt::Display for Team {
27 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
28 match self {
29 Team::Editors => write!(f, "editors"),
30 Team::Owners => write!(f, "owners"),
31 Team::Viewers => write!(f, "viewers"),
32 }
33 }
34}
35
36impl FromStr for Team {
37 type Err = String;
38
39 fn from_str(s: &str) -> Result<Self, Self::Err> {
40 match s {
41 "editors" => Ok(Self::Editors),
42 "owners" => Ok(Self::Owners),
43 "viewers" => Ok(Self::Viewers),
44 _ => Err(format!("Invalid `Team`: {}", s)),
45 }
46 }
47}
48
49#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
51#[serde(rename_all = "UPPERCASE")]
52pub enum Role {
53 Owner,
55 Writer,
57 Reader,
59}
60
61#[derive(Debug, serde::Deserialize)]
62#[serde(rename_all = "camelCase")]
63pub(crate) struct ListResponse<T> {
64 #[serde(default = "Vec::new")]
65 pub items: Vec<T>,
66 }
68
69#[derive(Debug, PartialEq, Clone)]
71pub enum Entity {
72 UserId(String),
74 UserEmail(String),
76 GroupId(String),
78 GroupEmail(String),
80 Domain(String),
83 Project(Team, String),
85 AllUsers,
87 AllAuthenticatedUsers,
89}
90
91use Entity::*;
92
93impl std::fmt::Display for Entity {
94 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
95 match self {
96 UserId(s) => write!(f, "user-{}", s),
97 UserEmail(s) => write!(f, "user-{}", s),
98 GroupId(s) => write!(f, "group-{}", s),
99 GroupEmail(s) => write!(f, "group-{}", s),
100 Domain(s) => write!(f, "domain-{}", s),
101 Project(team, project_id) => write!(f, "project-{}-{}", team, project_id),
102 AllUsers => write!(f, "allUsers"),
103 AllAuthenticatedUsers => write!(f, "allAuthenticatedUsers"),
104 }
105 }
106}
107
108impl serde::Serialize for Entity {
109 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
110 where
111 S: Serializer,
112 {
113 serializer.serialize_str(&format!("{}", self))
114 }
115}
116
117struct EntityVisitor;
118
119impl<'de> serde::de::Visitor<'de> for EntityVisitor {
120 type Value = Entity;
121
122 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
123 f.write_str("an `Entity` resource")
124 }
125
126 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
127 where
128 E: serde::de::Error,
129 {
130 let parts: Vec<&str> = value.split('-').collect();
131 let result = match &parts[..] {
132 ["user", rest @ ..] if is_email(rest) => UserEmail(rest.join("-")),
133 ["user", rest @ ..] => UserId(rest.join("-")),
134 ["group", rest @ ..] if is_email(rest) => GroupEmail(rest.join("-")),
135 ["group", rest @ ..] => GroupId(rest.join("-")),
136 ["domain", rest @ ..] => Domain(rest.join("-")),
137 ["project", team, project_id] => {
138 Project(Team::from_str(team).unwrap(), project_id.to_string())
139 }
140 ["allUsers"] => AllUsers,
141 ["allAuthenticatedUsers"] => AllAuthenticatedUsers,
142 _ => return Err(E::custom(format!("Unexpected `Entity`: {}", value))),
143 };
144 Ok(result)
145 }
146}
147
148fn is_email(pattern: &[&str]) -> bool {
149 pattern.iter().any(|s| s.contains('@'))
150}
151
152impl<'de> serde::Deserialize<'de> for Entity {
153 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
154 where
155 D: serde::Deserializer<'de>,
156 {
157 deserializer.deserialize_str(EntityVisitor)
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn serialize() {
167 let entity1 = UserId("some id".to_string());
168 assert_eq!(serde_json::to_string(&entity1).unwrap(), "\"user-some id\"");
169
170 let entity2 = UserEmail("some@email".to_string());
171 assert_eq!(
172 serde_json::to_string(&entity2).unwrap(),
173 "\"user-some@email\""
174 );
175
176 let entity3 = GroupId("some group id".to_string());
177 assert_eq!(
178 serde_json::to_string(&entity3).unwrap(),
179 "\"group-some group id\""
180 );
181
182 let entity4 = GroupEmail("some@group.email".to_string());
183 assert_eq!(
184 serde_json::to_string(&entity4).unwrap(),
185 "\"group-some@group.email\""
186 );
187
188 let entity5 = Domain("example.com".to_string());
189 assert_eq!(
190 serde_json::to_string(&entity5).unwrap(),
191 "\"domain-example.com\""
192 );
193
194 let entity6 = Project(Team::Viewers, "project id".to_string());
195 assert_eq!(
196 serde_json::to_string(&entity6).unwrap(),
197 "\"project-viewers-project id\""
198 );
199
200 let entity7 = AllUsers;
201 assert_eq!(serde_json::to_string(&entity7).unwrap(), "\"allUsers\"");
202
203 let entity8 = AllAuthenticatedUsers;
204 assert_eq!(
205 serde_json::to_string(&entity8).unwrap(),
206 "\"allAuthenticatedUsers\""
207 );
208 }
209
210 #[test]
211 fn deserialize() {
212 let str1 = "\"user-some id\"";
213 assert_eq!(
214 serde_json::from_str::<Entity>(str1).unwrap(),
215 UserId("some id".to_string())
216 );
217
218 let str2 = "\"user-some@email\"";
219 assert_eq!(
220 serde_json::from_str::<Entity>(str2).unwrap(),
221 UserEmail("some@email".to_string())
222 );
223
224 let str3 = "\"group-some group id\"";
225 assert_eq!(
226 serde_json::from_str::<Entity>(str3).unwrap(),
227 GroupId("some group id".to_string())
228 );
229
230 let str4 = "\"group-some@group.email\"";
231 assert_eq!(
232 serde_json::from_str::<Entity>(str4).unwrap(),
233 GroupEmail("some@group.email".to_string())
234 );
235
236 let str5 = "\"domain-example.com\"";
237 assert_eq!(
238 serde_json::from_str::<Entity>(str5).unwrap(),
239 Domain("example.com".to_string())
240 );
241
242 let str6 = "\"project-viewers-project id\"";
243 assert_eq!(
244 serde_json::from_str::<Entity>(str6).unwrap(),
245 Project(Team::Viewers, "project id".to_string())
246 );
247
248 let str7 = "\"allUsers\"";
249 assert_eq!(serde_json::from_str::<Entity>(str7).unwrap(), AllUsers);
250
251 let str8 = "\"allAuthenticatedUsers\"";
252 assert_eq!(
253 serde_json::from_str::<Entity>(str8).unwrap(),
254 AllAuthenticatedUsers
255 );
256 }
257}