Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 52 additions & 66 deletions exercises/23_conversions/from_into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,128 +3,114 @@
// You can read more about it in the documentation:
// https://doc.rust-lang.org/std/convert/trait.From.html

#[derive(Debug)]
use std::convert::{TryFrom, TryInto};
use std::num::ParseIntError;

#[derive(Debug, PartialEq)]
struct Person {
name: String,
age: u8,
}

// We implement the Default trait to use it as a fallback when the provided
// string is not convertible into a `Person` object.
impl Default for Person {
fn default() -> Self {
Self {
name: String::from("John"),
age: 30,
}
}
// We will use this error type for the `TryFrom` implementation.
#[derive(Debug, PartialEq)]
enum ParsePersonError {
// Incorrect number of fields
BadLen,
// Empty name field
NoName,
// Wrapped error from parse::<u8>()
ParseInt(ParseIntError),
}

// TODO: Complete this `From` implementation to be able to parse a `Person`
// TODO: Complete this `TryFrom` implementation to be able to parse a `Person`
// out of a string in the form of "Mark,20".
// Note that you'll need to parse the age component into a `u8` with something
// like `"4".parse::<u8>()`.
//
// Steps:
// 1. Split the given string on the commas present in it.
// 2. If the split operation returns less or more than 2 elements, return the
// default of `Person`.
// error `ParsePersonError::BadLen`.
// 3. Use the first element from the split operation as the name.
// 4. If the name is empty, return the default of `Person`.
// 4. If the name is empty, return the error `ParsePersonError::NoName`.
// 5. Parse the second element from the split operation into a `u8` as the age.
// 6. If parsing the age fails, return the default of `Person`.
impl From<&str> for Person {
fn from(s: &str) -> Self {}
// 6. If parsing the age fails, return the error `ParsePersonError::ParseInt`.
impl TryFrom<&str> for Person {
type Error = ParsePersonError;

fn try_from(s: &str) -> Result<Self, Self::Error> {}
}

fn main() {
// Use the `from` function.
let p1 = Person::from("Mark,20");
// Use the `try_from` function.
let p1 = Person::try_from("Mark,20");
println!("{p1:?}");

// Since `From` is implemented for Person, we are able to use `Into`.
let p2: Person = "Gerald,70".into();
// Since `TryFrom` is implemented for Person, we are able to use `try_into`.
let p2: Result<Person, ParsePersonError> = "Gerald,70".try_into();
println!("{p2:?}");
}

#[cfg(test)]
mod tests {
use super::*;
use ParsePersonError::*;

#[test]
fn test_default() {
let dp = Person::default();
assert_eq!(dp.name, "John");
assert_eq!(dp.age, 30);
fn empty_input() {
assert_eq!(Person::try_from(""), Err(BadLen));
}

#[test]
fn test_bad_convert() {
let p = Person::from("");
fn good_input() {
let p = Person::try_from("John,32");
assert!(p.is_ok());
let p = p.unwrap();
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
assert_eq!(p.age, 32);
}

#[test]
fn test_good_convert() {
let p = Person::from("Mark,20");
assert_eq!(p.name, "Mark");
assert_eq!(p.age, 20);
}

#[test]
fn test_bad_age() {
let p = Person::from("Mark,twenty");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
fn missing_age() {
assert!(matches!(Person::try_from("John,"), Err(ParseInt(_))));
}

#[test]
fn test_missing_comma_and_age() {
let p: Person = Person::from("Mark");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
fn invalid_age() {
assert!(matches!(Person::try_from("John,twenty"), Err(ParseInt(_))));
}

#[test]
fn test_missing_age() {
let p: Person = Person::from("Mark,");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
fn missing_comma_and_age() {
assert_eq!(Person::try_from("John"), Err(BadLen));
}

#[test]
fn test_missing_name() {
let p: Person = Person::from(",1");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
fn missing_name() {
assert_eq!(Person::try_from(",1"), Err(NoName));
}

#[test]
fn test_missing_name_and_age() {
let p: Person = Person::from(",");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
fn missing_name_and_age() {
assert!(matches!(Person::try_from(","), Err(NoName | ParseInt(_))));
}

#[test]
fn test_missing_name_and_invalid_age() {
let p: Person = Person::from(",one");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
fn missing_name_and_invalid_age() {
assert!(matches!(
Person::try_from(",one"),
Err(NoName | ParseInt(_)),
));
}

#[test]
fn test_trailing_comma() {
let p: Person = Person::from("Mike,32,");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
fn trailing_comma() {
assert_eq!(Person::try_from("John,32,"), Err(BadLen));
}

#[test]
fn test_trailing_comma_and_some_string() {
let p: Person = Person::from("Mike,32,dog");
assert_eq!(p.name, "John");
assert_eq!(p.age, 30);
fn trailing_comma_and_some_string() {
assert_eq!(Person::try_from("John,32,man"), Err(BadLen));
}
}
Loading