diff --git a/Cargo.lock b/Cargo.lock index d8e2ccf..c92bc37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1442,6 +1442,9 @@ version = "0.1.0" [[package]] name = "outro_04" version = "0.1.0" +dependencies = [ + "thiserror", +] [[package]] name = "outro_08" @@ -2320,6 +2323,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tryfrom" version = "0.1.0" +dependencies = [ + "thiserror", +] [[package]] name = "tungstenite" diff --git a/exercises/05_ticket_v2/13_try_from/Cargo.toml b/exercises/05_ticket_v2/13_try_from/Cargo.toml index 5d70357..8e0d3de 100644 --- a/exercises/05_ticket_v2/13_try_from/Cargo.toml +++ b/exercises/05_ticket_v2/13_try_from/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] +thiserror="*" diff --git a/exercises/05_ticket_v2/13_try_from/src/lib.rs b/exercises/05_ticket_v2/13_try_from/src/lib.rs index e0e1115..4b7795b 100644 --- a/exercises/05_ticket_v2/13_try_from/src/lib.rs +++ b/exercises/05_ticket_v2/13_try_from/src/lib.rs @@ -8,6 +8,36 @@ enum Status { Done, } +// use thiserror::Error; + +#[derive(Debug, thiserror::Error)] +#[error("{reason}, parsing failed.")] +struct ParseError { + reason: String, +} + +impl TryFrom for Status { + type Error = ParseError; + fn try_from(value: String) -> Result { + match value.to_lowercase().as_str() { + "todo" => Ok(Status::ToDo), + "done" => Ok(Status::Done), + "inprogress" => Ok(Status::InProgress), + _ => Err(ParseError { + reason: "Not Valid".to_string(), + }), + } + // Ok(Status::Done) + } +} + +impl TryFrom<&str> for Status { + type Error = ParseError; + fn try_from(value: &str) -> Result { + value.to_string().try_into() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/exercises/05_ticket_v2/14_source/src/lib.rs b/exercises/05_ticket_v2/14_source/src/lib.rs index 9f7cce5..2994f23 100644 --- a/exercises/05_ticket_v2/14_source/src/lib.rs +++ b/exercises/05_ticket_v2/14_source/src/lib.rs @@ -1,3 +1,5 @@ +use status::ParseStatusError; + use crate::status::Status; // We've seen how to declare modules in one of the earliest exercises, but @@ -23,6 +25,8 @@ pub enum TicketNewError { DescriptionCannotBeEmpty, #[error("Description cannot be longer than 500 bytes")] DescriptionTooLong, + #[error("{0}")] + InvalidStatus(#[from] ParseStatusError), } #[derive(Debug, PartialEq, Clone)] @@ -46,8 +50,7 @@ impl Ticket { if description.len() > 500 { return Err(TicketNewError::DescriptionTooLong); } - - // TODO: Parse the status string into a `Status` enum. + let status = Status::try_from(status)?; Ok(Ticket { title, diff --git a/exercises/05_ticket_v2/15_outro/Cargo.toml b/exercises/05_ticket_v2/15_outro/Cargo.toml index dc32a41..757cc87 100644 --- a/exercises/05_ticket_v2/15_outro/Cargo.toml +++ b/exercises/05_ticket_v2/15_outro/Cargo.toml @@ -2,3 +2,6 @@ name = "outro_04" version = "0.1.0" edition = "2021" + +[dependencies] +thiserror="*" diff --git a/exercises/05_ticket_v2/15_outro/src/description.rs b/exercises/05_ticket_v2/15_outro/src/description.rs index ecf55ad..1e486bd 100644 --- a/exercises/05_ticket_v2/15_outro/src/description.rs +++ b/exercises/05_ticket_v2/15_outro/src/description.rs @@ -2,8 +2,33 @@ // enforcing that the description is not empty and is not longer than 500 bytes. // Implement the traits required to make the tests pass too. +#[derive(Debug, PartialEq, Clone)] pub struct TicketDescription(String); +#[derive(Debug, thiserror::Error)] +#[error("{0}")] +pub struct ParseError(String); + +impl TryFrom for TicketDescription { + type Error = ParseError; + fn try_from(value: String) -> Result { + match value.len() { + 0 => Err(ParseError("The description cannot be empty".to_string())), + 501.. => Err(ParseError( + "The description cannot be longer than 500 bytes".to_string(), + )), + _ => Ok(TicketDescription(value)), + } + } +} + +impl TryFrom<&str> for TicketDescription { + type Error = ParseError; + fn try_from(value: &str) -> Result { + value.to_string().try_into() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/exercises/05_ticket_v2/15_outro/src/status.rs b/exercises/05_ticket_v2/15_outro/src/status.rs index 4453d52..10c8b6c 100644 --- a/exercises/05_ticket_v2/15_outro/src/status.rs +++ b/exercises/05_ticket_v2/15_outro/src/status.rs @@ -1,12 +1,36 @@ // TODO: Implement `TryFrom` and `TryFrom<&str>` for the `Status` enum. // The parsing should be case-insensitive. +#[derive(Debug, PartialEq, Clone)] pub enum Status { ToDo, InProgress, Done, } +#[derive(Debug, thiserror::Error)] +#[error("{0}")] +pub struct ParseError(String); + +impl TryFrom for Status { + type Error = ParseError; + fn try_from(value: String) -> Result { + match value.to_lowercase().as_str() { + "todo" => Ok(Status::ToDo), + "done" => Ok(Status::Done), + "inprogress" => Ok(Status::InProgress), + _ => Err(ParseError("Not Valid".to_string())), + } + // Ok(Status::Done) + } +} + +impl TryFrom<&str> for Status { + type Error = ParseError; + fn try_from(value: &str) -> Result { + value.to_string().try_into() + } +} #[cfg(test)] mod tests { use super::*; diff --git a/exercises/05_ticket_v2/15_outro/src/title.rs b/exercises/05_ticket_v2/15_outro/src/title.rs index 7c26c93..15412e7 100644 --- a/exercises/05_ticket_v2/15_outro/src/title.rs +++ b/exercises/05_ticket_v2/15_outro/src/title.rs @@ -2,8 +2,39 @@ // enforcing that the title is not empty and is not longer than 50 bytes. // Implement the traits required to make the tests pass too. +#[derive(Debug, Clone, PartialEq)] pub struct TicketTitle(String); +#[derive(thiserror::Error, Debug)] +#[error("{reason}")] +pub struct InvalidTicketError { + reason: String, +} + +impl TryFrom for TicketTitle { + type Error = InvalidTicketError; + fn try_from(value: String) -> Result { + if value.len() == 0 { + return Err(InvalidTicketError { + reason: "The title cannot be empty".to_string(), + }); + } else if value.len() > 50 { + return Err(InvalidTicketError { + reason: "The title cannot be longer than 50 bytes".to_string(), + }); + } else { + return Ok(TicketTitle(value)); + } + } +} + +impl TryFrom<&str> for TicketTitle { + type Error = InvalidTicketError; + fn try_from(value: &str) -> Result { + value.to_string().try_into() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/exercises/06_ticket_management/00_intro/src/lib.rs b/exercises/06_ticket_management/00_intro/src/lib.rs index 118e483..d0fd0da 100644 --- a/exercises/06_ticket_management/00_intro/src/lib.rs +++ b/exercises/06_ticket_management/00_intro/src/lib.rs @@ -1,6 +1,6 @@ fn intro() -> &'static str { // TODO: fix me 👇 - "I'm ready to __!" + "I'm ready to build a ticket management system!" } #[cfg(test)]