#![warn(
unknown_lints,
// ---------- Stylistic
absolute_paths_not_starting_with_crate,
elided_lifetimes_in_paths,
explicit_outlives_requirements,
macro_use_extern_crate,
nonstandard_style, /* group */
noop_method_call,
rust_2018_idioms,
single_use_lifetimes,
trivial_casts,
trivial_numeric_casts,
// ---------- Future
future_incompatible, /* group */
rust_2021_compatibility, /* group */
// ---------- Public
missing_debug_implementations,
// missing_docs,
unreachable_pub,
// ---------- Unsafe
unsafe_code,
unsafe_op_in_unsafe_fn,
// ---------- Unused
unused, /* group */
)]
#![deny(
// ---------- Public
exported_private_dependencies,
private_in_public,
// ---------- Deprecated
anonymous_parameters,
bare_trait_objects,
ellipsis_inclusive_range_patterns,
// ---------- Unsafe
deref_nullptr,
drop_bounds,
dyn_drop,
)]
use codes_agency::{standardized_type, Agency, Standard};
use codes_check_digits::iso_7064::{get_algorithm_instance, CheckDigitAlgorithm, IsoVariant};
use codes_check_digits::Calculator;
use codes_common::error::{invalid_format, invalid_length};
use codes_common::{code_as_str, code_impl, fixed_length_code, FixedLengthCode};
use std::str::FromStr;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub const ISO_17442: Standard = Standard::new_with_long_ref(
Agency::ISO,
"17442",
"ISO 17442-1:2020",
"Financial services — Legal entity identifier (LEI) — Part 1: Assignment",
"https://www.iso.org/standard/78829.html",
);
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct LegalEntityId(String);
pub use codes_common::CodeParseError as LegalEntityIdError;
const ISO_MOD_97_10: CheckDigitAlgorithm = get_algorithm_instance(IsoVariant::Mod_97_10);
impl FromStr for LegalEntityId {
type Err = LegalEntityIdError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.replace(' ', "");
if s.len() != Self::fixed_length() {
Err(invalid_length("LegalEntityId", s.len()))
} else if ISO_MOD_97_10.is_valid(&s) {
Ok(LegalEntityId(s))
} else {
Err(invalid_format("LegalEntityId", s))
}
}
}
#[cfg(feature = "urn")]
impl TryFrom<url::Url> for LegalEntityId {
type Error = LegalEntityIdError;
fn try_from(value: url::Url) -> Result<Self, Self::Error> {
if !value.scheme().eq_ignore_ascii_case("urn") {
Err(invalid_format("LegalEntityId", value.scheme()))
} else {
let path = value.path();
if path[0..4].eq_ignore_ascii_case("lei:") {
LegalEntityId::from_str(&path[4..])
} else {
Err(invalid_format("LegalEntityId", path))
}
}
}
}
#[cfg(feature = "urn")]
impl From<LegalEntityId> for url::Url {
fn from(v: LegalEntityId) -> url::Url {
url::Url::parse(&format!("urn:lei:{}", v.0)).unwrap()
}
}
code_impl!(LegalEntityId, as_str, str, String, to_string);
code_as_str!(LegalEntityId);
fixed_length_code!(LegalEntityId, 20);
standardized_type!(LegalEntityId, ISO_17442);
impl LegalEntityId {
pub fn local_operating_unit(&self) -> &str {
&self.0[..4]
}
pub fn entity(&self) -> &str {
&self.0[4..18]
}
pub fn check_digits(&self) -> &str {
&self.0[18..]
}
}
#[cfg(test)]
mod tests {
use crate::LegalEntityId;
use std::str::FromStr;
#[test]
fn test_some_valid_lei_1() {
assert!(LegalEntityId::from_str("54930084UKLVMY22DS16").is_ok());
}
#[test]
fn test_some_valid_lei_2() {
assert!(LegalEntityId::from_str("213800WSGIIZCXF1P572").is_ok());
}
#[test]
fn test_some_valid_lei_3() {
assert!(LegalEntityId::from_str("5493000IBP32UQZ0KL24").is_ok());
}
#[test]
fn test_some_valid_lei_4() {
assert!(LegalEntityId::from_str("YZ83GD8L7GG84979J516").is_ok());
}
#[test]
fn test_some_valid_lei_components() {
let lei = LegalEntityId::from_str("YZ83GD8L7GG84979J516").unwrap();
assert_eq!(lei.local_operating_unit(), "YZ83");
assert_eq!(lei.entity(), "GD8L7GG84979J5");
assert_eq!(lei.check_digits(), "16");
}
#[cfg(feature = "url")]
#[test]
fn test_lei_to_url() {
use url::Url;
let lei = LegalEntityId::from_str("YZ83GD8L7GG84979J516").unwrap();
let url: Url = lei.into();
assert_eq!(url.as_str(), "urn:lei:YZ83GD8L7GG84979J516");
}
#[cfg(feature = "url")]
#[test]
fn test_url_to_lei() {
use url::Url;
let url = Url::parse("urn:lei:YZ83GD8L7GG84979J516").unwrap();
let lei = LegalEntityId::try_from(url).unwrap();
assert_eq!(lei.as_str(), "YZ83GD8L7GG84979J516");
}
}