use crate::error::FsTypeError;
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FsType(String);
impl FsType {
pub fn new(s: impl Into<String>) -> Result<Self, FsTypeError> {
let s = s.into();
if s.is_empty() {
Err(FsTypeError::Empty)
} else {
Ok(FsType(s))
}
}
#[must_use]
pub fn swap() -> Self {
FsType("swap".to_owned())
}
#[must_use]
pub fn bind() -> Self {
FsType("none".to_owned())
}
pub fn parse(raw: &str) -> Result<Self, FsTypeError> {
Self::new(raw)
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
#[must_use]
pub fn is_swap(&self) -> bool {
self.0 == "swap"
}
#[must_use]
pub fn is_bind(&self) -> bool {
self.0 == "none"
}
#[must_use]
pub fn is_network(&self) -> bool {
let primary = self.primary();
matches!(
primary,
"nfs"
| "nfs4"
| "cifs"
| "smb"
| "smbfs"
| "ncpfs"
| "glusterfs"
| "ceph"
| "lustre"
| "afs"
)
}
#[must_use]
pub fn is_pseudo(&self) -> bool {
let primary = self.primary();
matches!(
primary,
"proc"
| "sysfs"
| "tmpfs"
| "devpts"
| "devtmpfs"
| "cgroup"
| "cgroup2"
| "configfs"
| "debugfs"
| "tracefs"
| "securityfs"
| "pstore"
| "efivarfs"
| "bpf"
| "fusectl"
| "mqueue"
| "hugetlbfs"
| "autofs"
| "binfmt_misc"
| "ramfs"
| "pipefs"
| "sockfs"
| "bdev"
)
}
#[must_use]
pub fn primary(&self) -> &str {
self.0
.split(',')
.next()
.and_then(|s| s.split('.').next())
.unwrap_or(&self.0)
}
pub fn iter(&self) -> impl Iterator<Item = &str> {
self.0.split(',')
}
}
impl fmt::Display for FsType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl std::str::FromStr for FsType {
type Err = FsTypeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl std::ops::Deref for FsType {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<String> for FsType {
fn from(s: String) -> Self {
FsType(s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_simple() {
let ft = FsType::parse("ext4").unwrap();
assert_eq!(ft.as_str(), "ext4");
assert!(!ft.is_swap());
assert!(!ft.is_bind());
}
#[test]
fn parse_swap() {
let ft = FsType::parse("swap").unwrap();
assert!(ft.is_swap());
}
#[test]
fn parse_none_for_bind() {
let ft = FsType::parse("none").unwrap();
assert!(ft.is_bind());
}
#[test]
fn parse_with_subtype() {
let ft = FsType::parse("fuse.sshfs").unwrap();
assert_eq!(ft.primary(), "fuse");
assert_eq!(ft.as_str(), "fuse.sshfs");
}
#[test]
fn parse_type_list() {
let ft = FsType::parse("nfs,ext4").unwrap();
assert_eq!(ft.primary(), "nfs");
let types: Vec<&str> = ft.iter().collect();
assert_eq!(types, vec!["nfs", "ext4"]);
}
#[test]
fn is_network() {
assert!(FsType::parse("nfs").unwrap().is_network());
assert!(FsType::parse("nfs4").unwrap().is_network());
assert!(FsType::parse("cifs").unwrap().is_network());
assert!(FsType::parse("smb").unwrap().is_network());
assert!(!FsType::parse("ext4").unwrap().is_network());
assert!(!FsType::parse("xfs").unwrap().is_network());
}
#[test]
fn is_pseudo() {
assert!(FsType::parse("proc").unwrap().is_pseudo());
assert!(FsType::parse("sysfs").unwrap().is_pseudo());
assert!(FsType::parse("tmpfs").unwrap().is_pseudo());
assert!(FsType::parse("devpts").unwrap().is_pseudo());
assert!(FsType::parse("cgroup2").unwrap().is_pseudo());
assert!(!FsType::parse("ext4").unwrap().is_pseudo());
}
#[test]
fn parse_empty_is_error() {
assert!(FsType::parse("").is_err());
}
#[test]
fn swap_constructor() {
assert_eq!(FsType::swap().as_str(), "swap");
}
#[test]
fn bind_constructor() {
assert_eq!(FsType::bind().as_str(), "none");
}
#[test]
fn parse_auto_type() {
let ft = FsType::parse("auto").unwrap();
assert_eq!(ft.as_str(), "auto");
}
#[test]
fn parse_ignore_is_not_swap() {
let ft = FsType::parse("ignore").unwrap();
assert!(!ft.is_swap());
assert!(!ft.is_bind());
}
#[test]
fn from_str_works() {
use std::str::FromStr;
let ft = FsType::from_str("ext4").unwrap();
assert_eq!(ft.as_str(), "ext4");
}
#[test]
fn deref_works() {
let ft = FsType::new("ext4").unwrap();
assert_eq!(&*ft, "ext4");
assert_eq!(ft.len(), 4); }
#[test]
fn display() {
assert_eq!(FsType::parse("ext4").unwrap().to_string(), "ext4");
assert_eq!(
FsType::parse("fuse.sshfs").unwrap().to_string(),
"fuse.sshfs"
);
}
}