Skip to content
Snippets Groups Projects
Commit 88c3df4c authored by orestis.malaspin's avatar orestis.malaspin Committed by Michaël El Kharroubi
Browse files

Adds part06 featuring modules and doc tests

parent cd91b40e
Branches
No related tags found
No related merge requests found
/// In part03 we introduce `Enums` (also known as `Algebraic Data Types`), `Pattern Matching`, /// In part02 we introduce `Enums` (also known as `Algebraic Data Types`), `Pattern Matching`,
/// and `Static Functions`. /// and `Static Functions`.
enum NumberOrNothing { enum NumberOrNothing {
......
[package]
name = "part04"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
/*!
Part04 illustrates the concepts of **Ownership** and **Borrowing**. It also
presents the manual implementation of [Clone] and [Copy].
*/
// Rust basics:
// - Ownership
// - Borrowing
// - Clone
// - Copy
// An generic enumerated type that has two variants.
//
// - Nothing
// - Something
enum SomethingOrNothing<T> {
// A [SomethingOrNothing::Nothing]
Nothing,
// A [SomethingOrNothing::Something] encapsulating a T
Something(T),
}
impl<T: std::fmt::Display> SomethingOrNothing<T> {
// A static function that prints the content of a SomethingOrNothing.
fn print(&self) {
match self {
SomethingOrNothing::Nothing => println!("Nothing."),
SomethingOrNothing::Something(val) => println!("Something is: {}", val),
}
}
}
// Manual implementation of [Clone]
impl<T: Clone> Clone for SomethingOrNothing<T> {
fn clone(&self) -> Self {
match self {
SomethingOrNothing::Nothing => SomethingOrNothing::Nothing,
SomethingOrNothing::Something(val) => SomethingOrNothing::Something(val.clone()),
}
}
}
// Manual implementation of [Copy]
impl<T: Copy> Copy for SomethingOrNothing<T> {}
// If we remove Copy, we have a problem with the t in tab
// in the computation of the minimum.
trait Minimum: Copy {
fn min(self, rhs: Self) -> Self;
}
impl<T: Minimum> Minimum for SomethingOrNothing<T> {
fn min(self, rhs: Self) -> Self {
match (self, rhs) {
(SomethingOrNothing::Nothing, SomethingOrNothing::Nothing) => {
SomethingOrNothing::Nothing
}
(SomethingOrNothing::Something(lhs), SomethingOrNothing::Something(rhs)) => {
SomethingOrNothing::Something(lhs.min(rhs))
}
(SomethingOrNothing::Nothing, SomethingOrNothing::Something(rhs)) => {
SomethingOrNothing::Something(rhs)
}
(SomethingOrNothing::Something(lhs), SomethingOrNothing::Nothing) => {
SomethingOrNothing::Something(lhs)
}
}
}
}
impl Minimum for i32 {
fn min(self, rhs: Self) -> Self {
if self < rhs {
self
} else {
rhs
}
}
}
const SIZE: usize = 9;
// Poorly emulates the parsing of a command line.
fn read_command_line() -> [i32; SIZE] {
[10, 32, 12, 43, 52, 53, 83, 2, 9]
}
// Prints all the elements of the `tab`.
// Tab is borrowed here
fn print_tab(tab: &[i32; SIZE]) {
for t in tab {
print!("{} ", t);
}
println!();
}
// Computes the minimum of a borrowed Array of a type T which implements the [Minimum] trait.
// Returns a [SomethingOrNothing::Something] containing the the minimum value
// or [SomethingOrNothing::Nothing] if no minimum value was found.
fn find_min<T: Minimum>(tab: &[T; SIZE]) -> SomethingOrNothing<T> {
let mut minimum = SomethingOrNothing::Nothing;
// Here is T is Copyable. Which means that t is not moved in the loop
for t in tab {
minimum = minimum.min(SomethingOrNothing::Something(*t));
}
minimum
}
fn main() {
let tab = read_command_line();
println!("Among the Somethings in the list:");
print_tab(&tab);
// There are alternatives to access fields of tuples
let min = find_min(&tab);
// The first field is not used therefore we can replace it with "_"
min.print();
}
[package]
name = "part05"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
/*!
This is an example of Rust crate comments (or inner comments).
They will be rendered in the front page of your (crate) library.
In this program we wrote an algorithm that computes the minimum of
a sequence of integers.
To create the documentation run the command
```bash
cargo doc
```
The obtain documentation can be found in the `target/doc/part04/index.html` directory
To view the documentation type
```bash
cargo doc --open
```
which will open the browser and show you the documentation.
The documentation supports the CommonMarkdown syntax.
Below we will use the `///` comments that will comment the code directly below.
We can also sue `//` but they will not be rendered.
Each line written here could be prefixed by `//!` instead of enclosed in `/*! */`.
For more informations about writing documentation [follow that link](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html).
Also Rust comes with great tooling.
- Clippy: A linter.
- Rustfmt: A formatter.
*/
// Rust basics:
// - Tests
// - Copy/Clone via derive
// - PartialEq
// - Documentation
// - clippy, rustfmt
/// An generic enumerated type that has two variants that are [Clone]
/// and [Copy] using derive.
///
/// - Nothing
/// - Something
#[derive(Clone, Copy)]
enum SomethingOrNothing<T> {
/// A [SomethingOrNothing::Nothing]
Nothing,
/// A [SomethingOrNothing::Something] encapsulating a T
Something(T),
}
impl<T: std::fmt::Display> SomethingOrNothing<T> {
/// A static function that prints the content of a SomethingOrNothing.
fn print(&self) {
match self {
SomethingOrNothing::Nothing => println!("Nothing."),
SomethingOrNothing::Something(val) => println!("Something is: {}", val),
}
}
}
impl<T> Default for SomethingOrNothing<T> {
/// By Default a [SomethingOrNothing] is a nothing.
fn default() -> Self {
SomethingOrNothing::Nothing
}
}
impl<T: PartialEq> PartialEq for SomethingOrNothing<T> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(SomethingOrNothing::Nothing, SomethingOrNothing::Nothing) => true,
(SomethingOrNothing::Something(lhs), SomethingOrNothing::Something(rhs)) => {
*lhs == *rhs
}
_ => false,
}
}
}
// If we remove Copy, we have a problem with the t in tab
// in the computation of the minimum.
trait Minimum: Copy {
fn min(self, rhs: Self) -> Self;
}
impl<T: Minimum> Minimum for SomethingOrNothing<T> {
fn min(self, rhs: Self) -> Self {
match (self, rhs) {
(SomethingOrNothing::Nothing, SomethingOrNothing::Nothing) => {
SomethingOrNothing::Nothing
}
(SomethingOrNothing::Something(lhs), SomethingOrNothing::Something(rhs)) => {
SomethingOrNothing::Something(lhs.min(rhs))
}
(SomethingOrNothing::Nothing, SomethingOrNothing::Something(rhs)) => {
SomethingOrNothing::Something(rhs)
}
(SomethingOrNothing::Something(lhs), SomethingOrNothing::Nothing) => {
SomethingOrNothing::Something(lhs)
}
}
}
}
// i32 is Copyable as a very basic type as f32, f64, etc.
// Arrays for example are not copyable.
impl Minimum for i32 {
fn min(self, rhs: Self) -> Self {
if self < rhs {
self
} else {
rhs
}
}
}
const SIZE: usize = 9;
/// Poorly emulates the parsing of a command line.
fn read_command_line() -> [i32; SIZE] {
[10, 32, 12, 43, 52, 53, 83, 2, 9]
}
/// Prints all the elements of the `tab` and returns `tab`.
fn print_tab(tab: &[i32; SIZE]) {
for t in tab {
print!("{} ", t);
}
println!();
}
/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
/// Returns the array and a [SomethingOrNothing::Something] containing the the minimum value
/// or [SomethingOrNothing::Nothing] if no minimum value was found.
///
/// # Example
///
/// ```
/// # fn main() {
/// let tab = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_min(&tab);
/// assert!(min == SomethingOrNothing::Something(2));
/// # }
/// ```
fn find_min<T: Minimum>(tab: &[T; SIZE]) -> SomethingOrNothing<T> {
let mut min = SomethingOrNothing::Nothing;
// Here is T is not Copyable tab is consumed and cannot be returned
for t in tab {
min = min.min(SomethingOrNothing::Something(*t));
}
min
}
fn main() {
let tab = read_command_line();
println!("Among the Somethings in the list:");
print_tab(&tab);
// There are alternatives to access fields of tuples
let min = find_min(&tab);
// The first field is not used therefore we can replace it with "_"
min.print();
}
#[test]
fn test_creation() {
let n1: SomethingOrNothing<i32> = SomethingOrNothing::default();
assert!(n1 == SomethingOrNothing::Nothing);
let n2: SomethingOrNothing<i32> = SomethingOrNothing::Something(1);
assert!(n2 == SomethingOrNothing::Something(1));
}
#[test]
#[should_panic]
fn test_failure_creation() {
let n2: SomethingOrNothing<i32> = SomethingOrNothing::Something(1);
assert!(n2 == SomethingOrNothing::Nothing);
assert!(n2 == SomethingOrNothing::Something(2));
}
#[test]
fn test_min() {
let a = [1, 5, -1, 2, 0, 10, 11, 0, 3];
let min = find_min(&a);
assert!(min == SomethingOrNothing::Something(-1));
}
#[cfg(test)]
mod tests {
#[test]
fn test_min() {
let x = 5;
let y = 10;
assert_eq!(x.min(y), x);
assert_eq!(y.min(x), x);
}
#[test]
fn test_min_something_or_nothing() {
use crate::Minimum;
let x = crate::SomethingOrNothing::Something(5i32);
let y = crate::SomethingOrNothing::Something(10i32);
let z = crate::SomethingOrNothing::Nothing;
assert!(x.min(y) == x);
assert!(y.min(x) == x);
assert!(z.min(y) == y);
assert!(y.min(z) == y);
assert!(z.min(z) == z);
}
}
[package]
name = "part06"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
/// Poorly emulates the parsing of a command line.
pub fn read_command_line() -> [i32; crate::SIZE] {
[10, 32, 12, 43, 52, 53, 83, 2, 9]
}
/// Prints all the elements of the `tab`.
/// Tab is borrowed here
pub fn print_tab(tab: &[i32; crate::SIZE]) {
for t in tab {
print!("{} ", t);
}
println!();
}
/*!
Part06 illustrates the concepts of **Ownership** and **Borrowing**. It also
presents [Clone] and [Copy] traits through derive.
*/
const SIZE: usize = 9;
pub mod io;
mod minimum;
pub mod something_or_nothing;
#[cfg(test)]
mod tests {
use crate::minimum::Minimum;
use crate::something_or_nothing::{find_min, SomethingOrNothing};
#[test]
fn test_creation() {
let n1: SomethingOrNothing<i32> = SomethingOrNothing::default();
assert!(n1 == SomethingOrNothing::Nothing);
let n2: SomethingOrNothing<i32> = SomethingOrNothing::Something(1);
assert!(n2 == SomethingOrNothing::Something(1));
}
#[test]
#[should_panic]
fn test_failure_creation() {
let n2: SomethingOrNothing<i32> = SomethingOrNothing::Something(1);
assert!(n2 == SomethingOrNothing::Nothing);
assert!(n2 == SomethingOrNothing::Something(2));
}
#[test]
fn test_min() {
let a = [1, 5, -1, 2, 0, 10, 11, 0, 3];
let min = find_min(&a);
assert!(min == SomethingOrNothing::Something(-1));
}
#[test]
fn test_min_i32() {
let x = 5;
let y = 10;
assert_eq!(Minimum::min(x, y), x);
assert_eq!(Minimum::min(y, x), x);
assert_eq!(Minimum::min(x, x), x);
assert_eq!(Minimum::min(y, y), y);
}
#[test]
fn test_min_something_or_nothing() {
let x = SomethingOrNothing::Something(5i32);
let y = SomethingOrNothing::Something(10i32);
let z = SomethingOrNothing::Nothing;
assert!(x.min(y) == x);
assert!(y.min(x) == x);
assert!(z.min(y) == y);
assert!(y.min(z) == y);
assert!(z.min(z) == z);
}
}
use part06::io;
use part06::something_or_nothing::find_min;
fn main() {
let tab = io::read_command_line();
println!("Among the Somethings in the list:");
io::print_tab(&tab);
// There are alternatives to access fields of tuples
let min = find_min(&tab);
// The first field is not used therefore we can replace it with "_"
min.print();
}
// If we remove Copy, we have a problem with the t in tab
// in the computation of the minimum.
pub trait Minimum: Copy {
fn min(self, rhs: Self) -> Self;
}
impl Minimum for i32 {
fn min(self, rhs: Self) -> Self {
if self < rhs {
self
} else {
rhs
}
}
}
use crate::minimum::Minimum;
/// An generic enumerated type that has two variants.
///
/// - Nothing
/// - Something
#[derive(Clone, Copy)]
pub enum SomethingOrNothing<T> {
/// A [SomethingOrNothing::Nothing]
Nothing,
/// A [SomethingOrNothing::Something] encapsulating a T
Something(T),
}
impl<T: std::fmt::Display> SomethingOrNothing<T> {
/// A static function that prints the content of a SomethingOrNothing.
pub fn print(&self) {
match self {
SomethingOrNothing::Nothing => println!("Nothing."),
SomethingOrNothing::Something(val) => println!("Something is: {}", val),
}
}
}
impl<T> Default for SomethingOrNothing<T> {
/// By Default a [SomethingOrNothing] is a nothing.
fn default() -> Self {
SomethingOrNothing::Nothing
}
}
impl<T: PartialEq> PartialEq for SomethingOrNothing<T> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(SomethingOrNothing::Nothing, SomethingOrNothing::Nothing) => true,
(SomethingOrNothing::Something(lhs), SomethingOrNothing::Something(rhs)) => {
*lhs == *rhs
}
_ => false,
}
}
}
impl<T: Minimum> Minimum for SomethingOrNothing<T> {
fn min(self, rhs: Self) -> Self {
match (self, rhs) {
(SomethingOrNothing::Nothing, SomethingOrNothing::Nothing) => {
SomethingOrNothing::Nothing
}
(SomethingOrNothing::Something(lhs), SomethingOrNothing::Something(rhs)) => {
SomethingOrNothing::Something(lhs.min(rhs))
}
(SomethingOrNothing::Nothing, SomethingOrNothing::Something(rhs)) => {
SomethingOrNothing::Something(rhs)
}
(SomethingOrNothing::Something(lhs), SomethingOrNothing::Nothing) => {
SomethingOrNothing::Something(lhs)
}
}
}
}
/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
/// Returns a [SomethingOrNothing::Something] containing the the minimum value
/// or [SomethingOrNothing::Nothing] if no minimum value was found.
///
/// # Example
///
/// ```
/// # use part06::something_or_nothing::{SomethingOrNothing, find_min};
/// # fn main() {
/// let tab = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_min(&tab);
/// assert!(min == SomethingOrNothing::Something(2));
/// # }
/// ```
pub fn find_min<T: Minimum>(tab: &[T; crate::SIZE]) -> SomethingOrNothing<T> {
let mut minimum = SomethingOrNothing::Nothing;
// Here is T is Copyable. Which means that t is not moved in the loop
for t in tab {
minimum = minimum.min(SomethingOrNothing::Something(*t));
}
minimum
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment