mod msdos;
mod unix;
use std::{
convert::{TryFrom, TryInto},
fmt::Display,
ops::Deref,
};
pub use msdos::FtpEntryMsdos;
pub use unix::FtpEntryUnix;
#[non_exhaustive]
#[derive(Debug)]
pub struct FtpEntryPermissions(String);
impl FtpEntryPermissions {
pub fn as_str(&self) -> &str {
&self.0
}
}
impl Display for FtpEntryPermissions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &self.0)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FtpEntryKind {
UNKNOWN,
Directory,
File,
BlockDevice,
CharacterDevice,
Pipe,
Socket,
Symlink,
}
impl From<char> for FtpEntryKind {
fn from(value: char) -> Self {
match value {
'-' => Self::File,
'd' => Self::Directory,
'b' => Self::BlockDevice,
'c' => Self::CharacterDevice,
'p' => Self::Pipe,
's' => Self::Socket,
'l' => Self::Symlink,
_ => Self::UNKNOWN,
}
}
}
impl TryFrom<&str> for FtpEntryKind {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
if value.len() == 1 {
Ok(value.chars().nth(0).unwrap().into())
} else {
Err("length of the value must be equal to 1")
}
}
}
pub trait FtpEntryInfo {
fn new(string: &str) -> Option<Self>
where
for<'a> Self: TryFrom<&'a str>,
{
Self::try_from(string).ok()
}
fn kind(&self) -> FtpEntryKind;
fn name(&self) -> &str;
fn size(&self) -> usize;
fn date_str(&self) -> &str;
}
#[derive(Debug)]
pub enum FtpEntry {
Unix(FtpEntryUnix),
Msdos(FtpEntryMsdos),
}
impl FtpEntry {
pub fn new(string: &str) -> Option<Self> {
string.try_into().ok()
}
pub fn is_unix_type(&self) -> bool {
match self {
FtpEntry::Unix(_) => true,
_ => false,
}
}
pub fn is_msdos_type(&self) -> bool {
match self {
FtpEntry::Msdos(_) => true,
_ => false,
}
}
pub fn to_unix_type(self) -> FtpEntryUnix {
self.try_to_unix_type().expect("FtpEntryType missmatch")
}
pub fn to_msdos_type(self) -> FtpEntryMsdos {
self.try_to_msdos_type().expect("FtpEntryType missmatch")
}
pub fn try_to_unix_type(self) -> Result<FtpEntryUnix, Self> {
if let FtpEntry::Unix(entry) = self {
Ok(entry)
} else {
Err(self)
}
}
pub fn try_to_msdos_type(self) -> Result<FtpEntryMsdos, Self> {
if let FtpEntry::Msdos(entry) = self {
Ok(entry)
} else {
Err(self)
}
}
}
impl Deref for FtpEntry {
type Target = dyn FtpEntryInfo;
fn deref(&self) -> &Self::Target {
match self {
FtpEntry::Msdos(entry) => entry,
FtpEntry::Unix(entry) => entry,
}
}
}
impl TryFrom<&str> for FtpEntry {
type Error = ();
fn try_from(value: &str) -> Result<Self, Self::Error> {
if let Ok(entry) = FtpEntryUnix::try_from(value) {
return Ok(FtpEntry::Unix(entry));
}
if let Ok(entry) = FtpEntryMsdos::try_from(value) {
return Ok(FtpEntry::Msdos(entry));
}
Err(())
}
}