100 exercises to learn Rust

This commit is contained in:
LukeMathWalker
2024-05-12 22:21:03 +02:00
commit 5edebf6cf2
309 changed files with 13173 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
[package]
name = "common"
version = "0.1.0"
edition = "2021"
[dependencies]

15
helpers/common/src/lib.rs Normal file
View File

@@ -0,0 +1,15 @@
pub fn overly_long_description() -> String {
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.".into()
}
pub fn overly_long_title() -> String {
"A title that's definitely longer than what should be allowed in a development ticket".into()
}
pub fn valid_title() -> String {
"A title".into()
}
pub fn valid_description() -> String {
"A description".into()
}

View File

@@ -0,0 +1,8 @@
[package]
name = "ticket_fields"
version = "0.1.0"
edition = "2021"
[dependencies]
thiserror = "1.0.59"
common = { path = "../common" }

View File

@@ -0,0 +1,73 @@
#[derive(Debug, PartialEq, Clone, Eq)]
pub struct TicketDescription(String);
#[derive(Debug, thiserror::Error)]
pub enum TicketDescriptionError {
#[error("The description cannot be empty")]
Empty,
#[error("The description cannot be longer than 500 characters")]
TooLong,
}
impl TryFrom<String> for TicketDescription {
type Error = TicketDescriptionError;
fn try_from(value: String) -> Result<Self, Self::Error> {
validate(&value)?;
Ok(Self(value))
}
}
impl TryFrom<&str> for TicketDescription {
type Error = TicketDescriptionError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
validate(value)?;
Ok(Self(value.to_string()))
}
}
fn validate(description: &str) -> Result<(), TicketDescriptionError> {
if description.is_empty() {
Err(TicketDescriptionError::Empty)
} else if description.len() > 500 {
Err(TicketDescriptionError::TooLong)
} else {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use common::{overly_long_description, valid_description};
use std::convert::TryFrom;
#[test]
fn test_try_from_string() {
let input = valid_description();
let description = TicketDescription::try_from(input.clone()).unwrap();
assert_eq!(description.0, input);
}
#[test]
fn test_try_from_empty_string() {
let err = TicketDescription::try_from("".to_string()).unwrap_err();
assert_eq!(err.to_string(), "The description cannot be empty");
}
#[test]
fn test_try_from_long_string() {
let err = TicketDescription::try_from(overly_long_description()).unwrap_err();
assert_eq!(
err.to_string(),
"The description cannot be longer than 500 characters"
);
}
#[test]
fn test_try_from_str() {
let description = TicketDescription::try_from("A description").unwrap();
assert_eq!(description.0, "A description");
}
}

View File

@@ -0,0 +1,6 @@
mod description;
pub mod test_helpers;
mod title;
pub use description::TicketDescription;
pub use title::TicketTitle;

View File

@@ -0,0 +1,14 @@
use crate::{TicketDescription, TicketTitle};
use common::{valid_description, valid_title};
/// A function to generate a valid ticket title,
/// for test purposes.
pub fn ticket_title() -> TicketTitle {
valid_title().try_into().unwrap()
}
/// A function to generate a valid ticket description,
/// for test purposes.
pub fn ticket_description() -> TicketDescription {
valid_description().try_into().unwrap()
}

View File

@@ -0,0 +1,75 @@
use std::convert::TryFrom;
#[derive(Debug, PartialEq, Clone, Eq)]
pub struct TicketTitle(String);
#[derive(Debug, thiserror::Error)]
pub enum TicketTitleError {
#[error("The title cannot be empty")]
Empty,
#[error("The title cannot be longer than 50 characters")]
TooLong,
}
impl TryFrom<String> for TicketTitle {
type Error = TicketTitleError;
fn try_from(value: String) -> Result<Self, Self::Error> {
validate(&value)?;
Ok(Self(value))
}
}
impl TryFrom<&str> for TicketTitle {
type Error = TicketTitleError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
validate(value)?;
Ok(Self(value.to_string()))
}
}
fn validate(title: &str) -> Result<(), TicketTitleError> {
if title.is_empty() {
Err(TicketTitleError::Empty)
} else if title.len() > 50 {
Err(TicketTitleError::TooLong)
} else {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use common::{overly_long_title, valid_title};
use std::convert::TryFrom;
#[test]
fn test_try_from_string() {
let input = valid_title();
let title = TicketTitle::try_from(input.clone()).unwrap();
assert_eq!(title.0, input);
}
#[test]
fn test_try_from_empty_string() {
let err = TicketTitle::try_from("".to_string()).unwrap_err();
assert_eq!(err.to_string(), "The title cannot be empty");
}
#[test]
fn test_try_from_long_string() {
let err = TicketTitle::try_from(overly_long_title()).unwrap_err();
assert_eq!(
err.to_string(),
"The title cannot be longer than 50 characters"
);
}
#[test]
fn test_try_from_str() {
let title = TicketTitle::try_from("A title").unwrap();
assert_eq!(title.0, "A title");
}
}