bc_components/id/
uri.rs

1use std::str::FromStr;
2use dcbor::prelude::*;
3use url::Url;
4use anyhow::{ bail, Result, Error };
5
6use crate::tags;
7
8/// A Uniform Resource Identifier (URI).
9///
10/// A URI is a string of characters that unambiguously identifies a particular resource.
11/// This implementation validates URIs using the `url` crate to ensure conformance to RFC 3986.
12///
13/// URIs are commonly used for:
14/// - Web addresses (URLs like "<https://example.com>")
15/// - Resource identifiers in various protocols
16/// - Namespace identifiers
17/// - References to resources in distributed systems
18#[derive(Clone, Debug, Eq, PartialEq, Hash)]
19pub struct URI(String);
20
21impl URI {
22    /// Creates a new `URI` from a string.
23    ///
24    /// No validation is performed on the string.
25    pub fn new(uri: impl Into<String>) -> Result<Self> {
26        let uri = uri.into();
27        if Url::parse(&uri).is_ok() {
28            Ok(Self(uri))
29        } else {
30            bail!("Invalid URI")
31        }
32    }
33}
34
35/// Implements string parsing to create a URI.
36impl FromStr for URI {
37    type Err = Error;
38
39    fn from_str(s: &str) -> Result<Self, Self::Err> {
40        Self::new(s)
41    }
42}
43
44/// Implements `AsRef<str>` to allow URI to be treated as a string slice.
45impl AsRef<str> for URI {
46    fn as_ref(&self) -> &str {
47        &self.0
48    }
49}
50
51/// Implements `AsRef<String>` to allow URI to be treated as a String reference.
52impl AsRef<String> for URI {
53    fn as_ref(&self) -> &String {
54        &self.0
55    }
56}
57
58/// Implements `AsRef<URI>` to allow URI to reference itself.
59impl AsRef<URI> for URI {
60    fn as_ref(&self) -> &URI {
61        self
62    }
63}
64
65/// Implements CBORTagged trait to provide CBOR tag information.
66impl CBORTagged for URI {
67    fn cbor_tags() -> Vec<Tag> {
68        tags_for_values(&[tags::TAG_URI])
69    }
70}
71
72/// Implements conversion from URI to CBOR for serialization.
73impl From<URI> for CBOR {
74    fn from(value: URI) -> Self {
75        value.tagged_cbor()
76    }
77}
78
79/// Implements CBORTaggedEncodable to provide CBOR encoding functionality.
80impl CBORTaggedEncodable for URI {
81    fn untagged_cbor(&self) -> CBOR {
82        self.0.clone().into()
83    }
84}
85
86/// Implements `TryFrom<CBOR>` for URI to support conversion from CBOR data.
87impl TryFrom<CBOR> for URI {
88    type Error = dcbor::Error;
89
90    fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
91        Self::from_tagged_cbor(cbor)
92    }
93}
94
95/// Implements CBORTaggedDecodable to provide CBOR decoding functionality.
96impl CBORTaggedDecodable for URI {
97    fn from_untagged_cbor(cbor: CBOR) -> dcbor::Result<Self> {
98        let uri: String = cbor.try_into()?;
99        Ok(Self::new(uri)?)
100    }
101}
102
103/// Implements Display for URI to format as a string.
104impl std::fmt::Display for URI {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        write!(f, "{}", self.0)
107    }
108}
109
110/// Implements conversion from string slice to URI with validation.
111impl TryFrom<&str> for URI {
112    type Error = Error;
113
114    fn try_from(uri: &str) -> Result<Self, Self::Error> {
115        Self::new(uri)
116    }
117}
118
119/// Implements conversion from String to URI with validation.
120impl TryFrom<String> for URI {
121    type Error = Error;
122
123    fn try_from(uri: String) -> Result<Self, Self::Error> {
124        Self::try_from(uri.as_str())
125    }
126}
127
128/// Implements conversion from URI to String.
129impl From<URI> for String {
130    fn from(uri: URI) -> Self {
131        uri.0
132    }
133}
134
135/// Implements conversion from URI reference to String.
136impl From<&URI> for String {
137    fn from(uri: &URI) -> Self {
138        uri.0.clone()
139    }
140}