feat: up
This commit is contained in:
parent
800cd6d542
commit
90a1d15565
|
@ -1,6 +1,6 @@
|
||||||
fn intro() -> &'static str {
|
fn intro() -> &'static str {
|
||||||
// TODO: fix me 👇
|
// TODO: fix me 👇
|
||||||
"I'm ready to __!"
|
"I'm ready to start modelling a software ticket!"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -5,6 +5,17 @@
|
||||||
// It should also have a method named `is_available` that returns a `true` if the quantity is
|
// It should also have a method named `is_available` that returns a `true` if the quantity is
|
||||||
// greater than 0, otherwise `false`.
|
// greater than 0, otherwise `false`.
|
||||||
|
|
||||||
|
struct Order {
|
||||||
|
price: u8,
|
||||||
|
quantity: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Order {
|
||||||
|
fn is_available(&self) -> bool {
|
||||||
|
self.quantity > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -18,7 +18,21 @@ impl Ticket {
|
||||||
// as well as some `String` methods. Use the documentation of Rust's standard library
|
// as well as some `String` methods. Use the documentation of Rust's standard library
|
||||||
// to find the most appropriate options -> https://doc.rust-lang.org/std/string/struct.String.html
|
// to find the most appropriate options -> https://doc.rust-lang.org/std/string/struct.String.html
|
||||||
fn new(title: String, description: String, status: String) -> Self {
|
fn new(title: String, description: String, status: String) -> Self {
|
||||||
todo!();
|
if title.is_empty() {
|
||||||
|
panic!("Title cannot be empty")
|
||||||
|
}
|
||||||
|
if description.is_empty() {
|
||||||
|
panic!("Description cannot be empty")
|
||||||
|
}
|
||||||
|
if title.len() > 50 {
|
||||||
|
panic!("Title cannot be longer than 50 bytes")
|
||||||
|
}
|
||||||
|
if description.len() > 500 {
|
||||||
|
panic!("Description cannot be longer than 500 bytes")
|
||||||
|
}
|
||||||
|
if !["To-Do", "In Progress", "Done"].contains(&status.as_str()) {
|
||||||
|
panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed")
|
||||||
|
}
|
||||||
Self {
|
Self {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
|
|
@ -2,6 +2,8 @@ mod helpers {
|
||||||
// TODO: Make this code compile, either by adding a `use` statement or by using
|
// TODO: Make this code compile, either by adding a `use` statement or by using
|
||||||
// the appropriate path to refer to the `Ticket` struct.
|
// the appropriate path to refer to the `Ticket` struct.
|
||||||
|
|
||||||
|
use crate::Ticket;
|
||||||
|
|
||||||
fn create_todo_ticket(title: String, description: String) -> Ticket {
|
fn create_todo_ticket(title: String, description: String) -> Ticket {
|
||||||
Ticket::new(title, description, "To-Do".into())
|
Ticket::new(title, description, "To-Do".into())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
mod ticket {
|
mod ticket {
|
||||||
struct Ticket {
|
pub struct Ticket {
|
||||||
title: String,
|
pub title: String,
|
||||||
description: String,
|
pub description: String,
|
||||||
status: String,
|
pub status: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ticket {
|
impl Ticket {
|
||||||
fn new(title: String, description: String, status: String) -> Ticket {
|
pub fn new(title: String, description: String, status: String) -> Ticket {
|
||||||
if title.is_empty() {
|
if title.is_empty() {
|
||||||
panic!("Title cannot be empty");
|
panic!("Title cannot be empty");
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,17 @@ pub mod ticket {
|
||||||
// - `title` that returns the `title` field.
|
// - `title` that returns the `title` field.
|
||||||
// - `description` that returns the `description` field.
|
// - `description` that returns the `description` field.
|
||||||
// - `status` that returns the `status` field.
|
// - `status` that returns the `status` field.
|
||||||
|
pub fn description(&self) -> &str {
|
||||||
|
&self.description
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn title(&self) -> &str {
|
||||||
|
&self.title
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn status(&self) -> &str {
|
||||||
|
&self.status
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,16 +34,16 @@ impl Ticket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title(self) -> String {
|
pub fn title(&self) -> &str {
|
||||||
self.title
|
&self.title
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn description(self) -> String {
|
pub fn description(&self) -> &str {
|
||||||
self.description
|
&self.description
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn status(self) -> String {
|
pub fn status(&self) -> &str {
|
||||||
self.status
|
&self.status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// Even better, extract that logic and reuse it in both places. You can use
|
// Even better, extract that logic and reuse it in both places. You can use
|
||||||
// private functions or private static methods for that.
|
// private functions or private static methods for that.
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Ticket {
|
pub struct Ticket {
|
||||||
title: String,
|
title: String,
|
||||||
description: String,
|
description: String,
|
||||||
|
@ -11,27 +12,12 @@ pub struct Ticket {
|
||||||
|
|
||||||
impl Ticket {
|
impl Ticket {
|
||||||
pub fn new(title: String, description: String, status: String) -> Ticket {
|
pub fn new(title: String, description: String, status: String) -> Ticket {
|
||||||
if title.is_empty() {
|
let mut t = Self::default();
|
||||||
panic!("Title cannot be empty");
|
t.set_title(title);
|
||||||
}
|
t.set_description(description);
|
||||||
if title.len() > 50 {
|
t.set_status(status);
|
||||||
panic!("Title cannot be longer than 50 bytes");
|
|
||||||
}
|
|
||||||
if description.is_empty() {
|
|
||||||
panic!("Description cannot be empty");
|
|
||||||
}
|
|
||||||
if description.len() > 500 {
|
|
||||||
panic!("Description cannot be longer than 500 bytes");
|
|
||||||
}
|
|
||||||
if status != "To-Do" && status != "In Progress" && status != "Done" {
|
|
||||||
panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ticket {
|
t
|
||||||
title,
|
|
||||||
description,
|
|
||||||
status,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title(&self) -> &String {
|
pub fn title(&self) -> &String {
|
||||||
|
@ -45,6 +31,32 @@ impl Ticket {
|
||||||
pub fn status(&self) -> &String {
|
pub fn status(&self) -> &String {
|
||||||
&self.status
|
&self.status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_title(&mut self, title: String) {
|
||||||
|
if title.is_empty() {
|
||||||
|
panic!("Title cannot be empty");
|
||||||
|
}
|
||||||
|
if title.len() > 50 {
|
||||||
|
panic!("Title cannot be longer than 50 bytes");
|
||||||
|
}
|
||||||
|
self.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_status(&mut self, status: String) {
|
||||||
|
if status != "To-Do" && status != "In Progress" && status != "Done" {
|
||||||
|
panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
|
||||||
|
}
|
||||||
|
self.status = status;
|
||||||
|
}
|
||||||
|
pub fn set_description(&mut self, description: String) {
|
||||||
|
if description.is_empty() {
|
||||||
|
panic!("Description cannot be empty");
|
||||||
|
}
|
||||||
|
if description.len() > 500 {
|
||||||
|
panic!("Description cannot be longer than 500 bytes");
|
||||||
|
}
|
||||||
|
self.description = description;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -6,16 +6,16 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn u16_size() {
|
fn u16_size() {
|
||||||
assert_eq!(size_of::<u16>(), todo!());
|
assert_eq!(size_of::<u16>(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn i32_size() {
|
fn i32_size() {
|
||||||
assert_eq!(size_of::<i32>(), todo!());
|
assert_eq!(size_of::<i32>(), 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bool_size() {
|
fn bool_size() {
|
||||||
assert_eq!(size_of::<bool>(), todo!());
|
assert_eq!(size_of::<bool>(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string_size() {
|
fn string_size() {
|
||||||
assert_eq!(size_of::<String>(), todo!());
|
assert_eq!(size_of::<String>(), 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -23,6 +23,6 @@ mod tests {
|
||||||
// but, in general, the memory layout of structs is a more complex topic.
|
// but, in general, the memory layout of structs is a more complex topic.
|
||||||
// If you're curious, check out the "Data layout" section of the Rustonomicon
|
// If you're curious, check out the "Data layout" section of the Rustonomicon
|
||||||
// https://doc.rust-lang.org/nomicon/data.html for more information.
|
// https://doc.rust-lang.org/nomicon/data.html for more information.
|
||||||
assert_eq!(size_of::<Ticket>(), todo!());
|
assert_eq!(size_of::<Ticket>(), 72);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,16 +13,16 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn u16_ref_size() {
|
fn u16_ref_size() {
|
||||||
assert_eq!(size_of::<&u16>(), todo!());
|
assert_eq!(size_of::<&u16>(), 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn u64_mut_ref_size() {
|
fn u64_mut_ref_size() {
|
||||||
assert_eq!(size_of::<&mut u64>(), todo!());
|
assert_eq!(size_of::<&mut u64>(), 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ticket_ref_size() {
|
fn ticket_ref_size() {
|
||||||
assert_eq!(size_of::<&Ticket>(), todo!());
|
assert_eq!(size_of::<&Ticket>(), 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// We'll pick the concept up again in a later chapter after covering traits and
|
// We'll pick the concept up again in a later chapter after covering traits and
|
||||||
// interior mutability.
|
// interior mutability.
|
||||||
fn outro() -> &'static str {
|
fn outro() -> &'static str {
|
||||||
"I have a basic understanding of __!"
|
"I have a basic understanding of destructors!"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -11,3 +11,61 @@
|
||||||
// Integration here has a very specific meaning: they test **the public API** of your project.
|
// Integration here has a very specific meaning: they test **the public API** of your project.
|
||||||
// You'll need to pay attention to the visibility of your types and methods; integration
|
// You'll need to pay attention to the visibility of your types and methods; integration
|
||||||
// tests can't access private or `pub(crate)` items.
|
// tests can't access private or `pub(crate)` items.
|
||||||
|
|
||||||
|
use core::panic;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Order {
|
||||||
|
product_name: String,
|
||||||
|
quantity: usize,
|
||||||
|
unit_price: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Order {
|
||||||
|
pub fn new(product_name: String, quantity: usize, unit_price: usize) -> Self {
|
||||||
|
let mut s = Order::default();
|
||||||
|
s.set_product_name(product_name);
|
||||||
|
s.set_quantity(quantity);
|
||||||
|
s.set_unit_price(unit_price);
|
||||||
|
s
|
||||||
|
}
|
||||||
|
pub fn product_name(&self) -> &str {
|
||||||
|
&self.product_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quantity(&self) -> &usize {
|
||||||
|
&self.quantity
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unit_price(&self) -> &usize {
|
||||||
|
&self.unit_price
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn total(&self) -> usize {
|
||||||
|
self.quantity * self.unit_price
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_product_name(&mut self, name: String) {
|
||||||
|
if name.is_empty() {
|
||||||
|
panic!("product_name is empty")
|
||||||
|
}
|
||||||
|
if name.len() > 300 {
|
||||||
|
panic!("product_name is too long")
|
||||||
|
}
|
||||||
|
self.product_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_quantity(&mut self, quantity: usize) {
|
||||||
|
if quantity == 0 {
|
||||||
|
panic!("quantity is zero")
|
||||||
|
}
|
||||||
|
self.quantity = quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_unit_price(&mut self, unit_price: usize) {
|
||||||
|
if unit_price == 0 {
|
||||||
|
panic!("unit_price is zero")
|
||||||
|
}
|
||||||
|
self.unit_price = unit_price;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
fn intro() -> &'static str {
|
fn intro() -> &'static str {
|
||||||
// TODO: fix me 👇
|
// TODO: fix me 👇
|
||||||
"I'm ready to __!"
|
"I'm ready to learn about traits!"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -3,6 +3,22 @@
|
||||||
//
|
//
|
||||||
// Then implement the trait for `u32` and `i32`.
|
// Then implement the trait for `u32` and `i32`.
|
||||||
|
|
||||||
|
trait IsEven {
|
||||||
|
fn is_even(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IsEven for u32 {
|
||||||
|
fn is_even(&self) -> bool {
|
||||||
|
self % 2 == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IsEven for i32 {
|
||||||
|
fn is_even(&self) -> bool {
|
||||||
|
self % 2 == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -3,9 +3,3 @@
|
||||||
// a foreign type (`u32`, from `std`).
|
// a foreign type (`u32`, from `std`).
|
||||||
// Look at the compiler error to get familiar with what it looks like.
|
// Look at the compiler error to get familiar with what it looks like.
|
||||||
// Then delete the code below and move on to the next exercise.
|
// Then delete the code below and move on to the next exercise.
|
||||||
|
|
||||||
impl PartialEq for u32 {
|
|
||||||
fn eq(&self, _other: &Self) -> bool {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,7 +8,13 @@ struct Ticket {
|
||||||
|
|
||||||
// TODO: Implement the `PartialEq` trait for `Ticket`.
|
// TODO: Implement the `PartialEq` trait for `Ticket`.
|
||||||
|
|
||||||
impl PartialEq for Ticket {}
|
impl PartialEq for Ticket {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.title == other.title
|
||||||
|
&& self.description == other.description
|
||||||
|
&& self.status == other.status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// print both sides of the comparison to the terminal.
|
// print both sides of the comparison to the terminal.
|
||||||
// If the compared type doesn't implement `Debug`, it doesn't know how to represent them!
|
// If the compared type doesn't implement `Debug`, it doesn't know how to represent them!
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq, Debug)]
|
||||||
struct Ticket {
|
struct Ticket {
|
||||||
title: String,
|
title: String,
|
||||||
description: String,
|
description: String,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// collections (e.g. BTreeMap).
|
// collections (e.g. BTreeMap).
|
||||||
|
|
||||||
/// Return the minimum of two values.
|
/// Return the minimum of two values.
|
||||||
pub fn min<T>(left: T, right: T) -> T {
|
pub fn min<T: std::cmp::Ord>(left: T, right: T) -> T {
|
||||||
if left <= right {
|
if left <= right {
|
||||||
left
|
left
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -31,15 +31,15 @@ impl Ticket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title(&self) -> &String {
|
pub fn title(&self) -> &str {
|
||||||
&self.title
|
&self.title
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn description(&self) -> &String {
|
pub fn description(&self) -> &str {
|
||||||
&self.description
|
&self.description
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn status(&self) -> &String {
|
pub fn status(&self) -> &str {
|
||||||
&self.status
|
&self.status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@ pub struct Ticket {
|
||||||
|
|
||||||
impl Ticket {
|
impl Ticket {
|
||||||
pub fn title(&self) -> &str {
|
pub fn title(&self) -> &str {
|
||||||
todo!()
|
self.title.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn description(&self) -> &str {
|
pub fn description(&self) -> &str {
|
||||||
todo!()
|
self.description.trim()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,5 +3,5 @@ pub fn example() {
|
||||||
// via `std::mem::size_of` will result in a compile-time error.
|
// via `std::mem::size_of` will result in a compile-time error.
|
||||||
//
|
//
|
||||||
// TODO: Comment out the following line and move on to the next exercise.
|
// TODO: Comment out the following line and move on to the next exercise.
|
||||||
std::mem::size_of::<str>();
|
// std::mem::size_of::<str>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,12 @@ pub struct WrappingU32 {
|
||||||
value: u32,
|
value: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<u32> for WrappingU32 {
|
||||||
|
fn from(value: u32) -> Self {
|
||||||
|
Self { value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn example() {
|
fn example() {
|
||||||
let wrapping: WrappingU32 = 42.into();
|
let wrapping: WrappingU32 = 42.into();
|
||||||
let wrapping = WrappingU32::from(42);
|
let wrapping = WrappingU32::from(42);
|
||||||
|
|
|
@ -13,6 +13,28 @@
|
||||||
// You don't have to though: it's perfectly okay to write three separate
|
// You don't have to though: it's perfectly okay to write three separate
|
||||||
// implementations manually. Venture further only if you're curious.
|
// implementations manually. Venture further only if you're curious.
|
||||||
|
|
||||||
|
trait Power<T> {
|
||||||
|
fn power(&self, t: T) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Power<u16> for u32 {
|
||||||
|
fn power(&self, t: u16) -> Self {
|
||||||
|
self.pow(t as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Power<u32> for u32 {
|
||||||
|
fn power(&self, t: u32) -> Self {
|
||||||
|
self.pow(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Power<&u32> for u32 {
|
||||||
|
fn power(&self, t: &u32) -> Self {
|
||||||
|
self.pow(*t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::Power;
|
use super::Power;
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
// to get the code to compile.
|
// to get the code to compile.
|
||||||
|
|
||||||
pub fn summary(ticket: Ticket) -> (Ticket, Summary) {
|
pub fn summary(ticket: Ticket) -> (Ticket, Summary) {
|
||||||
(ticket, ticket.summary())
|
(ticket.clone(), ticket.summary())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Ticket {
|
pub struct Ticket {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
// TODO: implement the necessary traits to make the test compile and pass.
|
// TODO: implement the necessary traits to make the test compile and pass.
|
||||||
// You *can't* modify the test.
|
// You *can't* modify the test.
|
||||||
|
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct WrappingU32 {
|
pub struct WrappingU32 {
|
||||||
value: u32,
|
value: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Add for WrappingU32 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self::new(self.value.wrapping_add(rhs.value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WrappingU32 {
|
impl WrappingU32 {
|
||||||
pub fn new(value: u32) -> Self {
|
pub fn new(value: u32) -> Self {
|
||||||
Self { value }
|
Self { value }
|
||||||
|
|
|
@ -2,6 +2,26 @@
|
||||||
// unless a certain operation has been performed on it.
|
// unless a certain operation has been performed on it.
|
||||||
// You can see the expected API in the tests below.
|
// You can see the expected API in the tests below.
|
||||||
|
|
||||||
|
struct DropBomb(bool);
|
||||||
|
|
||||||
|
impl DropBomb {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn defuse(&mut self) {
|
||||||
|
self.0 = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for DropBomb {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if !self.0 {
|
||||||
|
panic!("not defuse")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -8,3 +8,67 @@
|
||||||
// It should be possible to print its debug representation.
|
// It should be possible to print its debug representation.
|
||||||
//
|
//
|
||||||
// Tests are located in the `tests` folder—pay attention to the visibility of your types and methods.
|
// Tests are located in the `tests` folder—pay attention to the visibility of your types and methods.
|
||||||
|
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct SaturatingU16(u16);
|
||||||
|
|
||||||
|
impl From<u16> for SaturatingU16 {
|
||||||
|
fn from(value: u16) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for SaturatingU16 {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
Self(value as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&u16> for SaturatingU16 {
|
||||||
|
fn from(value: &u16) -> Self {
|
||||||
|
Self(*value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<&u8> for SaturatingU16 {
|
||||||
|
fn from(value: &u8) -> Self {
|
||||||
|
Self(*value as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<SaturatingU16> for SaturatingU16 {
|
||||||
|
type Output = u16;
|
||||||
|
|
||||||
|
fn add(self, rhs: SaturatingU16) -> Self::Output {
|
||||||
|
self.0.saturating_add(rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<&SaturatingU16> for SaturatingU16 {
|
||||||
|
type Output = u16;
|
||||||
|
|
||||||
|
fn add(self, rhs: &SaturatingU16) -> Self::Output {
|
||||||
|
self.0.saturating_add(rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<u16> for SaturatingU16 {
|
||||||
|
type Output = u16;
|
||||||
|
|
||||||
|
fn add(self, rhs: u16) -> Self::Output {
|
||||||
|
rhs.saturating_add(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<u16> for SaturatingU16 {
|
||||||
|
fn eq(&self, other: &u16) -> bool {
|
||||||
|
self.0 == *other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<SaturatingU16> for u16 {
|
||||||
|
fn eq(&self, other: &SaturatingU16) -> bool {
|
||||||
|
other.0 == *self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
fn intro() -> &'static str {
|
fn intro() -> &'static str {
|
||||||
// TODO: fix me 👇
|
// TODO: fix me 👇
|
||||||
"I'm ready to __!"
|
"I'm ready to refine the `Ticket` type!"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -7,15 +7,19 @@
|
||||||
struct Ticket {
|
struct Ticket {
|
||||||
title: String,
|
title: String,
|
||||||
description: String,
|
description: String,
|
||||||
status: String,
|
status: Status,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
enum Status {
|
enum Status {
|
||||||
// TODO: add the missing variants
|
// TODO: add the missing variants
|
||||||
|
ToDo,
|
||||||
|
InProgress,
|
||||||
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ticket {
|
impl Ticket {
|
||||||
pub fn new(title: String, description: String, status: String) -> Ticket {
|
pub fn new(title: String, description: String, status: Status) -> Ticket {
|
||||||
if title.is_empty() {
|
if title.is_empty() {
|
||||||
panic!("Title cannot be empty");
|
panic!("Title cannot be empty");
|
||||||
}
|
}
|
||||||
|
@ -28,7 +32,7 @@ impl Ticket {
|
||||||
if description.len() > 500 {
|
if description.len() > 500 {
|
||||||
panic!("Description cannot be longer than 500 bytes");
|
panic!("Description cannot be longer than 500 bytes");
|
||||||
}
|
}
|
||||||
if status != "To-Do" && status != "In Progress" && status != "Done" {
|
if status != Status::ToDo && status != Status::InProgress && status != Status::Done {
|
||||||
panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
|
panic!("Only `To-Do`, `In Progress`, and `Done` statuses are allowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +51,7 @@ impl Ticket {
|
||||||
&self.description
|
&self.description
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn status(&self) -> &String {
|
pub fn status(&self) -> &Status {
|
||||||
&self.status
|
&self.status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +85,7 @@ mod tests {
|
||||||
let ticket1 = Ticket {
|
let ticket1 = Ticket {
|
||||||
title: title.clone(),
|
title: title.clone(),
|
||||||
description: "description".to_string(),
|
description: "description".to_string(),
|
||||||
status,
|
status: status.clone(),
|
||||||
};
|
};
|
||||||
let ticket2 = Ticket {
|
let ticket2 = Ticket {
|
||||||
title: title.clone(),
|
title: title.clone(),
|
||||||
|
@ -98,7 +102,7 @@ mod tests {
|
||||||
let ticket1 = Ticket {
|
let ticket1 = Ticket {
|
||||||
title: "title".to_string(),
|
title: "title".to_string(),
|
||||||
description: description.clone(),
|
description: description.clone(),
|
||||||
status,
|
status: status.clone(),
|
||||||
};
|
};
|
||||||
let ticket2 = Ticket {
|
let ticket2 = Ticket {
|
||||||
title: "title2".to_string(),
|
title: "title2".to_string(),
|
||||||
|
|
|
@ -9,7 +9,13 @@ enum Shape {
|
||||||
impl Shape {
|
impl Shape {
|
||||||
// TODO: Implement the `n_sides` method using a `match`.
|
// TODO: Implement the `n_sides` method using a `match`.
|
||||||
pub fn n_sides(&self) -> u8 {
|
pub fn n_sides(&self) -> u8 {
|
||||||
todo!()
|
match *self {
|
||||||
|
Shape::Circle => 0,
|
||||||
|
Shape::Square => 4,
|
||||||
|
Shape::Rectangle => 4,
|
||||||
|
Shape::Triangle => 3,
|
||||||
|
Shape::Pentagon => 5,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,11 @@ impl Ticket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn assigned_to(&self) -> &str {
|
pub fn assigned_to(&self) -> &str {
|
||||||
todo!()
|
if let Status::InProgress { assigned_to } = &self.status {
|
||||||
|
assigned_to
|
||||||
|
} else {
|
||||||
|
panic!("Only `In-Progress` tickets can be assigned to someone")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,11 @@ impl Shape {
|
||||||
// TODO: Implement the `radius` method using
|
// TODO: Implement the `radius` method using
|
||||||
// either an `if let` or a `let/else`.
|
// either an `if let` or a `let/else`.
|
||||||
pub fn radius(&self) -> f64 {
|
pub fn radius(&self) -> f64 {
|
||||||
todo!()
|
if let Shape::Circle { radius } = &self {
|
||||||
|
*radius
|
||||||
|
} else {
|
||||||
|
panic!("wrong");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,11 @@ impl Ticket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn assigned_to(&self) -> Option<&String> {
|
pub fn assigned_to(&self) -> Option<&String> {
|
||||||
todo!()
|
if let Status::InProgress { assigned_to } = &self.status {
|
||||||
|
Some(assigned_to)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,25 +16,25 @@ enum Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ticket {
|
impl Ticket {
|
||||||
pub fn new(title: String, description: String, status: Status) -> Ticket {
|
pub fn new(title: String, description: String, status: Status) -> Result<Self, &'static str> {
|
||||||
if title.is_empty() {
|
if title.is_empty() {
|
||||||
panic!("Title cannot be empty");
|
Err("Title cannot be empty")?;
|
||||||
}
|
}
|
||||||
if title.len() > 50 {
|
if title.len() > 50 {
|
||||||
panic!("Title cannot be longer than 50 bytes");
|
Err("Title cannot be longer than 50 bytes")?;
|
||||||
}
|
}
|
||||||
if description.is_empty() {
|
if description.is_empty() {
|
||||||
panic!("Description cannot be empty");
|
Err("Description cannot be empty")?;
|
||||||
}
|
}
|
||||||
if description.len() > 500 {
|
if description.len() > 500 {
|
||||||
panic!("Description cannot be longer than 500 bytes");
|
Err("Description cannot be longer than 500 bytes")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ticket {
|
Ok(Ticket {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
status,
|
status,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// When the description is invalid, instead, it should use a default description:
|
// When the description is invalid, instead, it should use a default description:
|
||||||
// "Description not provided".
|
// "Description not provided".
|
||||||
fn easy_ticket(title: String, description: String, status: Status) -> Ticket {
|
fn easy_ticket(title: String, description: String, status: Status) -> Ticket {
|
||||||
todo!()
|
Ticket::new(title, description, status).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
@ -22,17 +22,18 @@ enum Status {
|
||||||
impl Ticket {
|
impl Ticket {
|
||||||
pub fn new(title: String, description: String, status: Status) -> Result<Ticket, String> {
|
pub fn new(title: String, description: String, status: Status) -> Result<Ticket, String> {
|
||||||
if title.is_empty() {
|
if title.is_empty() {
|
||||||
return Err("Title cannot be empty".to_string());
|
panic!("Title cannot be empty");
|
||||||
}
|
}
|
||||||
if title.len() > 50 {
|
if title.len() > 50 {
|
||||||
return Err("Title cannot be longer than 50 bytes".to_string());
|
panic!("Title cannot be longer than 50 bytes");
|
||||||
}
|
|
||||||
if description.is_empty() {
|
|
||||||
return Err("Description cannot be empty".to_string());
|
|
||||||
}
|
|
||||||
if description.len() > 500 {
|
|
||||||
return Err("Description cannot be longer than 500 bytes".to_string());
|
|
||||||
}
|
}
|
||||||
|
let description = {
|
||||||
|
if description.is_empty() || description.len() > 500 {
|
||||||
|
"Description not provided".to_string()
|
||||||
|
} else {
|
||||||
|
description
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Ticket {
|
Ok(Ticket {
|
||||||
title,
|
title,
|
||||||
|
|
|
@ -1,14 +1,23 @@
|
||||||
// TODO: Use two variants, one for a title error and one for a description error.
|
// TODO: Use two variants, one for a title error and one for a description error.
|
||||||
// Each variant should contain a string with the explanation of what went wrong exactly.
|
// Each variant should contain a string with the explanation of what went wrong exactly.
|
||||||
// You'll have to update the implementation of `Ticket::new` as well.
|
// You'll have to update the implementation of `Ticket::new` as well.
|
||||||
enum TicketNewError {}
|
enum TicketNewError {
|
||||||
|
TitleError(&'static str),
|
||||||
|
DescriptionError(&'static str),
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: `easy_ticket` should panic when the title is invalid, using the error message
|
// TODO: `easy_ticket` should panic when the title is invalid, using the error message
|
||||||
// stored inside the relevant variant of the `TicketNewError` enum.
|
// stored inside the relevant variant of the `TicketNewError` enum.
|
||||||
// When the description is invalid, instead, it should use a default description:
|
// When the description is invalid, instead, it should use a default description:
|
||||||
// "Description not provided".
|
// "Description not provided".
|
||||||
fn easy_ticket(title: String, description: String, status: Status) -> Ticket {
|
fn easy_ticket(title: String, description: String, status: Status) -> Ticket {
|
||||||
todo!()
|
Ticket::new(title.clone(), description, status.clone()).unwrap_or_else(|t| match t {
|
||||||
|
TicketNewError::TitleError(e) => panic!("{}", e),
|
||||||
|
TicketNewError::DescriptionError(_) => {
|
||||||
|
Ticket::new(title, "Description not provided".to_string(), status)
|
||||||
|
.unwrap_or_else(|_| panic!(""))
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
@ -32,16 +41,22 @@ impl Ticket {
|
||||||
status: Status,
|
status: Status,
|
||||||
) -> Result<Ticket, TicketNewError> {
|
) -> Result<Ticket, TicketNewError> {
|
||||||
if title.is_empty() {
|
if title.is_empty() {
|
||||||
return Err("Title cannot be empty".to_string());
|
Err(TicketNewError::TitleError("Title cannot be empty"))?;
|
||||||
}
|
}
|
||||||
if title.len() > 50 {
|
if title.len() > 50 {
|
||||||
return Err("Title cannot be longer than 50 bytes".to_string());
|
Err(TicketNewError::TitleError(
|
||||||
|
"Title cannot be longer than 50 bytes",
|
||||||
|
))?;
|
||||||
}
|
}
|
||||||
if description.is_empty() {
|
if description.is_empty() {
|
||||||
return Err("Description cannot be empty".to_string());
|
Err(TicketNewError::DescriptionError(
|
||||||
|
"Description cannot be empty",
|
||||||
|
))?;
|
||||||
}
|
}
|
||||||
if description.len() > 500 {
|
if description.len() > 500 {
|
||||||
return Err("Description cannot be longer than 500 bytes".to_string());
|
Err(TicketNewError::DescriptionError(
|
||||||
|
"Description cannot be longer than 500 bytes",
|
||||||
|
))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Ticket {
|
Ok(Ticket {
|
||||||
|
|
Loading…
Reference in New Issue