warlocks_cauldron/providers/
address.rs

1use super::dependencies::*;
2
3
4pub enum DDType {
5    lt, lg,
6}
7
8#[derive(Debug)]
9pub enum FloatNumber {
10    DMS(String),
11    Raw(f32),
12}
13
14impl std::fmt::Display for FloatNumber {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        write!(f, "{}", match self {
17            FloatNumber::DMS(dms) => dms.to_string(),
18            FloatNumber::Raw(raw) => raw.to_string(),
19        })
20    }
21}
22
23#[derive(Debug)]
24pub enum Coordinates {
25    DMS(String, String),
26    Raw(f32, f32),
27}
28
29impl std::fmt::Display for Coordinates {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        let coordiantes = match self {
32            Coordinates::DMS(lng, lat) => (lng.to_string(), lat.to_string()),
33            Coordinates::Raw(lng, lat) => (lng.to_string(), lat.to_string()),
34        };
35
36        write!(f, "({}, {})", coordiantes.0, coordiantes.1) 
37    }
38}
39
40
41/// Struct for generate fake address data.
42///
43/// This struct provides all the data related to geographical location.
44pub struct Address<'a>(pub &'a Locale);
45
46impl<'a> Address<'a> {
47    /// Private. Return global parsed data from own locale
48    fn data(&self) -> &ParsedData { self.0.get_data() }
49
50    /// Private. Convert decimal number to DMS format
51    /// 
52    /// # Arguments
53    /// * `num` - Decimal number
54    /// * `dd_type` - Type of number
55    fn dd_to_dms(num: f32, dd_type: DDType) -> String {
56        let direction = match dd_type {
57            DDType::lg => if num < 0.0 { "W" } else { "E" },
58            DDType::lt => if num < 0.0 { "S" } else { "N" },
59        };
60
61        let num = num.abs();
62        let degrees = num.floor();
63        let part = num - degrees;
64        let minutes = (part * 60.0).floor();
65        let seconds = 3600.0 * part - 60.0 * minutes;
66        format!("{degrees}º{minutes}'{seconds:.3}\"{direction}")
67    }
68
69    /// Get float number
70    /// 
71    /// # Arguments
72    /// * `key` - DDType enum
73    /// * `dms` - Use DMS format
74    fn get_fs(key: DDType, dms: bool) -> FloatNumber {
75        let rng = match key {
76            DDType::lt => (-90.0, 90.0),
77            DDType::lg => (-180.0, 180.0),
78        };
79
80        let result = uniform(rng.0, rng.1);
81
82        match dms {
83            true => FloatNumber::DMS(Self::dd_to_dms(result, key)),
84            false => FloatNumber::Raw(result),
85        }
86    }
87
88    /// Generate a random street number
89    /// 
90    /// return example: 666
91    pub fn street_number(&self) -> i32 {
92        rand::thread_rng().gen_range(0..1400)
93    }
94
95    /// Get a random street name
96    /// 
97    /// return example: Lovecraft
98    pub fn street_name(&self) -> &str {
99        get_random_element(self.data().address.street.name.iter())
100    }
101
102    /// Get a random street suffix
103    /// 
104    /// return example: Hill
105    pub fn street_suffix(&self) -> &str {
106        get_random_element(self.data().address.street.suffix.iter())
107    }
108
109    /// Generate a random local address | *An allias for .local_address()* 
110    ///  for compatibility with mimesis using
111    #[deprecated(since = "0.0.0", note = "use .local_address()")]
112    pub fn address(&self) -> String {
113        self.local_address()
114    }
115
116    /// Generate a random local address
117    ///
118    /// return example: 666 Lovecraft Avenue
119    pub fn local_address(&self) -> String {
120        let data = self.data();
121
122        let format = &data.address.address_fmt;
123
124        let st_num = &self.street_number().to_string();
125        let st_name = self.street_name();
126        
127        if SHORTENED_ADDRESS_FMT.contains(&data.lang_code) {
128            return format
129                .replace("{st_num}", st_num)
130                .replace("{st_name}", st_name);
131        }
132
133        if data.lang_code.eq("ja") {
134            return format
135                .replacen("{}", self.city(), 1)
136                .replacen("{}", &randint(0, 100).to_string(), 1)
137                .replacen("{}", &randint(0, 100).to_string(), 1)
138                .replacen("{}", &randint(0, 100).to_string(), 1);
139        }
140
141        format
142            .replace("{st_num}", st_num)
143            .replace("{st_name}", st_name)
144            .replace("{st_sfx}", &self.street_suffix())
145    }
146
147    /// Generate a random address including country name and state
148    /// 
149    /// return example: United States, Massachusetts, Innsmouth, 666 Lovecraft Avenue
150    pub fn full_address(&self) -> String {
151        format!("{}, {}, {}, {}", self.country(true), self.state(false), self.city(), self.local_address())
152    }
153
154    /// Get a random continent name or continent code
155    /// 
156    /// 
157    /// return example: NA
158    ///
159    /// # Arguments
160    /// * `code` - Return code of continent
161    pub fn continent(&self, code: bool) -> &str {
162        get_random_element(match code {
163            true => self.data().address.continent.iter(),
164            false => CONTINENT_CODES.iter(),
165        })
166    }
167
168    /// Get a random calling code of random country
169    ///  
170    /// return example: US
171    ///
172    /// # Arguments
173    /// * `code` - CountryCode enum
174    pub fn country_code(&self, code: Option<CountryCode>) -> Option<&str> {
175        match COUNTRY_CODES.get(validate_enum(code, None)) {
176            Some(cc) => Some(get_random_element(cc.iter())),
177            None => None,
178        }
179    }
180
181    /// Get the country of the current locale
182    ///  
183    /// return example: United States
184    ///
185    /// # Arguments
186    /// * `current_locale` - Get country name by current locale
187    pub fn country(&self, current_locale: bool) -> &str {
188        match current_locale {
189            false => get_random_element(self.data().address.country.name.iter()),
190            true => &self.data().address.country.current_locale,
191        }
192    }
193
194    /// Get a random administrative district of country
195    /// 
196    /// return example: Massachusetts
197    ///
198    /// # Arguments
199    /// * `abbr` - Return ISO 3166-2 code
200    pub fn state(&self, abbr: bool) -> &str {
201        get_random_element(
202            match abbr {
203                true => self.data().address.state.abbr.iter(),
204                false => self.data().address.state.name.iter(),
205            }
206        )
207    }
208
209    /// Get a random region | *An allias for .state()*
210    /// 
211    /// return example: Massachusetts
212    ///
213    /// # Arguments
214    /// * `abbr` - Return ISO 3166-2 code
215    pub fn region(&self, abbr: bool) -> &str {
216        self.state(abbr)
217    }
218
219    /// Get a random province | *An allias for .state()*
220    /// 
221    /// return example: Massachusetts
222    ///
223    /// # Arguments
224    /// * `abbr` - Return ISO 3166-2 code
225    pub fn province(&self, abbr: bool) -> &str {
226        self.state(abbr)
227    }
228
229    /// Get a random region | *An allias for .state()*
230    /// 
231    /// return example: Massachusetts
232    ///
233    /// # Arguments
234    /// * `abbr` - Return ISO 3166-2 code
235    pub fn federal_subject(&self, abbr: bool) -> &str {
236        self.state(abbr)
237    }
238
239    /// Get a random prefecture | *An allias for .state()*
240    /// 
241    /// return example: Massachusetts
242    ///
243    /// # Arguments
244    /// * `abbr` - Return ISO 3166-2 code
245    pub fn prefecture(&self, abbr: bool) -> &str {
246        self.state(abbr)
247    }
248
249    /// Get a random city
250    /// 
251    /// return example: Innsmouth
252    pub fn city(&self) -> &str {
253        get_random_element(self.data().address.city.iter())
254    }
255
256    /// Generate a postal code for current locale
257    ///
258    /// return example: 66613
259    pub fn postal_code(&self) -> String {
260        custom_code(&self.data().address.postal_code_fmt, '@', '#')
261    }
262
263    /// Generate a zip code | *An allias for .postal_code()*
264    ///
265    /// return example: 66613
266    pub fn zip_code(&self) -> String {
267        self.postal_code()
268    }
269
270    /// Get a random calling code of random country
271    ///
272    /// return example: +666
273    pub fn calling_code(&self) -> &str {
274        get_random_element(CALLING_CODES.iter())
275    }
276
277    /// Generate a random value of latitude
278    /// 
279    /// return example: 41º14'0.000"N
280    ///
281    /// # Arguments
282    /// * `abbr` - Use DMS format
283    pub fn latitude(dms: bool) -> FloatNumber {
284        Self::get_fs(DDType::lt, dms)
285    }
286
287    /// Generate a random value of longitude
288    /// 
289    /// return example: 69º56'0.000"W
290    /// 
291    /// # Arguments
292    /// * `abbr` - Use DMS format
293    pub fn longitude(dms: bool) -> FloatNumber {
294        Self::get_fs(DDType::lg, dms)
295    }
296
297    /// Generate random geo coordinates
298    /// 
299    /// return example: Coordinates::DMS("41º14'0.000"N", "69º56'0.000"W")
300    ///
301    /// # Arguments
302    /// * `abbr` - Use DMS format
303    pub fn coordinates(dms: bool) -> Coordinates {
304        match (dms, Self::latitude(dms), Self::longitude(dms)) {
305            (true, FloatNumber::DMS(lat), FloatNumber::DMS(lng)) => Coordinates::DMS(lat, lng),
306            (false, FloatNumber::Raw(lat), FloatNumber::Raw(lng)) => Coordinates::Raw(lat, lng),
307            _ => panic!("In theory, it shouldn't break :D"),
308        }
309    }
310}