iso10383_parser/
lib.rs

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