use std::fmt;
use std::str::FromStr;
use crate::core::device::BlockDevice;
use crate::core::device::MountPoint;
use crate::core::device::Pseudo;
use crate::core::device::SmbFs;
use crate::core::device::SshFs;
use crate::core::device::Tag;
use crate::core::device::NFS;
use crate::core::errors::ParserError;
#[derive(Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Source {
BlockDevice(BlockDevice),
MountPoint(MountPoint),
NFS(NFS),
SmbFs(SmbFs),
SshFs(SshFs),
Tag(Tag),
PseudoFs(Pseudo),
}
impl Source {
pub fn is_block_device(&self) -> bool {
matches!(self, Self::BlockDevice(_))
}
pub fn is_mount_point(&self) -> bool {
matches!(self, Self::MountPoint(_))
}
pub fn is_nfs_share(&self) -> bool {
matches!(self, Self::NFS(_))
}
pub fn is_samba_share(&self) -> bool {
matches!(self, Self::SmbFs(_))
}
pub fn is_sshfs_share(&self) -> bool {
matches!(self, Self::SshFs(_))
}
pub fn is_tag(&self) -> bool {
matches!(self, Self::Tag(_))
}
pub fn is_pseudo_fs(&self) -> bool {
matches!(self, Self::PseudoFs(_))
}
pub fn is_tag_label(&self) -> bool {
matches!(self, Self::Tag(t) if t.is_label())
}
pub fn is_tag_partition_label(&self) -> bool {
matches!(self, Self::Tag(t) if t.is_partition_label())
}
pub fn is_tag_uuid(&self) -> bool {
matches!(self, Self::Tag(t) if t.is_uuid())
}
pub fn is_tag_partition_uuid(&self) -> bool {
matches!(self, Self::Tag(t) if t.is_partition_uuid())
}
pub fn is_tag_id(&self) -> bool {
matches!(self, Self::Tag(t) if t.is_id())
}
}
impl AsRef<Source> for Source {
#[inline]
fn as_ref(&self) -> &Source {
self
}
}
impl TryFrom<&str> for Source {
type Error = ParserError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
Tag::from_str(s)
.map(Self::from)
.or_else(|_| Pseudo::from_str(s).map(Self::from))
.or_else(|_| SmbFs::from_str(s).map(Self::from))
.or_else(|_| SshFs::from_str(s).map(Self::from))
.or_else(|_| NFS::from_str(s).map(Self::from))
.or_else(|_| MountPoint::from_str(s).map(Self::from))
.or_else(|_| BlockDevice::from_str(s).map(Self::from))
}
}
impl TryFrom<String> for Source {
type Error = ParserError;
#[inline]
fn try_from(s: String) -> Result<Self, Self::Error> {
Self::try_from(s.as_str())
}
}
impl TryFrom<&String> for Source {
type Error = ParserError;
#[inline]
fn try_from(s: &String) -> Result<Self, Self::Error> {
Self::try_from(s.as_str())
}
}
impl FromStr for Source {
type Err = ParserError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(s)
}
}
impl fmt::Display for Source {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let output = match self {
Self::BlockDevice(device) => device.to_string(),
Self::MountPoint(mount_point) => mount_point.to_string(),
Self::NFS(share) => share.to_string(),
Self::SmbFs(share) => share.to_string(),
Self::SshFs(share) => share.to_string(),
Self::Tag(tag) => tag.to_string(),
Self::PseudoFs(fs) => fs.to_string(),
};
write!(f, "{}", output)
}
}
impl From<BlockDevice> for Source {
#[inline]
fn from(device: BlockDevice) -> Source {
Source::BlockDevice(device)
}
}
impl From<MountPoint> for Source {
#[inline]
fn from(mount_point: MountPoint) -> Source {
Source::MountPoint(mount_point)
}
}
impl From<NFS> for Source {
#[inline]
fn from(share: NFS) -> Source {
Source::NFS(share)
}
}
impl From<SmbFs> for Source {
#[inline]
fn from(share: SmbFs) -> Source {
Source::SmbFs(share)
}
}
impl From<SshFs> for Source {
#[inline]
fn from(share: SshFs) -> Source {
Source::SshFs(share)
}
}
impl From<Tag> for Source {
#[inline]
fn from(share: Tag) -> Source {
Source::Tag(share)
}
}
impl From<Pseudo> for Source {
#[inline]
fn from(fs: Pseudo) -> Source {
Source::PseudoFs(fs)
}
}
#[cfg(test)]
#[allow(unused_imports)]
mod tests {
use super::*;
use pretty_assertions::{assert_eq, assert_ne};
#[test]
#[should_panic(expected = "expected a device path instead of")]
fn source_does_not_parse_an_empty_string_as_a_block_device() {
let source = "";
let _ = Source::try_from(source).unwrap();
}
#[test]
fn source_parses_a_block_device() -> crate::Result<()> {
let source = "/dev/vda";
let actual: Source = source.parse()?;
assert!(actual.is_block_device());
Ok(())
}
#[test]
fn source_parses_a_mount_point() -> crate::Result<()> {
let source = "/boot";
let actual: Source = source.parse()?;
assert!(actual.is_mount_point());
Ok(())
}
#[test]
fn source_parses_a_nfs_share_address_as_an_sshfs_share() -> crate::Result<()> {
let source = "localhost:/share";
let actual: Source = source.parse()?;
assert!(actual.is_sshfs_share());
Ok(())
}
#[test]
fn source_parses_a_samba_share_address() -> crate::Result<()> {
let source = "smb://localhost/share";
let actual: Source = source.parse()?;
assert!(actual.is_samba_share());
Ok(())
}
#[test]
fn source_parses_a_sshfs_share_address() -> crate::Result<()> {
let source = "user@localhost:/share";
let actual: Source = source.parse()?;
assert!(actual.is_sshfs_share());
Ok(())
}
#[test]
fn source_parses_a_uuid_tag() -> crate::Result<()> {
let source = "UUID=dd476616-1ce4-415e-9dbd-8c2fa8f42f0f";
let actual: Source = source.parse()?;
assert!(actual.is_tag_uuid());
Ok(())
}
#[test]
fn source_parses_a_pseudo_fs() -> crate::Result<()> {
let source = "none";
let actual: Source = source.parse()?;
assert!(actual.is_pseudo_fs());
Ok(())
}
}