From 6eb3727a6fceca20e36ac17a1f8aadaf91858c0d Mon Sep 17 00:00:00 2001 From: Oliver Lee Date: Sat, 31 Aug 2019 19:45:39 +0200 Subject: [PATCH] Implement trait TryFrom for Letter TryFrom is implemented for '&char' instead of 'char' due to a conflict with the blanket implementation. For more details see: https://github.com/rust-lang/rust/issues/50133 https://old.reddit.com/r/rust/comments/c1yubv/why_this_code_does_not_compile/ --- Cargo.lock | 10 +++++ Cargo.toml | 1 + src/letter.rs | 115 +++++++++++++++++++++++++++++++++++++++++++------- src/lib.rs | 3 ++ 4 files changed, 113 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bd5cc2d..dcae187 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,16 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "morse" version = "0.1.0" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] +[metadata] +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" diff --git a/Cargo.toml b/Cargo.toml index 18c0b9e..0876888 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/letter.rs b/src/letter.rs index 29cd70a..98063de 100644 --- a/src/letter.rs +++ b/src/letter.rs @@ -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 = { + 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, @@ -56,7 +115,6 @@ pub enum Letter { Slash, } - impl Letter { pub fn str_ref(&self) -> &'static str { match self { @@ -115,13 +173,11 @@ impl Letter { } pub fn marks(&self) -> Vec { - self.str_ref().chars() - .map(|c| Mark::from(c)) - .collect() + self.str_ref().chars().map(|c| Mark::from(c)).collect() } } -impl convert::From for Letter { +impl From for Letter { fn from(c: char) -> Self { match c { 'A' => Self::A, @@ -180,20 +236,30 @@ impl convert::From for Letter { } } +impl TryFrom<&char> for Letter { + type Error = &'static str; + + fn try_from(c: &char) -> Result { + 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] @@ -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(), ".----."); } @@ -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()); + } } diff --git a/src/lib.rs b/src/lib.rs index 4d15e5f..ffb54d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,5 @@ +#[macro_use] +extern crate lazy_static; + pub mod letter; pub mod mark;