From 8c1a0a52f67ad22d64b9a3a53eba5be1f14773b5 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Tue, 22 Sep 2020 20:09:53 +0200 Subject: [PATCH] make the parser use the TryFrom trait. --- src/passwd.rs | 123 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 40 deletions(-) diff --git a/src/passwd.rs b/src/passwd.rs index ae6bd42..9f7eb25 100644 --- a/src/passwd.rs +++ b/src/passwd.rs @@ -1,4 +1,5 @@ use std::cmp::Eq; +use std::convert::TryFrom; use std::fmt::{self, Display}; #[derive(Debug, PartialEq, Eq)] @@ -64,49 +65,23 @@ impl<'a> Passwd<'a> { return Err("Failed to parse: not enough elements"); } else { Ok(Passwd { - username: Username { - username: elements.get(0).unwrap(), - }, - password: Password { - password: elements.get(1).unwrap(), - }, - uid: Uid { - uid: elements.get(2).unwrap().parse::().unwrap(), - }, - gid: Gid { - gid: elements.get(3).unwrap().parse::().unwrap(), - }, - gecos: parse_gecos(elements.get(4).unwrap()).unwrap(), - home_dir: HomeDir { - dir: elements.get(5).unwrap(), - }, - shell_dir: ShellDir { - shell: elements.get(6).unwrap(), - }, + username: Username::try_from(*elements.get(0).unwrap()) + .expect("failed to parse username."), + password: Password::try_from(*elements.get(1).unwrap()) + .expect("Failed to parse Password"), + 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"), + gecos: Gecos::try_from(*elements.get(4).unwrap()) + .expect("Failed to parse Gecos field"), + home_dir: HomeDir::try_from(*elements.get(5).unwrap()) + .expect("Failed to parse home directory"), + shell_dir: ShellDir::try_from(*elements.get(6).unwrap()) + .expect("Failed to parse shell directory"), }) } } } -fn parse_gecos(source: &str) -> Result { - 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<'_> { fn default() -> Self { 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 { + Ok(Self { username: source }) + } +} + impl Display for Password<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 { + Ok(Self { password: source }) + } +} + impl Display for Uid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.uid,) } } +impl TryFrom<&str> for Uid { + type Error = &'static str; + fn try_from(source: &str) -> std::result::Result { + Ok(Self { + uid: source.parse::().unwrap(), + }) + } +} + impl Display for Gid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.gid,) } } +impl TryFrom<&str> for Gid { + type Error = &'static str; + fn try_from(source: &str) -> std::result::Result { + Ok(Self { + gid: source.parse::().unwrap(), + }) + } +} + impl Display for Gecos<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 { + 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<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 { + Ok(Self { dir: source }) + } +} + impl Display for ShellDir<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 { + Ok(Self { shell: source }) + } +} + // Tests ---------------------------------------------------------------------- #[test] @@ -216,8 +259,8 @@ fn test_parse_gecos() { // 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 gcs = "A böring comment →"; - let res_detail = parse_gecos(gcd).unwrap(); - let res_simple = parse_gecos(gcs).unwrap(); + let res_detail = Gecos::try_from(gcd).unwrap(); + let res_simple = Gecos::try_from(gcs).unwrap(); match res_simple { Gecos::Simple { comment } => assert_eq!(comment, "A böring comment →"), _ => unreachable!(),