1#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub enum Locale {
7 EnUs,
8 EnIn,
9 EnEu,
10 EnBy,
11}
12
13#[derive(Debug, PartialEq, Eq)]
15pub struct LocalFormat {
16 pub name: &'static str,
17 pub digit_separator: char,
18 pub digit_separator_pattern: &'static [usize],
19 pub exponent_separator: char,
20}
21
22const PATTERN_3_3_3: &[usize] = &[3, 3, 3];
24const PATTERN_3_2_2: &[usize] = &[3, 2, 2];
25
26impl LocalFormat {
27 pub fn from_locale(locale: Locale) -> LocalFormat {
29 use Locale::*;
30
31 match locale {
32 EnUs => LocalFormat {
33 name: "en-us",
34 digit_separator: ',',
35 digit_separator_pattern: PATTERN_3_3_3,
36 exponent_separator: '.',
37 },
38 EnIn => LocalFormat {
39 name: "en-in",
40 digit_separator: ',',
41 digit_separator_pattern: PATTERN_3_2_2,
42 exponent_separator: '.',
43 },
44 EnEu => LocalFormat {
45 name: "en-eu",
46 digit_separator: '.',
47 digit_separator_pattern: PATTERN_3_3_3,
48 exponent_separator: ',',
49 },
50 EnBy => LocalFormat {
51 name: "en-by",
52 digit_separator: ' ',
53 digit_separator_pattern: PATTERN_3_3_3,
54 exponent_separator: ',',
55 },
56 }
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[test]
65 fn en_us_locale_format() {
66 let format = LocalFormat::from_locale(Locale::EnUs);
67 assert_eq!(format.name, "en-us");
68 assert_eq!(format.digit_separator, ',');
69 assert_eq!(format.exponent_separator, '.');
70 assert_eq!(format.digit_separator_pattern, &[3, 3, 3]);
71 }
72
73 #[test]
74 fn en_in_locale_format() {
75 let format = LocalFormat::from_locale(Locale::EnIn);
77 assert_eq!(format.name, "en-in");
78 assert_eq!(format.digit_separator, ',');
79 assert_eq!(format.exponent_separator, '.');
80 assert_eq!(format.digit_separator_pattern, &[3, 2, 2]);
81 }
82
83 #[test]
84 fn en_eu_locale_format() {
85 let format = LocalFormat::from_locale(Locale::EnEu);
87 assert_eq!(format.name, "en-eu");
88 assert_eq!(format.digit_separator, '.');
89 assert_eq!(format.exponent_separator, ',');
90 assert_eq!(format.digit_separator_pattern, &[3, 3, 3]);
91 }
92
93 #[test]
94 fn en_by_locale_format() {
95 let format = LocalFormat::from_locale(Locale::EnBy);
97 assert_eq!(format.name, "en-by");
98 assert_eq!(format.digit_separator, ' ');
99 assert_eq!(format.exponent_separator, ',');
100 assert_eq!(format.digit_separator_pattern, &[3, 3, 3]);
101 }
102
103 #[test]
104 fn all_locales_have_distinct_names() {
105 let locales = [Locale::EnUs, Locale::EnIn, Locale::EnEu, Locale::EnBy];
106 let names: Vec<_> = locales
107 .iter()
108 .map(|l| LocalFormat::from_locale(*l).name)
109 .collect();
110
111 for (i, name) in names.iter().enumerate() {
113 for (j, other) in names.iter().enumerate() {
114 if i != j {
115 assert_ne!(name, other, "Locale names must be unique");
116 }
117 }
118 }
119 }
120
121 #[test]
122 fn digit_and_exponent_separators_differ() {
123 let locales = [Locale::EnUs, Locale::EnIn, Locale::EnEu, Locale::EnBy];
126 for locale in locales {
127 let format = LocalFormat::from_locale(locale);
128 assert_ne!(
129 format.digit_separator, format.exponent_separator,
130 "Locale {:?} has same digit and exponent separator",
131 locale
132 );
133 }
134 }
135}