1use std::collections::HashMap;
41
42use serde_json::{Value, json};
43
44pub fn build_lookup_data() -> Value {
48 json!({
49 "countries": build_countries_lookup(),
50 "currencies": build_currencies_lookup(),
51 "timezones": build_timezones_lookup(),
52 "languages": build_languages_lookup(),
53 })
54}
55
56fn build_countries_lookup() -> HashMap<String, Value> {
58 let mut countries = HashMap::new();
59
60 countries.insert(
62 "FR".to_string(),
63 json!({
64 "name": "France",
65 "continent": "Europe",
66 "region": "EU",
67 "in_eu": true,
68 "in_schengen": true,
69 }),
70 );
71 countries.insert(
72 "DE".to_string(),
73 json!({
74 "name": "Germany",
75 "continent": "Europe",
76 "region": "EU",
77 "in_eu": true,
78 "in_schengen": true,
79 }),
80 );
81 countries.insert(
82 "GB".to_string(),
83 json!({
84 "name": "United Kingdom",
85 "continent": "Europe",
86 "region": "EU",
87 "in_eu": false,
88 "in_schengen": false,
89 }),
90 );
91 countries.insert(
92 "IT".to_string(),
93 json!({
94 "name": "Italy",
95 "continent": "Europe",
96 "region": "EU",
97 "in_eu": true,
98 "in_schengen": true,
99 }),
100 );
101 countries.insert(
102 "ES".to_string(),
103 json!({
104 "name": "Spain",
105 "continent": "Europe",
106 "region": "EU",
107 "in_eu": true,
108 "in_schengen": true,
109 }),
110 );
111 countries.insert(
112 "PL".to_string(),
113 json!({
114 "name": "Poland",
115 "continent": "Europe",
116 "region": "EU",
117 "in_eu": true,
118 "in_schengen": true,
119 }),
120 );
121 countries.insert(
122 "NL".to_string(),
123 json!({
124 "name": "Netherlands",
125 "continent": "Europe",
126 "region": "EU",
127 "in_eu": true,
128 "in_schengen": true,
129 }),
130 );
131 countries.insert(
132 "BE".to_string(),
133 json!({
134 "name": "Belgium",
135 "continent": "Europe",
136 "region": "EU",
137 "in_eu": true,
138 "in_schengen": true,
139 }),
140 );
141 countries.insert(
142 "CH".to_string(),
143 json!({
144 "name": "Switzerland",
145 "continent": "Europe",
146 "region": "EU",
147 "in_eu": false,
148 "in_schengen": true,
149 }),
150 );
151
152 countries.insert(
154 "US".to_string(),
155 json!({
156 "name": "United States",
157 "continent": "North America",
158 "region": "Americas",
159 "in_eu": false,
160 "in_schengen": false,
161 }),
162 );
163 countries.insert(
164 "CA".to_string(),
165 json!({
166 "name": "Canada",
167 "continent": "North America",
168 "region": "Americas",
169 "in_eu": false,
170 "in_schengen": false,
171 }),
172 );
173 countries.insert(
174 "MX".to_string(),
175 json!({
176 "name": "Mexico",
177 "continent": "North America",
178 "region": "Americas",
179 "in_eu": false,
180 "in_schengen": false,
181 }),
182 );
183
184 countries.insert(
186 "BR".to_string(),
187 json!({
188 "name": "Brazil",
189 "continent": "South America",
190 "region": "Americas",
191 "in_eu": false,
192 "in_schengen": false,
193 }),
194 );
195 countries.insert(
196 "AR".to_string(),
197 json!({
198 "name": "Argentina",
199 "continent": "South America",
200 "region": "Americas",
201 "in_eu": false,
202 "in_schengen": false,
203 }),
204 );
205
206 countries.insert(
208 "CN".to_string(),
209 json!({
210 "name": "China",
211 "continent": "Asia",
212 "region": "Asia",
213 "in_eu": false,
214 "in_schengen": false,
215 }),
216 );
217 countries.insert(
218 "JP".to_string(),
219 json!({
220 "name": "Japan",
221 "continent": "Asia",
222 "region": "Asia",
223 "in_eu": false,
224 "in_schengen": false,
225 }),
226 );
227 countries.insert(
228 "IN".to_string(),
229 json!({
230 "name": "India",
231 "continent": "Asia",
232 "region": "Asia",
233 "in_eu": false,
234 "in_schengen": false,
235 }),
236 );
237 countries.insert(
238 "SG".to_string(),
239 json!({
240 "name": "Singapore",
241 "continent": "Asia",
242 "region": "Asia",
243 "in_eu": false,
244 "in_schengen": false,
245 }),
246 );
247
248 countries.insert(
250 "ZA".to_string(),
251 json!({
252 "name": "South Africa",
253 "continent": "Africa",
254 "region": "Africa",
255 "in_eu": false,
256 "in_schengen": false,
257 }),
258 );
259 countries.insert(
260 "EG".to_string(),
261 json!({
262 "name": "Egypt",
263 "continent": "Africa",
264 "region": "Africa",
265 "in_eu": false,
266 "in_schengen": false,
267 }),
268 );
269
270 countries.insert(
272 "AU".to_string(),
273 json!({
274 "name": "Australia",
275 "continent": "Oceania",
276 "region": "Oceania",
277 "in_eu": false,
278 "in_schengen": false,
279 }),
280 );
281 countries.insert(
282 "NZ".to_string(),
283 json!({
284 "name": "New Zealand",
285 "continent": "Oceania",
286 "region": "Oceania",
287 "in_eu": false,
288 "in_schengen": false,
289 }),
290 );
291
292 countries
293}
294
295fn build_currencies_lookup() -> HashMap<String, Value> {
297 let mut currencies = HashMap::new();
298
299 currencies.insert(
300 "USD".to_string(),
301 json!({
302 "name": "US Dollar",
303 "symbol": "$",
304 "decimal_places": 2,
305 }),
306 );
307 currencies.insert(
308 "EUR".to_string(),
309 json!({
310 "name": "Euro",
311 "symbol": "€",
312 "decimal_places": 2,
313 }),
314 );
315 currencies.insert(
316 "GBP".to_string(),
317 json!({
318 "name": "British Pound",
319 "symbol": "£",
320 "decimal_places": 2,
321 }),
322 );
323 currencies.insert(
324 "JPY".to_string(),
325 json!({
326 "name": "Japanese Yen",
327 "symbol": "¥",
328 "decimal_places": 0,
329 }),
330 );
331 currencies.insert(
332 "CHF".to_string(),
333 json!({
334 "name": "Swiss Franc",
335 "symbol": "₣",
336 "decimal_places": 2,
337 }),
338 );
339 currencies.insert(
340 "CAD".to_string(),
341 json!({
342 "name": "Canadian Dollar",
343 "symbol": "C$",
344 "decimal_places": 2,
345 }),
346 );
347 currencies.insert(
348 "AUD".to_string(),
349 json!({
350 "name": "Australian Dollar",
351 "symbol": "A$",
352 "decimal_places": 2,
353 }),
354 );
355 currencies.insert(
356 "CNY".to_string(),
357 json!({
358 "name": "Chinese Yuan",
359 "symbol": "¥",
360 "decimal_places": 2,
361 }),
362 );
363 currencies.insert(
364 "INR".to_string(),
365 json!({
366 "name": "Indian Rupee",
367 "symbol": "₹",
368 "decimal_places": 2,
369 }),
370 );
371 currencies.insert(
372 "MXN".to_string(),
373 json!({
374 "name": "Mexican Peso",
375 "symbol": "$",
376 "decimal_places": 2,
377 }),
378 );
379
380 currencies
381}
382
383fn build_timezones_lookup() -> HashMap<String, Value> {
385 let mut timezones = HashMap::new();
386
387 timezones.insert(
389 "UTC".to_string(),
390 json!({
391 "offset_minutes": 0,
392 "has_dst": false,
393 "region": "UTC",
394 }),
395 );
396
397 timezones.insert(
399 "GMT".to_string(),
400 json!({
401 "offset_minutes": 0,
402 "has_dst": false,
403 "region": "Europe",
404 }),
405 );
406 timezones.insert(
407 "CET".to_string(),
408 json!({
409 "offset_minutes": 60,
410 "has_dst": true,
411 "region": "Europe",
412 }),
413 );
414 timezones.insert(
415 "CEST".to_string(),
416 json!({
417 "offset_minutes": 120,
418 "has_dst": false,
419 "region": "Europe",
420 }),
421 );
422
423 timezones.insert(
425 "EST".to_string(),
426 json!({
427 "offset_minutes": -300,
428 "has_dst": true,
429 "region": "Americas",
430 }),
431 );
432 timezones.insert(
433 "EDT".to_string(),
434 json!({
435 "offset_minutes": -240,
436 "has_dst": false,
437 "region": "Americas",
438 }),
439 );
440 timezones.insert(
441 "CST".to_string(),
442 json!({
443 "offset_minutes": -360,
444 "has_dst": true,
445 "region": "Americas",
446 }),
447 );
448 timezones.insert(
449 "CDT".to_string(),
450 json!({
451 "offset_minutes": -300,
452 "has_dst": false,
453 "region": "Americas",
454 }),
455 );
456 timezones.insert(
457 "MST".to_string(),
458 json!({
459 "offset_minutes": -420,
460 "has_dst": true,
461 "region": "Americas",
462 }),
463 );
464 timezones.insert(
465 "MDT".to_string(),
466 json!({
467 "offset_minutes": -360,
468 "has_dst": false,
469 "region": "Americas",
470 }),
471 );
472 timezones.insert(
473 "PST".to_string(),
474 json!({
475 "offset_minutes": -480,
476 "has_dst": true,
477 "region": "Americas",
478 }),
479 );
480 timezones.insert(
481 "PDT".to_string(),
482 json!({
483 "offset_minutes": -420,
484 "has_dst": false,
485 "region": "Americas",
486 }),
487 );
488
489 timezones.insert(
491 "JST".to_string(),
492 json!({
493 "offset_minutes": 540,
494 "has_dst": false,
495 "region": "Asia",
496 }),
497 );
498 timezones.insert(
499 "IST".to_string(),
500 json!({
501 "offset_minutes": 330,
502 "has_dst": false,
503 "region": "Asia",
504 }),
505 );
506 timezones.insert(
507 "SGT".to_string(),
508 json!({
509 "offset_minutes": 480,
510 "has_dst": false,
511 "region": "Asia",
512 }),
513 );
514 timezones.insert(
515 "AEST".to_string(),
516 json!({
517 "offset_minutes": 600,
518 "has_dst": false,
519 "region": "Oceania",
520 }),
521 );
522
523 timezones
524}
525
526fn build_languages_lookup() -> HashMap<String, Value> {
528 let mut languages = HashMap::new();
529
530 languages.insert(
532 "EN".to_string(),
533 json!({
534 "name": "English",
535 "family": "Indo-European",
536 "script": "Latin",
537 }),
538 );
539 languages.insert(
540 "FR".to_string(),
541 json!({
542 "name": "French",
543 "family": "Indo-European",
544 "script": "Latin",
545 }),
546 );
547 languages.insert(
548 "DE".to_string(),
549 json!({
550 "name": "German",
551 "family": "Indo-European",
552 "script": "Latin",
553 }),
554 );
555 languages.insert(
556 "ES".to_string(),
557 json!({
558 "name": "Spanish",
559 "family": "Indo-European",
560 "script": "Latin",
561 }),
562 );
563 languages.insert(
564 "IT".to_string(),
565 json!({
566 "name": "Italian",
567 "family": "Indo-European",
568 "script": "Latin",
569 }),
570 );
571 languages.insert(
572 "PT".to_string(),
573 json!({
574 "name": "Portuguese",
575 "family": "Indo-European",
576 "script": "Latin",
577 }),
578 );
579 languages.insert(
580 "RU".to_string(),
581 json!({
582 "name": "Russian",
583 "family": "Indo-European",
584 "script": "Cyrillic",
585 }),
586 );
587
588 languages.insert(
590 "ZH".to_string(),
591 json!({
592 "name": "Chinese",
593 "family": "Sino-Tibetan",
594 "script": "Han",
595 }),
596 );
597
598 languages.insert(
600 "JA".to_string(),
601 json!({
602 "name": "Japanese",
603 "family": "Japonic",
604 "script": "Japanese",
605 }),
606 );
607
608 languages.insert(
610 "KO".to_string(),
611 json!({
612 "name": "Korean",
613 "family": "Koreanic",
614 "script": "Hangul",
615 }),
616 );
617
618 languages.insert(
620 "VI".to_string(),
621 json!({
622 "name": "Vietnamese",
623 "family": "Austroasiatic",
624 "script": "Latin",
625 }),
626 );
627
628 languages
629}
630
631#[cfg(test)]
632mod tests {
633 use super::*;
634
635 #[test]
636 fn test_build_lookup_data() {
637 let data = build_lookup_data();
638
639 assert!(data.get("countries").is_some());
640 assert!(data.get("currencies").is_some());
641 assert!(data.get("timezones").is_some());
642 assert!(data.get("languages").is_some());
643 }
644
645 #[test]
646 fn test_countries_have_required_fields() {
647 let countries = build_countries_lookup();
648
649 for (code, data) in countries {
650 assert!(data.get("name").is_some(), "Country {code} missing name");
651 assert!(data.get("continent").is_some(), "Country {code} missing continent");
652 assert!(data.get("in_eu").is_some(), "Country {code} missing in_eu");
653 assert!(data.get("in_schengen").is_some(), "Country {code} missing in_schengen");
654 }
655 }
656
657 #[test]
658 fn test_currencies_have_required_fields() {
659 let currencies = build_currencies_lookup();
660
661 for (code, data) in currencies {
662 assert!(data.get("name").is_some(), "Currency {code} missing name");
663 assert!(data.get("symbol").is_some(), "Currency {code} missing symbol");
664 assert!(data.get("decimal_places").is_some(), "Currency {code} missing decimal_places");
665 }
666 }
667
668 #[test]
669 fn test_timezones_have_required_fields() {
670 let timezones = build_timezones_lookup();
671
672 for (code, data) in timezones {
673 assert!(data.get("offset_minutes").is_some(), "Timezone {code} missing offset_minutes");
674 assert!(data.get("has_dst").is_some(), "Timezone {code} missing has_dst");
675 }
676 }
677
678 #[test]
679 fn test_eu_member_states() {
680 let countries = build_countries_lookup();
681
682 assert!(countries["FR"]["in_eu"].as_bool().unwrap());
684 assert!(countries["DE"]["in_eu"].as_bool().unwrap());
685 assert!(countries["IT"]["in_eu"].as_bool().unwrap());
686
687 assert!(!countries["US"]["in_eu"].as_bool().unwrap());
689 assert!(!countries["GB"]["in_eu"].as_bool().unwrap());
690 }
691
692 #[test]
693 fn test_schengen_members() {
694 let countries = build_countries_lookup();
695
696 assert!(countries["FR"]["in_schengen"].as_bool().unwrap());
698 assert!(countries["DE"]["in_schengen"].as_bool().unwrap());
699 assert!(countries["CH"]["in_schengen"].as_bool().unwrap());
700
701 assert!(!countries["US"]["in_schengen"].as_bool().unwrap());
703 assert!(!countries["GB"]["in_schengen"].as_bool().unwrap());
704 }
705}