initial commit

This commit is contained in:
2025-02-19 10:34:15 +05:30
commit b9cb4c290a
355 changed files with 18626 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
[package]
name = "intro_03"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,14 @@
fn intro() -> &'static str {
// TODO: fix me 👇
"I'm ready to __!"
}
#[cfg(test)]
mod tests {
use crate::intro;
#[test]
fn test_intro() {
assert_eq!(intro(), "I'm ready to learn about traits!");
}
}

View File

@@ -0,0 +1,4 @@
[package]
name = "trait_"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,23 @@
// Define a trait named `IsEven` that has a method `is_even` that returns a `true` if `self` is
// even, otherwise `false`.
//
// Then implement the trait for `u32` and `i32`.
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_u32_is_even() {
assert!(42u32.is_even());
assert!(!43u32.is_even());
}
#[test]
fn test_i32_is_even() {
assert!(42i32.is_even());
assert!(!43i32.is_even());
assert!(0i32.is_even());
assert!(!(-1i32).is_even());
}
}

View File

@@ -0,0 +1,4 @@
[package]
name = "orphan"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,11 @@
// TODO: this is an example of an orphan rule violation.
// We're implementing a foreign trait (`PartialEq`, from `std`) on
// a foreign type (`u32`, from `std`).
// 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.
impl PartialEq for u32 {
fn eq(&self, _other: &Self) -> bool {
todo!()
}
}

View File

@@ -0,0 +1,4 @@
[package]
name = "overloading"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,85 @@
use std::cmp::PartialEq;
struct Ticket {
title: String,
description: String,
status: String,
}
// TODO: Implement the `PartialEq` trait for `Ticket`.
impl PartialEq for Ticket {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_partial_eq() {
let title = "title";
let description = "description";
let status = "To-Do";
let ticket1 = Ticket {
title: title.to_string(),
description: description.to_string(),
status: status.to_string(),
};
let ticket2 = Ticket {
title: title.to_string(),
description: description.to_string(),
status: status.to_string(),
};
assert!(ticket1 == ticket2);
}
#[test]
fn test_description_not_matching() {
let title = "title";
let status = "To-Do";
let ticket1 = Ticket {
title: title.to_string(),
description: "description".to_string(),
status: status.to_string(),
};
let ticket2 = Ticket {
title: title.to_string(),
description: "description2".to_string(),
status: status.to_string(),
};
assert!(ticket1 != ticket2);
}
#[test]
fn test_title_not_matching() {
let status = "To-Do";
let description = "description";
let ticket1 = Ticket {
title: "title".to_string(),
description: description.to_string(),
status: status.to_string(),
};
let ticket2 = Ticket {
title: "title2".to_string(),
description: description.to_string(),
status: status.to_string(),
};
assert!(ticket1 != ticket2);
}
#[test]
fn test_status_not_matching() {
let title = "title";
let description = "description";
let ticket1 = Ticket {
title: title.to_string(),
description: description.to_string(),
status: "status".to_string(),
};
let ticket2 = Ticket {
title: title.to_string(),
description: description.to_string(),
status: "status2".to_string(),
};
assert!(ticket1 != ticket2);
}
}

View File

@@ -0,0 +1,4 @@
[package]
name = "derives"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,90 @@
// TODO: A (derivable) trait implementation is missing for this exercise to compile successfully.
// Fix it!
//
// # `Debug` primer
//
// `Debug` returns a representation of a Rust type that's suitable for debugging (hence the name).
// `assert_eq!` requires `Ticket` to implement `Debug` because, when the assertion fails, it tries to
// 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!
#[derive(PartialEq)]
struct Ticket {
title: String,
description: String,
status: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_partial_eq() {
let title = "title";
let description = "description";
let status = "To-Do";
let ticket1 = Ticket {
title: title.to_string(),
description: description.to_string(),
status: status.to_string(),
};
let ticket2 = Ticket {
title: title.to_string(),
description: description.to_string(),
status: status.to_string(),
};
assert_eq!(ticket1, ticket2);
}
#[test]
fn test_description_not_matching() {
let title = "title";
let status = "To-Do";
let ticket1 = Ticket {
title: title.to_string(),
description: "description".to_string(),
status: status.to_string(),
};
let ticket2 = Ticket {
title: title.to_string(),
description: "description2".to_string(),
status: status.to_string(),
};
assert_ne!(ticket1, ticket2);
}
#[test]
fn test_title_not_matching() {
let status = "To-Do";
let description = "description";
let ticket1 = Ticket {
title: "title".to_string(),
description: description.to_string(),
status: status.to_string(),
};
let ticket2 = Ticket {
title: "title2".to_string(),
description: description.to_string(),
status: status.to_string(),
};
assert_ne!(ticket1, ticket2);
}
#[test]
fn test_status_not_matching() {
let title = "title";
let description = "description";
let ticket1 = Ticket {
title: title.to_string(),
description: description.to_string(),
status: "status".to_string(),
};
let ticket2 = Ticket {
title: title.to_string(),
description: description.to_string(),
status: "status2".to_string(),
};
assert_ne!(ticket1, ticket2);
}
}

View File

@@ -0,0 +1,4 @@
[package]
name = "trait_bounds"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,15 @@
// TODO: Add the necessary trait bounds to `min` so that it compiles successfully.
// Refer to the documentation of the `std::cmp` module for more information on the traits you might need.
//
// Note: there are different trait bounds that'll make the compiler happy, but they come with
// different _semantics_. We'll cover those differences later in the course when we talk about ordered
// collections (e.g. BTreeMap).
/// Return the minimum of two values.
pub fn min<T>(left: T, right: T) -> T {
if left <= right {
left
} else {
right
}
}

View File

@@ -0,0 +1,7 @@
[package]
name = "str_slice"
version = "0.1.0"
edition = "2021"
[dev-dependencies]
common = { path = "../../../helpers/common" }

View File

@@ -0,0 +1,61 @@
// TODO: Re-implement `Ticket`'s accessor methods. This time return a `&str` rather than a `&String`.
pub struct Ticket {
title: String,
description: String,
status: String,
}
impl Ticket {
pub fn new(title: String, description: String, status: String) -> Ticket {
if title.is_empty() {
panic!("Title cannot be empty");
}
if title.len() > 50 {
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 {
title,
description,
status,
}
}
pub fn title(&self) -> &String {
&self.title
}
pub fn description(&self) -> &String {
&self.description
}
pub fn status(&self) -> &String {
&self.status
}
}
#[cfg(test)]
mod tests {
use super::*;
use common::{valid_description, valid_title};
use std::any::{Any, TypeId};
#[test]
fn test_type() {
let ticket = Ticket::new(valid_title(), valid_description(), "To-Do".to_string());
// Some dark magic to verify that you used the expected return types
assert_eq!(TypeId::of::<str>(), ticket.title().type_id());
assert_eq!(TypeId::of::<str>(), ticket.description().type_id());
assert_eq!(TypeId::of::<str>(), ticket.status().type_id());
}
}

View File

@@ -0,0 +1,4 @@
[package]
name = "deref"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,38 @@
// TODO: whenever `title` and `description` are returned via their accessor methods, they
// should be normalized—i.e. leading and trailing whitespace should be removed.
// There is a method in Rust's standard library that can help with this, but you won't
// find it in the documentation for `String`.
// Can you figure out where it is defined and how to use it?
pub struct Ticket {
title: String,
description: String,
status: String,
}
impl Ticket {
pub fn title(&self) -> &str {
todo!()
}
pub fn description(&self) -> &str {
todo!()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normalization() {
let ticket = Ticket {
title: " A title ".to_string(),
description: " A description ".to_string(),
status: "To-Do".to_string(),
};
assert_eq!("A title", ticket.title());
assert_eq!("A description", ticket.description());
}
}

View File

@@ -0,0 +1,4 @@
[package]
name = "sized"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,7 @@
pub fn example() {
// Trying to get the size of a str (or any other DST)
// 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.
std::mem::size_of::<str>();
}

View File

@@ -0,0 +1,4 @@
[package]
name = "from"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,10 @@
// TODO: Implement the `From` trait for the `WrappingU32` type to make `example` compile.
pub struct WrappingU32 {
value: u32,
}
fn example() {
let wrapping: WrappingU32 = 42.into();
let wrapping = WrappingU32::from(42);
}

View File

@@ -0,0 +1,4 @@
[package]
name = "assoc_vs_generic"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,37 @@
// TODO: Define a new trait, `Power`, that has a method `power` that raises `self`
// to the power of `n`.
// The trait definition and its implementations should be enough to get
// the tests to compile and pass.
//
// Recommendation: you may be tempted to write a generic implementation to handle
// all cases at once. However, this is fairly complicated and requires the use of
// additional crates (i.e. `num-traits`).
// Even then, it might be preferable to use a simple macro instead to avoid
// the complexity of a highly generic implementation. Check out the
// "Little book of Rust macros" (https://veykril.github.io/tlborm/) if you're
// interested in learning more about it.
// You don't have to though: it's perfectly okay to write three separate
// implementations manually. Venture further only if you're curious.
#[cfg(test)]
mod tests {
use super::Power;
#[test]
fn test_power_u16() {
let x: u32 = 2_u32.power(3u16);
assert_eq!(x, 8);
}
#[test]
fn test_power_u32() {
let x: u32 = 2_u32.power(3u32);
assert_eq!(x, 8);
}
#[test]
fn test_power_ref_u32() {
let x: u32 = 2_u32.power(&3u32);
assert_eq!(x, 8);
}
}

View File

@@ -0,0 +1,4 @@
[package]
name = "clone"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,26 @@
// TODO: add the necessary `Clone` implementations (and invocations)
// to get the code to compile.
pub fn summary(ticket: Ticket) -> (Ticket, Summary) {
(ticket, ticket.summary())
}
pub struct Ticket {
pub title: String,
pub description: String,
pub status: String,
}
impl Ticket {
pub fn summary(self) -> Summary {
Summary {
title: self.title,
status: self.status,
}
}
}
pub struct Summary {
pub title: String,
pub status: String,
}

View File

@@ -0,0 +1,4 @@
[package]
name = "copy"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,25 @@
// TODO: implement the necessary traits to make the test compile and pass.
// You *can't* modify the test.
pub struct WrappingU32 {
value: u32,
}
impl WrappingU32 {
pub fn new(value: u32) -> Self {
Self { value }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ops() {
let x = WrappingU32::new(42);
let y = WrappingU32::new(31);
let z = WrappingU32::new(u32::MAX);
assert_eq!(x + y + y + z, WrappingU32::new(103));
}
}

View File

@@ -0,0 +1,4 @@
[package]
name = "drop"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,23 @@
// TODO: implement a so-called "Drop bomb": a type that panics when dropped
// unless a certain operation has been performed on it.
// You can see the expected API in the tests below.
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic]
fn test_drop_bomb() {
let bomb = DropBomb::new();
// The bomb should panic when dropped
}
#[test]
fn test_defused_drop_bomb() {
let mut bomb = DropBomb::new();
bomb.defuse();
// The bomb should not panic when dropped
// since it has been defused
}
}

View File

@@ -0,0 +1,4 @@
[package]
name = "outro_03"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,10 @@
// TODO: Define a new `SaturatingU16` type.
// It should hold a `u16` value.
// It should provide conversions from `u16`, `u8`, `&u16` and `&u8`.
// It should support addition with a right-hand side of type
// SaturatingU16, u16, &u16, and &SaturatingU16. Addition should saturate at the
// maximum value for `u16`.
// It should be possible to compare it with another `SaturatingU16` or a `u16`.
// 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.

View File

@@ -0,0 +1,17 @@
use outro_03::SaturatingU16;
#[test]
fn test_saturating_u16() {
let a: SaturatingU16 = (&10u8).into();
let b: SaturatingU16 = 5u8.into();
let c: SaturatingU16 = u16::MAX.into();
let d: SaturatingU16 = (&1u16).into();
let e = &c;
assert_eq!(a + b, SaturatingU16::from(15u16));
assert_eq!(a + c, SaturatingU16::from(u16::MAX));
assert_eq!(a + d, SaturatingU16::from(11u16));
assert_eq!(a + a, 20u16);
assert_eq!(a + 5u16, 15u16);
assert_eq!(a + e, SaturatingU16::from(u16::MAX));
}