make the parser use the TryFrom trait.

This commit is contained in:
Dietrich 2020-09-22 20:09:53 +02:00
parent c9cba38f2f
commit 8c1a0a52f6

View File

@ -1,4 +1,5 @@
use std::cmp::Eq; use std::cmp::Eq;
use std::convert::TryFrom;
use std::fmt::{self, Display}; use std::fmt::{self, Display};
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
@ -64,49 +65,23 @@ impl<'a> Passwd<'a> {
return Err("Failed to parse: not enough elements"); return Err("Failed to parse: not enough elements");
} else { } else {
Ok(Passwd { Ok(Passwd {
username: Username { username: Username::try_from(*elements.get(0).unwrap())
username: elements.get(0).unwrap(), .expect("failed to parse username."),
}, password: Password::try_from(*elements.get(1).unwrap())
password: Password { .expect("Failed to parse Password"),
password: elements.get(1).unwrap(), uid: Uid::try_from(*elements.get(2).unwrap()).expect("Failed to parse uid"),
}, gid: Gid::try_from(*elements.get(3).unwrap()).expect("Failed to parse gid"),
uid: Uid { gecos: Gecos::try_from(*elements.get(4).unwrap())
uid: elements.get(2).unwrap().parse::<u32>().unwrap(), .expect("Failed to parse Gecos field"),
}, home_dir: HomeDir::try_from(*elements.get(5).unwrap())
gid: Gid { .expect("Failed to parse home directory"),
gid: elements.get(3).unwrap().parse::<u32>().unwrap(), shell_dir: ShellDir::try_from(*elements.get(6).unwrap())
}, .expect("Failed to parse shell directory"),
gecos: parse_gecos(elements.get(4).unwrap()).unwrap(),
home_dir: HomeDir {
dir: elements.get(5).unwrap(),
},
shell_dir: ShellDir {
shell: elements.get(6).unwrap(),
},
}) })
} }
} }
} }
fn parse_gecos(source: &str) -> Result<Gecos, &str> {
let vals: Vec<&str> = source.split(',').collect();
if vals.len() == 5 {
Ok(Gecos::Detail {
full_name: vals.get(0).unwrap(),
room: vals.get(1).unwrap(),
phone_work: vals.get(2).unwrap(),
phone_home: vals.get(3).unwrap(),
other: vals.get(4).unwrap(),
})
} else if vals.len() == 1 {
Ok(Gecos::Simple {
comment: vals.get(0).unwrap(),
})
} else {
panic!(format!("Could not parse this string: {}", source))
}
}
impl Default for Passwd<'_> { impl Default for Passwd<'_> {
fn default() -> Self { fn default() -> Self {
Passwd { Passwd {
@ -151,24 +126,56 @@ impl Display for Username<'_> {
} }
} }
impl<'a> TryFrom<&'a str> for Username<'a> {
type Error = &'static str;
fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
Ok(Self { username: source })
}
}
impl Display for Password<'_> { impl Display for Password<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.password,) write!(f, "{}", self.password,)
} }
} }
impl<'a> TryFrom<&'a str> for Password<'a> {
type Error = &'static str;
fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
Ok(Self { password: source })
}
}
impl Display for Uid { impl Display for Uid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.uid,) write!(f, "{}", self.uid,)
} }
} }
impl TryFrom<&str> for Uid {
type Error = &'static str;
fn try_from(source: &str) -> std::result::Result<Self, Self::Error> {
Ok(Self {
uid: source.parse::<u32>().unwrap(),
})
}
}
impl Display for Gid { impl Display for Gid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.gid,) write!(f, "{}", self.gid,)
} }
} }
impl TryFrom<&str> for Gid {
type Error = &'static str;
fn try_from(source: &str) -> std::result::Result<Self, Self::Error> {
Ok(Self {
gid: source.parse::<u32>().unwrap(),
})
}
}
impl Display for Gecos<'_> { impl Display for Gecos<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self { match &self {
@ -188,18 +195,54 @@ impl Display for Gecos<'_> {
} }
} }
impl<'a> TryFrom<&'a str> for Gecos<'a> {
type Error = &'static str;
fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
let vals: Vec<&str> = source.split(',').collect();
if vals.len() == 5 {
Ok(Gecos::Detail {
full_name: vals.get(0).unwrap(),
room: vals.get(1).unwrap(),
phone_work: vals.get(2).unwrap(),
phone_home: vals.get(3).unwrap(),
other: vals.get(4).unwrap(),
})
} else if vals.len() == 1 {
Ok(Gecos::Simple {
comment: vals.get(0).unwrap(),
})
} else {
panic!(format!("Could not parse this string: {}", source))
}
}
}
impl Display for HomeDir<'_> { impl Display for HomeDir<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.dir,) write!(f, "{}", self.dir,)
} }
} }
impl<'a> TryFrom<&'a str> for HomeDir<'a> {
type Error = &'static str;
fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
Ok(Self { dir: source })
}
}
impl Display for ShellDir<'_> { impl Display for ShellDir<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.shell,) write!(f, "{}", self.shell,)
} }
} }
impl<'a> TryFrom<&'a str> for ShellDir<'a> {
type Error = &'static str;
fn try_from(source: &'a str) -> std::result::Result<Self, Self::Error> {
Ok(Self { shell: source })
}
}
// Tests ---------------------------------------------------------------------- // Tests ----------------------------------------------------------------------
#[test] #[test]
@ -216,8 +259,8 @@ fn test_parse_gecos() {
// test if the Gecos field can be parsed and the resulting struct is populated correctly. // test if the Gecos field can be parsed and the resulting struct is populated correctly.
let gcd = "Full Name,504,11345342,ä1-2312,myemail@test.com"; let gcd = "Full Name,504,11345342,ä1-2312,myemail@test.com";
let gcs = "A böring comment →"; let gcs = "A böring comment →";
let res_detail = parse_gecos(gcd).unwrap(); let res_detail = Gecos::try_from(gcd).unwrap();
let res_simple = parse_gecos(gcs).unwrap(); let res_simple = Gecos::try_from(gcs).unwrap();
match res_simple { match res_simple {
Gecos::Simple { comment } => assert_eq!(comment, "A böring comment →"), Gecos::Simple { comment } => assert_eq!(comment, "A böring comment →"),
_ => unreachable!(), _ => unreachable!(),