/* * This file is part of ActivityStreams. * * Copyright © 2020 Riley Trautman * * ActivityStreams is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ActivityStreams is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ActivityStreams. If not, see . */ /// The type xsd:anyURI represents a Uniform Resource Identifier (URI) reference. /// /// URIs are used to identify resources, and they may be absolute or relative. Absolute URIs /// provide the entire context for locating the resources, such as http://datypic.com/prod.html. /// Relative URIs are specified as the difference from a base URI, such as ../prod.html. It is also /// possible to specify a fragment identifier, using the # character, such as ../prod.html#shirt. /// /// The three previous examples happen to be HTTP URLs (Uniform Resource Locators), but URIs also /// encompass URLs of other schemes (e.g., FTP, gopher, telnet), as well as URNs (Uniform Resource /// Names). URIs are not required to be dereferencable; that is, it is not necessary for there to /// be a web page at http://datypic.com/prod.html in order for this to be a valid URI. /// /// URIs require that some characters be escaped with their hexadecimal Unicode code point preceded /// by the % character. This includes non-ASCII characters and some ASCII characters, namely /// control characters, spaces, and the following characters (unless they are used as deliimiters /// in the URI): <>#%{}|\^`. For example, ../édition.html must be represented instead as /// ../%C3%A9dition.html, with the é escaped as %C3%A9. However, the anyURI type will accept these /// characters either escaped or unescaped. With the exception of the characters % and #, it will /// assume that unescaped characters are intended to be escaped when used in an actual URI, /// although the schema processor will do nothing to alter them. It is valid for an anyURI value to /// contain a space, but this practice is strongly discouraged. Spaces should instead be escaped /// using %20. /// /// The schema processor is not required to parse the contents of an xsd:anyURI value to determine /// whether it is valid according to any particular URI scheme. Since the bare minimum rules for /// valid URI references are fairly generic, the schema processor will accept most character /// strings, including an empty value. The only values that are not accepted are ones that make /// inappropriate use of reserved characters, such as ones that contain multiple # characters or /// have % characters that are not followed by two hexadecimal digits. /// /// Note that when relative URI references such as "../prod" are used as values of xsd:anyURI, no /// attempt is made to determine or keep track of the base URI to which they may be applied. For /// more information on URIs, see RFC 2396, Uniform Resource Identifiers (URI): Generic Syntax. #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct XsdAnyUri(url::Url); /// The error type produced when an XsdAnyUri cannot be parsed #[derive(Clone, Debug, thiserror::Error)] #[error("Could not parse XsdAnyUri")] pub struct XsdAnyUriError; impl XsdAnyUri { /// Borrow the underlying string from the XsdAnyUri pub fn as_str(&self) -> &str { self.as_ref() } /// Borrow a `url::Url` from the XsdAnyUri pub fn as_url(&self) -> &url::Url { self.as_ref() } /// Mutably borrow a `url::Url` from the XsdAnyUri pub fn as_url_mut(&mut self) -> &mut url::Url { self.as_mut() } } impl From for XsdAnyUri { fn from(u: url::Url) -> Self { XsdAnyUri(u) } } impl From for url::Url { fn from(u: XsdAnyUri) -> Self { u.0 } } impl Default for XsdAnyUri { fn default() -> Self { "data:text/plain,uwu".parse().unwrap() } } impl AsRef for XsdAnyUri { fn as_ref(&self) -> &str { self.0.as_ref() } } impl AsRef for XsdAnyUri { fn as_ref(&self) -> &url::Url { &self.0 } } impl AsMut for XsdAnyUri { fn as_mut(&mut self) -> &mut url::Url { &mut self.0 } } impl std::convert::TryFrom for XsdAnyUri { type Error = XsdAnyUriError; fn try_from(s: String) -> Result { s.parse() } } impl std::convert::TryFrom<&str> for XsdAnyUri { type Error = XsdAnyUriError; fn try_from(s: &str) -> Result { s.parse() } } impl std::convert::TryFrom<&mut str> for XsdAnyUri { type Error = XsdAnyUriError; fn try_from(s: &mut str) -> Result { s.parse() } } impl std::str::FromStr for XsdAnyUri { type Err = XsdAnyUriError; fn from_str(s: &str) -> Result { Ok(XsdAnyUri(s.parse().map_err(|_| XsdAnyUriError)?)) } } impl std::fmt::Display for XsdAnyUri { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { std::fmt::Display::fmt(&self.0, f) } } impl serde::ser::Serialize for XsdAnyUri { fn serialize(&self, serializer: S) -> Result where S: serde::ser::Serializer, { serializer.serialize_str(&self.0.to_string()) } } impl<'de> serde::de::Deserialize<'de> for XsdAnyUri { fn deserialize(deserializer: D) -> Result where D: serde::de::Deserializer<'de>, { let s = String::deserialize(deserializer)?; s.parse().map_err(serde::de::Error::custom) } }