iso10383_parser/
lib.rs

1//! ISO 10383 Market Identifier Codes XML Parser
2
3#![doc = include_str!("../README.md")]
4
5use iso3166_static::Alpha2;
6use iso10383_types::{Category, Kind, Mic, Status};
7use serde::{Deserialize, Serialize};
8use std::{
9    cell::RefCell,
10    collections::HashMap,
11    sync::atomic::{AtomicBool, Ordering},
12};
13
14/// A list of MICs which can be parsed from the distributed XML file.
15#[derive(Debug, Default, Deserialize, Serialize)]
16pub struct MicList {
17    #[serde(alias = "ISO10383_MIC")]
18    mics: Vec<MicRecord>,
19    #[serde(skip)]
20    by_mics: RefCell<HashMap<String, MicRecord>>,
21    #[serde(skip)]
22    by_mics_loaded: AtomicBool,
23}
24
25impl MicList {
26    fn update_cache(&self) {
27        if self.by_mics_loaded.load(Ordering::Acquire) {
28            return;
29        }
30
31        for mic in &self.mics {
32            self.by_mics
33                .borrow_mut()
34                .insert(mic.name.clone(), mic.clone());
35        }
36        self.by_mics_loaded.store(true, Ordering::Release);
37    }
38
39    /// Get the size of the cache
40    pub fn len(&self) -> usize {
41        self.update_cache();
42
43        self.mics.len()
44    }
45
46    /// Get whether or not the cache is empty.
47    pub fn is_empty(&self) -> bool {
48        self.update_cache();
49
50        self.mics.is_empty()
51    }
52
53    /// Retrieve a slice of the parsed MICs.
54    pub fn mics(&self) -> &[MicRecord] {
55        &self.mics
56    }
57}
58
59/// A structure representing a Market Identifier record.
60#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
61pub struct MicRecord {
62    /// The MIC itself
63    #[serde(alias = "MIC")]
64    pub mic: Mic,
65
66    /// The "owning/operating" MIC which controls this entry.
67    #[serde(alias = "OPERATING_x0020_MIC")]
68    pub operating_mic: Mic,
69
70    /// What type of MIC this is
71    #[serde(alias = "OPRT_x002F_SGMT")]
72    pub kind: Kind,
73
74    /// The human-readable name of this MIC
75    #[serde(alias = "MARKET_x0020_NAME-INSTITUTION_x0020_DESCRIPTION")]
76    pub name: String,
77
78    /// The name of the legal entity responsible for this MIC
79    #[serde(alias = "LEGAL_x0020_ENTITY_x0020_NAME")]
80    pub legal_entity_name: Option<String>,
81
82    /// The ISO 17442 LEI code for the legal entity.
83    ///
84    /// This is a string because quick-xml treats `<LEI></LEI>` as `Some("")` and tries to parse
85    /// the `""`. A simple `deserialize_with` that returns an `Option<Lei>` also did not work...
86    #[serde(alias = "LEI")]
87    pub legal_entity_id: Option<String>,
88
89    /// The market category this MIC is operating in
90    #[serde(alias = "MARKET_x0020_CATEGORY_x0020_CODE")]
91    pub category: Category,
92
93    /// Known acronym of the market
94    #[serde(alias = "ACRONYM")]
95    pub acronym: Option<String>,
96
97    /// ISO 3166-2 alpha-2 code
98    #[serde(alias = "ISO_x0020_COUNTRY_x0020_CODE_x0020__x0028_ISO_x0020_3166_x0029_")]
99    pub country: Alpha2,
100
101    /// The city where this market is located
102    #[serde(alias = "CITY")]
103    pub city: String,
104
105    /// The website of this market
106    #[serde(alias = "WEBSITE")]
107    pub website: Option<String>,
108
109    /// The current status of this code
110    #[serde(alias = "STATUS")]
111    pub status: Status,
112
113    /// The date this code was originally created in the ASCII decimal format YYYYMMDD.
114    #[serde(alias = "CREATION_x0020_DATE")]
115    pub creation_date: String,
116
117    /// The last update date in the ASCII decimal format YYYYMMDD.
118    #[serde(alias = "LAST_x0020_UPDATE_x0020_DATE")]
119    pub last_update_date: String,
120
121    /// The date this MIC was last verified for correctness in the ASCII decimal format YYYYMMDD.
122    #[serde(alias = "LAST_x0020_VALIDATION_x0020_DATE")]
123    pub last_validation_date: Option<String>,
124
125    /// The date when this MIC was marked inactive in the ASCII decimal format YYYYMMDD.
126    #[serde(alias = "EXPIRY_x0020_DATE")]
127    pub expiry_date: Option<String>,
128
129    /// Additional details or comments.
130    #[serde(alias = "COMMENTS")]
131    pub comments: Option<String>,
132}