use std::fmt;
use std::str::FromStr;
use crate::core::errors::ParserError;
#[derive(Debug, Eq, PartialEq)]
pub struct SmbFs {
host: String,
share: String,
}
impl SmbFs {
#[doc(hidden)]
pub(crate) fn new<T>(host: T, share: T) -> SmbFs
where
T: AsRef<str>,
{
let host = host.as_ref().to_owned();
let share = share.as_ref().to_owned();
Self { host, share }
}
pub fn host(&self) -> &str {
&self.host
}
pub fn share(&self) -> &str {
&self.share
}
}
impl AsRef<SmbFs> for SmbFs {
#[inline]
fn as_ref(&self) -> &SmbFs {
self
}
}
impl fmt::Display for SmbFs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "smb://{}{}", self.host, self.share)
}
}
impl TryFrom<&str> for SmbFs {
type Error = ParserError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
let err_missing_prefix = format!(
"invalid Samba share address: {}. Missing prefix `smb://`",
s
);
let err_missing_dir = format!(
"invalid Samba share address: {}. Missing host name and/or path of shared file/directory",
s
);
let prefix = "smb://";
let parsed = s
.trim()
.strip_prefix(prefix)
.ok_or(ParserError::SmbFs(err_missing_prefix))
.and_then(|stripped| {
stripped
.split_once('/')
.ok_or(ParserError::SmbFs(err_missing_dir))
})?;
match parsed {
("", _) => {
let err_msg = format!("invalid Samba share address: {}. Missing host name", s);
Err(ParserError::SmbFs(err_msg))
}
(host, share) => {
let share = format!("/{}", share);
let share = SmbFs::new(host, &share);
Ok(share)
}
}
}
}
impl TryFrom<String> for SmbFs {
type Error = ParserError;
#[inline]
fn try_from(s: String) -> Result<Self, Self::Error> {
Self::try_from(s.as_str())
}
}
impl TryFrom<&String> for SmbFs {
type Error = ParserError;
#[inline]
fn try_from(s: &String) -> Result<Self, Self::Error> {
Self::try_from(s.as_str())
}
}
impl FromStr for SmbFs {
type Err = ParserError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(s)
}
}
#[cfg(test)]
#[allow(unused_imports)]
mod tests {
use super::*;
use pretty_assertions::{assert_eq, assert_ne};
#[test]
#[should_panic(expected = "Missing prefix")]
fn samba_share_can_not_parse_an_empty_string() {
let _: SmbFs = "".parse().unwrap();
}
#[test]
#[should_panic(expected = "Missing host name")]
fn samba_share_can_not_parse_an_address_without_a_hostname() {
let _: SmbFs = "smb:///".parse().unwrap();
}
#[test]
#[should_panic(expected = "Missing host name and/or path")]
fn samba_share_can_not_parse_an_address_without_a_hostname_and_share_dir() {
let _: SmbFs = "smb://".parse().unwrap();
}
#[test]
#[should_panic(expected = "Missing host name and/or path")]
fn samba_share_can_not_parse_an_address_without_share_dir() {
let _: SmbFs = "smb://localhost".parse().unwrap();
}
#[test]
fn samba_share_can_parse_an_adress_sharing_the_root_directory() -> crate::Result<()> {
let address = "smb://localhost/";
let actual: SmbFs = address.parse()?;
let expected_host = "localhost";
let expected_share = "/";
assert_eq!(actual.host(), expected_host);
assert_eq!(actual.share(), expected_share);
assert_eq!(&actual.to_string(), address);
Ok(())
}
#[test]
fn samba_share_can_parse_an_adress_sharing_a_directory() -> crate::Result<()> {
let address = "smb://localhost/share";
let actual: SmbFs = address.parse()?;
let expected_host = "localhost";
let expected_share = "/share";
assert_eq!(actual.host(), expected_host);
assert_eq!(actual.share(), expected_share);
assert_eq!(&actual.to_string(), address);
Ok(())
}
}