1use initiative_macros::WordList;
2use serde::{Deserialize, Serialize};
3use std::fmt;
4
5#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, WordList)]
6#[serde(into = "&'static str", try_from = "&str")]
7pub enum Gender {
8 #[alias = "female"]
9 #[alias = "woman"]
10 #[alias = "girl"]
11 Feminine,
12
13 #[alias = "male"]
14 #[alias = "man"]
15 #[alias = "boy"]
16 Masculine,
17
18 Neuter,
19
20 #[term = "non-binary"]
21 #[alias = "enby"]
22 #[alias = "nb"]
23 NonBinaryThey,
24}
25
26impl Gender {
27 pub fn name(&self) -> &'static str {
28 match self {
29 Self::Feminine => "feminine",
30 Self::Masculine => "masculine",
31 Self::Neuter => "neuter",
32 Self::NonBinaryThey => "non-binary",
33 }
34 }
35
36 pub fn pronouns(&self) -> &'static str {
37 match self {
38 Self::Feminine => "she/her",
39 Self::Masculine => "he/him",
40 Self::Neuter => "it",
41 Self::NonBinaryThey => "they/them",
42 }
43 }
44
45 pub fn they(&self) -> &'static str {
46 match self {
47 Self::Feminine => "she",
48 Self::Masculine => "he",
49 Self::Neuter => "it",
50 Self::NonBinaryThey => "they",
51 }
52 }
53
54 pub fn they_cap(&self) -> &'static str {
55 match self {
56 Self::Feminine => "She",
57 Self::Masculine => "He",
58 Self::Neuter => "It",
59 Self::NonBinaryThey => "They",
60 }
61 }
62
63 pub fn theyre(&self) -> &'static str {
64 match self {
65 Self::Feminine => "she's",
66 Self::Masculine => "he's",
67 Self::Neuter => "it's",
68 Self::NonBinaryThey => "they're",
69 }
70 }
71
72 pub fn theyre_cap(&self) -> &'static str {
73 match self {
74 Self::Feminine => "She's",
75 Self::Masculine => "He's",
76 Self::Neuter => "It's",
77 Self::NonBinaryThey => "They're",
78 }
79 }
80
81 pub fn theyve(&self) -> &'static str {
82 match self {
83 Self::Feminine => "she's",
84 Self::Masculine => "he's",
85 Self::Neuter => "it's",
86 Self::NonBinaryThey => "they've",
87 }
88 }
89
90 pub fn theyve_cap(&self) -> &'static str {
91 match self {
92 Self::Feminine => "She's",
93 Self::Masculine => "He's",
94 Self::Neuter => "It's",
95 Self::NonBinaryThey => "They've",
96 }
97 }
98
99 pub fn them(&self) -> &'static str {
100 match self {
101 Self::Feminine => "her",
102 Self::Masculine => "him",
103 Self::Neuter => "it",
104 Self::NonBinaryThey => "them",
105 }
106 }
107
108 pub fn them_cap(&self) -> &'static str {
109 match self {
110 Self::Feminine => "Her",
111 Self::Masculine => "Him",
112 Self::Neuter => "It",
113 Self::NonBinaryThey => "Them",
114 }
115 }
116
117 pub fn their(&self) -> &'static str {
118 match self {
119 Self::Feminine => "her",
120 Self::Masculine => "his",
121 Self::Neuter => "its",
122 Self::NonBinaryThey => "their",
123 }
124 }
125
126 pub fn their_cap(&self) -> &'static str {
127 match self {
128 Self::Feminine => "Her",
129 Self::Masculine => "His",
130 Self::Neuter => "Its",
131 Self::NonBinaryThey => "Their",
132 }
133 }
134
135 pub fn theirs(&self) -> &'static str {
136 match self {
137 Self::Feminine => "hers",
138 Self::Masculine => "his",
139 Self::Neuter => "its",
140 Self::NonBinaryThey => "theirs",
141 }
142 }
143
144 pub fn theirs_cap(&self) -> &'static str {
145 match self {
146 Self::Feminine => "Hers",
147 Self::Masculine => "His",
148 Self::Neuter => "Its",
149 Self::NonBinaryThey => "Theirs",
150 }
151 }
152
153 pub fn themself(&self) -> &'static str {
154 match self {
155 Self::Feminine => "herself",
156 Self::Masculine => "himself",
157 Self::Neuter => "itself",
158 Self::NonBinaryThey => "themself",
159 }
160 }
161
162 pub fn themself_cap(&self) -> &'static str {
163 match self {
164 Self::Feminine => "Herself",
165 Self::Masculine => "Himself",
166 Self::Neuter => "Itself",
167 Self::NonBinaryThey => "Themself",
168 }
169 }
170
171 pub fn conjugate<'a>(&self, singular_form: &'a str, plural_form: &'a str) -> &'a str {
172 if self == &Self::NonBinaryThey {
173 plural_form
174 } else {
175 singular_form
176 }
177 }
178}
179
180impl fmt::Display for Gender {
181 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182 match self {
183 Self::Feminine => write!(f, "feminine (she/her)"),
184 Self::Masculine => write!(f, "masculine (he/him)"),
185 Self::Neuter => write!(f, "neuter (it)"),
186 Self::NonBinaryThey => write!(f, "non-binary (they/them)"),
187 }
188 }
189}
190
191#[cfg(test)]
192mod test {
193 use super::*;
194
195 #[test]
196 fn pronouns_test() {
197 let [f, m, n, t] = variants();
198
199 assert_eq!("she/her", f.pronouns());
200 assert_eq!("he/him", m.pronouns());
201 assert_eq!("it", n.pronouns());
202 assert_eq!("they/them", t.pronouns());
203
204 assert_eq!("she", f.they());
205 assert_eq!("She", f.they_cap());
206 assert_eq!("he", m.they());
207 assert_eq!("He", m.they_cap());
208 assert_eq!("it", n.they());
209 assert_eq!("It", n.they_cap());
210 assert_eq!("they", t.they());
211 assert_eq!("They", t.they_cap());
212
213 assert_eq!("she's", f.theyre());
214 assert_eq!("She's", f.theyre_cap());
215 assert_eq!("he's", m.theyre());
216 assert_eq!("He's", m.theyre_cap());
217 assert_eq!("it's", n.theyre());
218 assert_eq!("It's", n.theyre_cap());
219 assert_eq!("they're", t.theyre());
220 assert_eq!("They're", t.theyre_cap());
221
222 assert_eq!("she's", f.theyve());
223 assert_eq!("She's", f.theyve_cap());
224 assert_eq!("he's", m.theyve());
225 assert_eq!("He's", m.theyve_cap());
226 assert_eq!("it's", n.theyve());
227 assert_eq!("It's", n.theyve_cap());
228 assert_eq!("they've", t.theyve());
229 assert_eq!("They've", t.theyve_cap());
230
231 assert_eq!("her", f.them());
232 assert_eq!("Her", f.them_cap());
233 assert_eq!("him", m.them());
234 assert_eq!("Him", m.them_cap());
235 assert_eq!("it", n.them());
236 assert_eq!("It", n.them_cap());
237 assert_eq!("them", t.them());
238 assert_eq!("Them", t.them_cap());
239
240 assert_eq!("her", f.their());
241 assert_eq!("Her", f.their_cap());
242 assert_eq!("his", m.their());
243 assert_eq!("His", m.their_cap());
244 assert_eq!("its", n.their());
245 assert_eq!("Its", n.their_cap());
246 assert_eq!("their", t.their());
247 assert_eq!("Their", t.their_cap());
248
249 assert_eq!("hers", f.theirs());
250 assert_eq!("Hers", f.theirs_cap());
251 assert_eq!("his", m.theirs());
252 assert_eq!("His", m.theirs_cap());
253 assert_eq!("its", n.theirs());
254 assert_eq!("Its", n.theirs_cap());
255 assert_eq!("theirs", t.theirs());
256 assert_eq!("Theirs", t.theirs_cap());
257
258 assert_eq!("herself", f.themself());
259 assert_eq!("Herself", f.themself_cap());
260 assert_eq!("himself", m.themself());
261 assert_eq!("Himself", m.themself_cap());
262 assert_eq!("itself", n.themself());
263 assert_eq!("Itself", n.themself_cap());
264 assert_eq!("themself", t.themself());
265 assert_eq!("Themself", t.themself_cap());
266 }
267
268 #[test]
269 fn conjugate_test() {
270 let [f, m, n, t] = variants();
271
272 assert_eq!("conjugate", m.conjugate("conjugate", "conjugates"));
273 assert_eq!("conjugate", f.conjugate("conjugate", "conjugates"));
274 assert_eq!("conjugates", t.conjugate("conjugate", "conjugates"));
275 assert_eq!("conjugate", n.conjugate("conjugate", "conjugates"));
276 }
277
278 #[test]
279 fn fmt_test() {
280 assert_eq!("masculine (he/him)", format!("{}", Gender::Masculine));
281 assert_eq!("feminine (she/her)", format!("{}", Gender::Feminine));
282 assert_eq!(
283 "non-binary (they/them)",
284 format!("{}", Gender::NonBinaryThey)
285 );
286 assert_eq!("neuter (it)", format!("{}", Gender::Neuter));
287 }
288
289 #[test]
290 fn serialize_deserialize_test() {
291 let [f, m, n, t] = variants();
292
293 assert_eq!("\"feminine\"", serde_json::to_string(&f).unwrap());
294 assert_eq!("\"masculine\"", serde_json::to_string(&m).unwrap());
295 assert_eq!("\"neuter\"", serde_json::to_string(&n).unwrap());
296 assert_eq!("\"non-binary\"", serde_json::to_string(&t).unwrap());
297
298 let value: Gender = serde_json::from_str("\"feminine\"").unwrap();
299 assert_eq!(f, value);
300
301 let value: Gender = serde_json::from_str("\"masculine\"").unwrap();
302 assert_eq!(m, value);
303
304 let value: Gender = serde_json::from_str("\"neuter\"").unwrap();
305 assert_eq!(n, value);
306
307 let value: Gender = serde_json::from_str("\"non-binary\"").unwrap();
308 assert_eq!(t, value);
309 }
310
311 fn variants() -> [Gender; 4] {
312 [
313 Gender::Feminine,
314 Gender::Masculine,
315 Gender::Neuter,
316 Gender::NonBinaryThey,
317 ]
318 }
319}