Skip to content

Commit

Permalink
Implement trait TryFrom for Letter
Browse files Browse the repository at this point in the history
TryFrom is implemented for '&char' instead of 'char' due to a conflict
with the blanket implementation.

For more details see:
rust-lang/rust#50133
https://old.reddit.com/r/rust/comments/c1yubv/why_this_code_does_not_compile/
  • Loading branch information
oliverlee committed Aug 31, 2019
1 parent 534b810 commit 89c11ab
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 18 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
lazy_static = "1.4.0"
119 changes: 101 additions & 18 deletions src/letter.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,66 @@
use crate::mark::Mark;
use std::convert;
use std::collections::HashSet;
use std::convert::{From, TryFrom};
use std::fmt;

lazy_static! {
static ref VALID_LETTERS: HashSet<char> = {
let mut s = HashSet::new();
s.insert('A');
s.insert('B');
s.insert('C');
s.insert('D');
s.insert('E');
s.insert('F');
s.insert('G');
s.insert('H');
s.insert('I');
s.insert('J');
s.insert('K');
s.insert('L');
s.insert('M');
s.insert('N');
s.insert('O');
s.insert('P');
s.insert('Q');
s.insert('R');
s.insert('S');
s.insert('T');
s.insert('U');
s.insert('V');
s.insert('W');
s.insert('X');
s.insert('Y');
s.insert('Z');
s.insert('0');
s.insert('1');
s.insert('2');
s.insert('3');
s.insert('4');
s.insert('5');
s.insert('6');
s.insert('7');
s.insert('8');
s.insert('9');
s.insert('&');
s.insert('\'');
s.insert('@');
s.insert(')');
s.insert('(');
s.insert(':');
s.insert(',');
s.insert('=');
s.insert('!');
s.insert('.');
s.insert('-');
s.insert('+');
s.insert('"');
s.insert('?');
s.insert('/');
s
};
}

pub enum Letter {
A,
B,
Expand Down Expand Up @@ -56,7 +115,6 @@ pub enum Letter {
Slash,
}


impl Letter {
pub fn str_ref(&self) -> &'static str {
match self {
Expand Down Expand Up @@ -115,13 +173,11 @@ impl Letter {
}

pub fn marks(&self) -> Vec<Mark> {
self.str_ref().chars()
.map(|c| Mark::from(c))
.collect()
self.str_ref().chars().map(|c| Mark::from(c)).collect()
}
}

impl convert::From<char> for Letter {
impl From<char> for Letter {
fn from(c: char) -> Self {
match c {
'A' => Letter::A,
Expand Down Expand Up @@ -161,7 +217,7 @@ impl convert::From<char> for Letter {
'8' => Letter::Digit8,
'9' => Letter::Digit9,
'&' => Letter::Ampersand,
'\'' =>Letter::Apostrophe,
'\'' => Letter::Apostrophe,
'@' => Letter::At,
')' => Letter::BracketClose,
'(' => Letter::BracketOpen,
Expand All @@ -175,25 +231,35 @@ impl convert::From<char> for Letter {
'"' => Letter::Quote,
'?' => Letter::Query,
'/' => Letter::Slash,
_ => panic!("Unexpected char for Letter"),
_ => panic!("Unexpected char for Letter: {}", c),
}
}
}

impl TryFrom<&char> for Letter {
type Error = &'static str;

fn try_from(c: &char) -> Result<Self, Self::Error> {
println!("{}", c);
if VALID_LETTERS.contains(c) {
Ok(Letter::from(*c))
} else {
Err("Invalid char for Letter")
}
}
}

impl fmt::Display for Letter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
self.str_ref()
)
write!(f, "{}", self.str_ref())
}
}

#[cfg(test)]
mod test {
use super::Letter;
use super::{Letter,VALID_LETTERS};
use crate::mark::Mark;
use std::convert::{From, TryFrom};

#[test]
#[should_panic]
Expand All @@ -215,22 +281,22 @@ mod test {

#[test]
#[allow(non_snake_case)]
fn convert_M() {
fn from_M() {
assert_eq!(Letter::from('M').to_string(), "--");
}

#[test]
fn convert_0() {
fn from_0() {
assert_eq!(Letter::from('0').to_string(), "-----");
}

#[test]
fn convert_period() {
fn from_period() {
assert_eq!(Letter::from('.').to_string(), ".-.-.-");
}

#[test]
fn convert_apostrophe() {
fn from_apostrophe() {
assert_eq!(Letter::from('\'').to_string(), ".----.");
}

Expand All @@ -239,4 +305,21 @@ mod test {
assert_eq!(Letter::M.marks(), vec![Mark::Dash, Mark::Dash]);
}

#[test]
#[allow(non_snake_case)]
fn try_from_M() {
assert_eq!(Letter::try_from('M').unwrap().to_string(), "--");
}

#[test]
fn valid_char() {
assert!(VALID_LETTERS.contains(&'M'));
assert!(!VALID_LETTERS.contains(&'m'));
assert!(!VALID_LETTERS.contains(&' '));
}

#[test]
fn try_from_m() {
assert!(Letter::try_from(&'m').is_err());
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
#[macro_use]
extern crate lazy_static;

pub mod letter;
pub mod mark;

0 comments on commit 89c11ab

Please sign in to comment.