1use std::{error::Error, fmt, str::FromStr};
6
7#[derive(Clone, Debug, PartialEq, Eq, Hash)]
9pub struct Urn {
10 pub owner: String,
15
16 pub id: String,
19}
20
21impl fmt::Display for Urn {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 write!(f, "extension:{}:{}", self.owner, self.id)
24 }
25}
26
27#[derive(Debug, PartialEq)]
29pub struct InvalidUrn;
30
31impl fmt::Display for InvalidUrn {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 write!(f, "invalid urn")
34 }
35}
36
37impl Error for InvalidUrn {}
38
39impl FromStr for Urn {
40 type Err = InvalidUrn;
41
42 fn from_str(s: &str) -> Result<Self, Self::Err> {
43 s.split_once(':')
44 .filter(|(extension, _)| *extension == "extension")
45 .map(|(_, segments)| segments)
46 .and_then(|segments| segments.split_once(':'))
47 .filter(|(owner, id)| !owner.is_empty() && !id.is_empty())
48 .map(|(owner, id)| Urn {
49 owner: owner.to_owned(),
50 id: id.to_owned(),
51 })
52 .ok_or(InvalidUrn)
53 }
54}