#![allow(clippy::module_name_repetitions)]
use crate::error::{Error as IriError, Result as IriResult};
use crate::{Authority, Fragment, Host, Path, Port, Query, Scheme, UserInfo, IRI};
use std::convert::TryFrom;
use std::str::FromStr;
#[derive(Debug)]
pub struct IriBuilder {
scheme: Option<Scheme>,
host: Option<Host>,
user_name: Option<String>,
password: Option<String>,
port: Option<Port>,
path: Option<Path>,
query: Option<Query>,
fragment: Option<Fragment>,
}
impl Default for IriBuilder {
fn default() -> Self {
Self {
scheme: None,
host: None,
user_name: None,
password: None,
port: None,
path: None,
query: None,
fragment: None,
}
}
}
impl TryFrom<&mut IriBuilder> for IRI {
type Error = IriError;
fn try_from(builder: &mut IriBuilder) -> Result<Self, Self::Error> {
let mut iri = match &builder.path {
None => IRI::default(),
Some(path) => IRI::new(path),
};
if let Some(scheme) = &builder.scheme {
iri.set_scheme(Some(scheme.clone()));
}
if let Some(host) = &builder.host {
let mut authority = Authority::new(host.clone());
if let Some(port) = &builder.port {
authority.set_port(port.clone());
}
if let Some(user_name) = &builder.user_name {
let mut user_info = UserInfo::new(user_name)?;
if let Some(password) = &builder.password {
user_info.set_password(password)?;
}
authority.set_user_info(user_info);
}
iri.set_authority(Some(authority));
}
if let Some(query) = &builder.query {
iri.set_query(Some(query.clone()));
}
if let Some(fragment) = &builder.fragment {
iri.set_fragment(Some(fragment.clone()));
}
Ok(iri)
}
}
impl IriBuilder {
pub fn scheme(&mut self, scheme: &Scheme) -> &mut Self {
self.scheme = Some(scheme.clone());
self
}
pub fn scheme_str(&mut self, scheme: &str) -> IriResult<&mut Self> {
self.scheme = Some(Scheme::from_str(scheme)?);
Ok(self)
}
pub fn host(&mut self, host: &str) -> IriResult<&mut Self> {
match Host::from_str(host) {
Err(e) => Err(e),
Ok(host) => {
self.host = Some(host);
Ok(self)
}
}
}
pub fn port(&mut self, port: Port) -> &mut Self {
self.port = Some(port);
self
}
pub fn user(&mut self, user_name: &str, password: &str) -> &mut Self {
self.user_name = Some(user_name.to_string());
self.password = Some(password.to_string());
self
}
pub fn user_name(&mut self, user_name: &str) -> &mut Self {
self.user_name = Some(user_name.to_string());
self
}
pub fn password(&mut self, password: &str) -> &mut Self {
self.password = Some(password.to_string());
self
}
pub fn path(&mut self, path: &Path) -> &mut Self {
self.path = Some(path.clone());
self
}
pub fn path_str(&mut self, path: &str) -> IriResult<&mut Self> {
self.path = Some(Path::from_str(path)?);
Ok(self)
}
pub fn append_segment(&mut self, segment: &str) -> &mut Self {
match &mut self.path {
None => self.path = Some(Path::from_str(segment).unwrap()),
Some(path) => path.push(segment).unwrap(),
}
self
}
pub fn query(&mut self, query: &Query) -> &mut Self {
self.query = Some(query.clone());
self
}
pub fn query_str(&mut self, query: &str) -> IriResult<&mut Self> {
self.query = Some(Query::from_str(query)?);
Ok(self)
}
pub fn fragment(&mut self, fragment: &Fragment) -> &mut Self {
self.fragment = Some(fragment.clone());
self
}
pub fn fragment_str(&mut self, fragment: &str) -> IriResult<&mut Self> {
self.fragment = Some(Fragment::from_str(fragment)?);
Ok(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::scheme::Scheme;
use std::convert::TryInto;
#[test]
fn test_http_url() {
fn inner() -> IriResult<IRI> {
let mut builder = IriBuilder::default();
let result: IriResult<IRI> = builder
.scheme(&Scheme::https())
.user_name("john.doe")
.host("www.example.com")?
.port(123.into())
.path_str("/forum/questions/")?
.query_str("tag=networking&order=newest")?
.fragment_str("top")?
.try_into();
assert!(result.is_ok());
result
}
let iri = inner().unwrap();
assert_eq!(
iri.to_string(),
"https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top"
.to_string()
);
}
#[test]
fn test_ldap_url() {
let mut builder = IriBuilder::default();
let builder = builder
.scheme(&Scheme::ldap())
.host("[2001:db8::7]")
.unwrap()
.path_str("/c=GB")
.unwrap()
.query_str("objectClass?one")
.unwrap();
println!("{:#?}", builder);
let result: IriResult<IRI> = builder.try_into();
assert!(result.is_ok());
let iri = result.unwrap();
println!("{:#?}", iri);
assert_eq!(
iri.to_string(),
"ldap://[2001:db8::7]/c=GB?objectClass?one".to_string()
);
}
#[test]
fn test_mailto_iri() {
let mut builder = IriBuilder::default();
let result: IriResult<IRI> = builder
.scheme(&Scheme::mailto())
.path_str("John.Doe@example.com")
.unwrap()
.try_into();
assert!(result.is_ok());
let iri = result.unwrap();
assert_eq!(iri.to_string(), "mailto:John.Doe@example.com".to_string());
}
#[test]
fn test_news_iri() {
let mut builder = IriBuilder::default();
let result: IriResult<IRI> = builder
.scheme(&Scheme::news())
.path_str("comp.infosystems.www.servers.unix")
.unwrap()
.try_into();
assert!(result.is_ok());
let iri = result.unwrap();
assert_eq!(
iri.to_string(),
"news:comp.infosystems.www.servers.unix".to_string()
);
}
#[test]
fn test_tel_iri() {
let mut builder = IriBuilder::default();
let result: IriResult<IRI> = builder
.scheme(&Scheme::tel())
.path_str("+1-816-555-1212")
.unwrap()
.try_into();
assert!(result.is_ok());
let iri = result.unwrap();
assert_eq!(iri.to_string(), "tel:+1-816-555-1212".to_string());
}
#[test]
fn test_telnet_iri() {
let mut builder = IriBuilder::default();
let result: IriResult<IRI> = builder
.scheme(&Scheme::telnet())
.host("192.0.2.16")
.unwrap()
.port(80.into())
.path_str("/")
.unwrap()
.try_into();
assert!(result.is_ok());
let iri = result.unwrap();
assert_eq!(iri.to_string(), "telnet://192.0.2.16:80/".to_string());
}
#[test]
fn test_urn_iri() {
let mut builder = IriBuilder::default();
let result: IriResult<IRI> = builder
.scheme(&Scheme::urn())
.path_str("oasis:names:specification:docbook:dtd:xml:4.1.2")
.unwrap()
.try_into();
assert!(result.is_ok());
let iri = result.unwrap();
assert_eq!(
iri.to_string(),
"urn:oasis:names:specification:docbook:dtd:xml:4.1.2".to_string()
);
}
}