/// Rust basics:
/// - basic types (usize, i32, str)
/// - const, let, let mut
/// - control structures (for, if)
/// - collection: arrays, indexing
/// - macros for IO and errors
// No functions, only types used are i32, usize and [i32; SIZE].
// Indexing of array, for and if else control structures.
// Macros: panic! for error handling, print! and println! for I/O.
// Clippy does not like the code at all.
fn main() {
const SIZE: usize = 9;
let tab: [i32; SIZE] = [10, 32, 12, 43, 52, 53, 83, 2, 9];
if SIZE == 0 {
panic!("Size is of tab = 0.");
}
println!("Among the numbers in the list:");
for i in 0..SIZE {
print!("{} ", tab[i]);
}
println!();
let mut min = tab[0];
for i in 1..SIZE {
if min > tab[i] {
min = tab[i];
}
}
println!("The minimal value is: {}", min);
}
/// Rust basics:
/// - Functions
/// - Arguments are "moved"
/// - if is an expression
/// - for loops revisited
const SIZE: usize = 9;
fn read_command_line() -> [i32; SIZE] {
[10, 32, 12, 43, 52, 53, 83, 2, 9]
}
// Check if the size is large enough (more that 1 element)
fn check_size(size: usize) {
if size == 0 {
panic!("Size is of tab = 0.");
}
}
// Prints tab and returns tab.
// Tab would be destructed at the end of the function otherwise.
fn print_tab(tab: [i32; SIZE]) {
for t in tab {
print!("{} ", t);
}
println!();
}
fn min_i32(lhs: i32, rhs: i32) -> i32 {
if lhs < rhs { lhs } else { rhs }
}
fn find_min(tab: [i32; SIZE]) -> i32 {
check_size(SIZE);
let mut min = i32::MAX;
for t in tab {
min = min_i32(min, t);
}
min
}
fn main() {
let tab = read_command_line();
println!("Among the numbers in the list:");
print_tab(tab);
let min = find_min(tab);
println!("The minimal value is: {}", min);
}
/// In types_avances we introduce `Enums` (also known as `Algebraic Data Types`), `Pattern Matching`,
/// associated functions and methods.
enum NumberOrNothing {
Nothing,
Number(i32),
}
impl NumberOrNothing {
fn new(val: i32) -> Self {
NumberOrNothing::Number(val)
}
// Method (takes `self`)
fn print(self) {
match self {
NumberOrNothing::Nothing => println!("No number."),
NumberOrNothing::Number(val) => println!("The number is: {}", val),
}
}
}
const SIZE: usize = 9;
fn read_command_line() -> [i32; SIZE] {
[10, 32, 12, 43, 52, 53, 83, 2, 9]
}
// Prints tab and returns tab.
// Tab would be destructed at the end of the function otherwise.
fn print_tab(tab: [i32; SIZE]) {
for t in tab {
print!("{} ", t);
}
println!();
}
fn min_i32(lhs: i32, rhs: i32) -> i32 {
if lhs < rhs { lhs } else { rhs }
}
fn find_min(tab: [i32; SIZE]) -> NumberOrNothing {
let mut min = NumberOrNothing::Nothing;
for t in tab {
match min {
NumberOrNothing::Nothing => min = NumberOrNothing::new(t),
NumberOrNothing::Number(val) => min = NumberOrNothing::new(min_i32(val, t)),
}
}
min
}
fn main() {
let tab = read_command_line();
println!("Among the numbers in the list:");
print_tab(tab);
let min = find_min(tab);
min.print();
}
/* ANCHOR: all */
/// In gen_types_composes we introduce genericity through traits and in particular, [Copy],
/// [Clone], [std::fmt::Display] .
// ANCHOR: something_or_nothing
enum SomethingOrNothing<T> {
Nothing,
Something(T),
}
// ANCHOR_END: something_or_nothing
// ANCHOR: new
impl<T> SomethingOrNothing<T> {
fn new(val: T) -> SomethingOrNothing<T> {
SomethingOrNothing::Something(val)
}
}
// ANCHOR_END: new
// ANCHOR: print
// Print function
// We know the generic type T must be Displayable
fn print<T: std::fmt::Display>(val: SomethingOrNothing<T>) {
match val {
SomethingOrNothing::Nothing => println!("Nothing."),
SomethingOrNothing::Something(val) => println!("Something is: {}", val),
}
}
// ANCHOR_END: print
// ANCHOR: clone
impl<T: Clone> Clone for SomethingOrNothing<T> {
fn clone(&self) -> Self {
match self {
SomethingOrNothing::Nothing => SomethingOrNothing::Nothing,
SomethingOrNothing::Something(val) => SomethingOrNothing::new(val.clone()),
}
}
}
// ANCHOR_END: clone
// ANCHOR: copy
impl<T: Copy> Copy for SomethingOrNothing<T> {}
// ANCHOR_END: copy
// If we remove Copy, we have a problem with the t in tab
// in the computation of the minimum.
// ANCHOR: minimum
trait Minimum: Copy {
fn min(self, rhs: Self) -> Self;
}
// ANCHOR_END: minimum
// ANCHOR: minimum_impl
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::new(lhs.min(rhs))
}
(SomethingOrNothing::Nothing, SomethingOrNothing::Something(rhs)) => {
SomethingOrNothing::new(rhs)
}
(SomethingOrNothing::Something(lhs), SomethingOrNothing::Nothing) => {
SomethingOrNothing::new(lhs)
}
}
}
}
// ANCHOR_END: minimum_impl
// i32 is Copy, like other primitive types (f32, f64, etc.).
// Fixed-size arrays [T; N] are also Copy when T is Copy.
// ANCHOR: minimum_i32
impl Minimum for i32 {
fn min(self, rhs: Self) -> Self {
if self < rhs { self } else { rhs }
}
}
// ANCHOR_END: minimum_i32
const SIZE: usize = 9;
fn read_command_line() -> [i32; SIZE] {
[10, 32, 12, 43, 52, 53, 83, 2, 9]
}
// Prints tab and returns tab.
// Tab would be destructed at the end of the function otherwise.
// ANCHOR: print_tab
fn print_tab<T: std::fmt::Display>(tab: [T; SIZE]) {
for t in tab {
print!("{} ", t);
}
println!();
}
// ANCHOR_END: print_tab
// ANCHOR: find_min
fn find_min<T: Minimum>(tab: [T; SIZE]) -> SomethingOrNothing<T> {
let mut current_minimum = SomethingOrNothing::Nothing;
// Here, if T is not Copyable, tab is consumed and cannot be returned
for t in tab {
current_minimum = current_minimum.min(SomethingOrNothing::new(t));
}
current_minimum
}
// ANCHOR_END: find_min
// ANCHOR: main
fn main() {
let tab = read_command_line();
println!("Among the Somethings in the list:");
print_tab(tab);
let min = find_min(tab);
print(min);
}
// ANCHOR_END: main
/* ANCHOR_END: all */
/* ANCHOR: all */
/*!
propriete illustrates the concepts of **Ownership** and **Borrowing**. It also
presents the manual implementation of [Clone] and [Copy].
*/
// ANCHOR: something_or_nothing
enum SomethingOrNothing<T> {
Nothing,
Something(T),
}
impl<T> SomethingOrNothing<T> {
fn new(val: T) -> SomethingOrNothing<T> {
SomethingOrNothing::Something(val)
}
}
// ANCHOR_END: something_or_nothing
// ANCHOR: print
fn print<T: std::fmt::Display>(val: &SomethingOrNothing<T>) {
match val {
SomethingOrNothing::Nothing => println!("Nothing."),
SomethingOrNothing::Something(val) => println!("Something is: {}", val),
}
}
// ANCHOR_END: print
// 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.
// ANCHOR: minimum
trait Minimum: Copy {
fn min(self, rhs: Self) -> Self;
}
// ANCHOR_END: minimum
// ANCHOR: minimum_impl
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)
}
}
}
}
// ANCHOR_END: minimum_impl
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
// ANCHOR: print_tab
fn print_tab<T: std::fmt::Display>(tab: &[T; SIZE]) {
for t in tab {
print!("{} ", t);
}
println!();
}
// ANCHOR_END: print_tab
// Computes the minimum of a borrowed Array of a type T which implements the [Minimum] trait.
// Returns a [SomethingOrNothing::Something] containing the minimum value
// or [SomethingOrNothing::Nothing] if no minimum value was found.
// ANCHOR: find_min
fn find_min<T: Minimum>(tab: &[T; SIZE]) -> SomethingOrNothing<T> {
let mut current_minimum = SomethingOrNothing::Nothing;
// Here, if T is not Copyable, tab is consumed and cannot be returned
for t in tab {
current_minimum = current_minimum.min(SomethingOrNothing::new(*t));
}
current_minimum
}
// ANCHOR_END: find_min
// ANCHOR: main
fn main() {
let tab = read_command_line();
println!("Among the Somethings in the list:");
print_tab(&tab);
let min = find_min(&tab);
print(&min);
}
// ANCHOR_END: main
/* ANCHOR_END: all */
#![allow(unused)]
fn main() {
// ANCHOR: lib_modules
/*!
modules_visibilite illustrates the concepts of **modules** and **visibility**.
*/
// The size of the tab
const SIZE: usize = 9;
pub mod io;
mod minimum;
pub mod something_or_nothing;
// ANCHOR_END: lib_modules
}
// ANCHOR: main_imports
use modules_visibilite::io;
use modules_visibilite::something_or_nothing::find_min;
// ANCHOR_END: main_imports
fn main() {
// modules_visibilite::io is imported but not read_command_line
let tab = io::read_command_line();
println!("Among the Somethings in the list:");
// modules_visibilite::io is imported but not print_tab
io::print_tab(&tab);
// modules_visibilite::something_or_nothing::find_min is imported and can be used directly
let min = find_min(&tab);
min.print();
}
#![allow(unused)]
fn main() {
// 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
// ANCHOR: pub_fn
pub fn print_tab(tab: &[i32; crate::SIZE]) {
for t in tab {
print!("{} ", t);
}
println!();
}
// ANCHOR_END: pub_fn
}
#![allow(unused)]
fn main() {
// ANCHOR: trait
pub trait Minimum: Copy {
fn min(self, rhs: Self) -> Self;
}
// ANCHOR_END: trait
impl Minimum for i32 {
fn min(self, rhs: Self) -> Self {
if self < rhs { self } else { rhs }
}
}
}
#![allow(unused)]
fn main() {
// ANCHOR: minimum
use crate::minimum::Minimum;
// ANCHOR_END: minimum
// ANCHOR: pub_enum
#[derive(Clone, Copy)]
pub enum SomethingOrNothing<T> {
Nothing,
Something(T),
}
// ANCHOR_END: pub_enum
// ANCHOR: pub_method
impl<T: std::fmt::Display> SomethingOrNothing<T> {
pub fn print(&self) {
match self {
SomethingOrNothing::Nothing => println!("Nothing."),
SomethingOrNothing::Something(val) => println!("Something is: {}", val),
}
}
}
// ANCHOR_END: pub_method
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 minimum value
// or [SomethingOrNothing::Nothing] if no minimum value was found.
pub fn find_min<T: Minimum>(tab: &[T; crate::SIZE]) -> SomethingOrNothing<T> {
let mut minimum = SomethingOrNothing::Nothing;
// Here, if T is Copyable, t is not moved in the loop
for t in tab {
minimum = minimum.min(SomethingOrNothing::Something(*t));
}
minimum
}
}
#![allow(unused)]
fn main() {
// ANCHOR: crate
//! This is an example of Rust crate comments (or inner comments).
//! They will be rendered in the front page of your (crate) library.
//!
//! # How to generate the documentation
//!
//! 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 generated documentation can be found in the `target/doc/tooling/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 Common Markdown syntax.
//!
//! Below we will use the `///` comments that will comment the code directly below.
//! We can also use `//` but they will not be rendered.
//! All the lines written here could be enclosed in `/*! ... */` instead of being prefixed by `//!`.
//!
//! For more information about writing documentation [follow that link](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html).
//!
//! # Tooling
//!
//! Also Rust comes with great tooling.
//! - [Clippy](https://doc.rust-lang.org/stable/clippy/): The official Rust linter.
//! - [Rustfmt](https://github.com/rust-lang/rustfmt): The official Rust code formatter.
// ANCHOR_END: crate
// ANCHOR: size
/// The SIZE constant allows using statically sized arrays
const SIZE: usize = 9;
// ANCHOR_END: size
// ANCHOR: lib_modules
pub mod io;
pub mod minimum;
pub mod something_or_nothing;
// ANCHOR_END: lib_modules
// ANCHOR: test_creation
#[test]
fn test_creation() {
use something_or_nothing::SomethingOrNothing;
let n1: SomethingOrNothing<i32> = SomethingOrNothing::default();
assert!(n1 == SomethingOrNothing::Nothing);
let n2: SomethingOrNothing<i32> = SomethingOrNothing::Something(1);
assert!(n2 == SomethingOrNothing::Something(1));
}
// ANCHOR_END: test_creation
// ANCHOR: cfg_test
#[cfg(test)]
mod tests {
use crate::minimum::Minimum;
use crate::something_or_nothing::{SomethingOrNothing, find_min};
// ANCHOR: should_panic
#[test]
#[should_panic]
fn test_failure_creation() {
let n2: SomethingOrNothing<i32> = SomethingOrNothing::Something(1);
assert!(n2 == SomethingOrNothing::Nothing);
assert!(n2 == SomethingOrNothing::Something(2));
}
// ANCHOR_END: should_panic
#[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_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);
}
}
// ANCHOR_END: cfg_test
}
use tooling::io;
use tooling::something_or_nothing::find_min;
fn main() {
let tab = io::read_command_line();
println!("Among the Somethings in the list:");
io::print_tab(&tab);
let min = find_min(&tab);
min.print();
}
// ANCHOR: crate
//! This is an example of Rust crate comments (or inner comments).
//! They will be rendered in the front page of your (crate) library.
//!
//! # How to generate the documentation
//!
//! 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/tooling/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.
//! All the lines written here could be enclosed in `/*! ... */` instead of being prefixed by `//!`.
//!
//! For more informations about writing documentation [follow that link](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html).
//!
//! # Tooling
//!
//! Also Rust comes with great tooling.
//! - Clippy: A linter.
//! - Rustfmt: A formatter.
// ANCHOR_END: crate
// ANCHOR: something_or_nothing
/// 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),
}
// ANCHOR_END: something_or_nothing
// ANCHOR: static_function
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),
}
}
}
// ANCHOR_END: static_function
// ANCHOR: default
impl<T> Default for SomethingOrNothing<T> {
/// By Default a [SomethingOrNothing] is a nothing.
fn default() -> Self {
SomethingOrNothing::Nothing
}
}
// ANCHOR_END: default
// ANCHOR: partial_eq
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,
}
}
}
// ANCHOR_END: partial_eq
// ANCHOR: minimum
/// The [Minimum] trait computes the minimum value between two values of a type
trait Minimum: Copy {
fn min(self, rhs: Self) -> Self;
}
// ANCHOR_END: minimum
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)
}
}
}
}
// Since i32 is [Copy] we don't need to explicitly implement it for i32
impl Minimum for i32 {
fn min(self, rhs: Self) -> Self {
if self < rhs {
self
} else {
rhs
}
}
}
// ANCHOR: size
/// A constant that is the size of
const SIZE: usize = 9;
// ANCHOR_END: size
// ANCHOR: function
/// Poorly emulates the parsing of a command line.
fn read_command_line() -> [i32; SIZE] {
[10, 32, 12, 43, 52, 53, 83, 2, 9]
}
// ANCHOR_END: function
/// 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 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
///
/// ```
/// # 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 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();
}
#![allow(unused)]
fn main() {
// ANCHOR: io_module
//! Contains functions to interact with the user, either
//! by reading inputs from the terminal, either by writing values
//! in it.
//ANCHOR_END: io_module
// ANCHOR: function
/// 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]
}
// ANCHOR_END: function
/// 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!();
}
}
#![allow(unused)]
fn main() {
// ANCHOR: min
//! Contains a generic trait implementation for computing the minimum between two
//! values. It is the equivalent of the `<` operator.
//!
//! # Examples
//!
//! For integers this would look like
//!
//! ```
//! # use tooling::minimum::Minimum;
//! let one = 1;
//! let two = 2;
//! assert!(Minimum::min(one, two) == one);
//! ```
// ANCHOR_END: min
// ANCHOR: minimum
/// The [Minimum] trait computes the minimum value between two values of a type
pub trait Minimum: Copy {
fn min(self, rhs: Self) -> Self;
}
// ANCHOR_END: minimum
impl Minimum for i32 {
fn min(self, rhs: Self) -> Self {
if self < rhs { self } else { rhs }
}
}
// ANCHOR: cfg_test_min
#[cfg(test)]
mod tests {
use crate::minimum::Minimum;
#[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);
}
}
// ANCHOR_END: cfg_test_min
}
//! Contains the core logic of the library, allowing to store generic values
//! (or their absence) and manipulate them.
use crate::minimum::Minimum;
// ANCHOR: something_or_nothing
/// A 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),
}
// ANCHOR_END: something_or_nothing
// ANCHOR: method
impl<T: std::fmt::Display> SomethingOrNothing<T> {
/// A method that prints the content of a SomethingOrNothing.
pub fn print(&self) {
match self {
SomethingOrNothing::Nothing => println!("Nothing."),
SomethingOrNothing::Something(val) => println!("Something is: {}", val),
}
}
}
// ANCHOR_END: method
// ANCHOR: default
/// Implementation of the [Default] trait that creates a [SomethingOrNothing]
/// that is a `Nothing` variant.
///
/// # Example
///
/// ```
/// # use tooling::something_or_nothing::SomethingOrNothing;
/// # fn main() {
/// let def: SomethingOrNothing<i32> = SomethingOrNothing::default();
/// assert!(def == SomethingOrNothing::Nothing);
/// # }
/// ```
impl<T> Default for SomethingOrNothing<T> {
/// By Default a [SomethingOrNothing] is a nothing.
fn default() -> Self {
SomethingOrNothing::Nothing
}
}
// ANCHOR_END: default
// ANCHOR: partial_eq
/// Implementation of the [PartialEq] trait that is useful for tests.
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,
}
}
}
// ANCHOR_END: partial_eq
/// Implementation of the [Minimum] trait used for comparing values
/// in this crate.
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)
}
}
}
}
// ANCHOR: find_min
/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
/// Returns a [SomethingOrNothing::Something] containing the minimum value
/// or [SomethingOrNothing::Nothing] if no minimum value was found.
///
/// # Example
///
/// ```
/// # use tooling::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, if T is Copyable, t is not moved in the loop
for t in tab {
minimum = minimum.min(SomethingOrNothing::Something(*t));
}
minimum
}
// ANCHOR_END: find_min
#![allow(unused)]
fn main() {
//! This crate shows us different ways of dealing with errors in a Rust program.
//! You will find examples of [Option], [Result] and [panic!].
pub mod find_minimum;
pub mod io;
pub mod minimum;
#[cfg(test)]
mod tests {
use crate::find_minimum::{
find_min_amongst_arrays_by_hand, find_min_amongst_arrays_qm_op, find_min_with_option,
find_min_with_panic, find_min_with_result,
};
const TAB: [i32; 9] = [10, 32, 12, 43, 52, 53, 83, 2, 9];
const TAB_B: [i32; 9] = [22, 34, 11, 4, 52, 99, 71, 13, 43];
const TAB_EMPTY: [i32; 0] = [];
const MIN_TAB: i32 = 2;
#[test]
fn test_find_min_option() {
let min = find_min_with_option(&TAB);
assert!(min == Some(MIN_TAB));
}
#[test]
fn test_find_min_option_empty() {
let min = find_min_with_option(&TAB_EMPTY);
assert!(min.is_none());
}
#[test]
fn test_find_min_result() {
let min = find_min_with_result(&TAB);
assert!(min == Ok(MIN_TAB));
}
#[test]
fn test_find_min_result_empty() {
let min = find_min_with_result(&TAB_EMPTY);
assert!(min.is_err());
}
#[test]
fn test_find_min_panic() {
let min = find_min_with_panic(&TAB);
assert!(min == MIN_TAB);
}
#[test]
#[should_panic]
fn test_find_min_panic_empty() {
let _min = find_min_with_panic(&TAB_EMPTY);
}
#[test]
fn test_find_min_amongst_arrays_bh() {
let min = find_min_amongst_arrays_by_hand(&TAB, &TAB_B);
assert!(min == Ok(MIN_TAB));
}
#[test]
fn test_find_min_amongst_arrays_qm() {
let min = find_min_amongst_arrays_qm_op(&TAB, &TAB_B);
assert!(min == Ok(MIN_TAB));
}
#[test]
fn test_find_min_amongst_arrays_bh_empty() {
let min = find_min_amongst_arrays_by_hand(&TAB, &TAB_EMPTY);
assert!(min.is_err());
}
#[test]
fn test_find_min_amongst_arrays_qm_empty() {
let min = find_min_amongst_arrays_qm_op(&TAB, &TAB_EMPTY);
assert!(min.is_err());
}
}
}
use gestion_erreurs::find_minimum::{
FindMinError::EmptyList, FindMinError::UnsupportedError, find_min_amongst_arrays_qm_op,
find_min_with_option, find_min_with_result,
};
use gestion_erreurs::io;
fn main() {
let tab = io::read_command_line_correct();
println!("Among the elements in the list:");
io::print_tab(&tab);
let min = find_min_with_option(&tab);
match min {
Some(val) => print!("The minimum value is {}", val),
None => eprintln!("There is no minimum since the list is empty"),
}
println!("");
println!("");
let tab_empty = io::read_empty_command_line();
println!("Among the elements in the list:");
io::print_tab(&tab_empty);
//ANCHOR: parse_result
let min = find_min_with_result(&tab_empty);
match min {
Ok(val) => print!("The minimum value is {}", val),
Err(EmptyList) => eprintln!("The array is empty"),
Err(UnsupportedError(msg)) => panic!("Unsupported error : {}", msg),
}
//ANCHOR_END: parse_result
println!("Among the elements in the lists:");
io::print_tab(&tab);
io::print_tab(&tab_empty);
let min = find_min_amongst_arrays_qm_op(&tab, &tab_empty);
match min {
Ok(val) => print!("The minimum value is {}", val),
Err(EmptyList) => eprintln!("One or both arrays are empty"),
Err(UnsupportedError(msg)) => panic!("Unsupported error : {}", msg),
}
}
//! Contains the core logic of the library, allowing to store generic values
//! (or their absence) and manipulate them.
//! We demonstrates three kind of way to deal with errors
use crate::minimum::Minimum;
// ANCHOR: find_min_error
#[derive(PartialEq)]
pub enum FindMinError {
EmptyList,
UnsupportedError(String),
}
// ANCHOR_END: find_min_error
use crate::find_minimum::FindMinError::EmptyList;
/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
/// Returns a [Option::Some] containing the minimum value
/// or [Option::None] if no minimum value was found.
///
/// # Example
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_with_option};
/// # fn main() {
/// let tab = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_min_with_option(&tab);
/// assert!(min == Some(2));
/// # }
/// ```
// ANCHOR: min_with_option
pub fn find_min_with_option<T: Minimum>(tab: &[T]) -> Option<T> {
let mut minimum = None;
// Here, if T is Copyable, t is not moved in the loop
for t in tab {
minimum = Minimum::min(minimum, Some(*t));
}
minimum
}
// ANCHOR_END: min_with_option
/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
/// Returns a [Result::Ok] containing the minimum value
/// or an [Result::Err] containing the error, if no minimum value was found.
///
/// # Example
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_with_result};
/// # fn main() {
/// let tab = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_min_with_result(&tab);
/// assert!(min == Ok(2));
/// # }
/// ```
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_with_result};
/// # fn main() {
/// let tab : [i32; 0] = [];
/// let min = find_min_with_result(&tab);
/// assert!(min.is_err());
/// # }
/// ```
// ANCHOR: min_with_result
pub fn find_min_with_result<T: Minimum>(tab: &[T]) -> Result<T, FindMinError> {
let mut minimum = None;
// Here, if T is Copyable, t is not moved in the loop
for t in tab {
minimum = Minimum::min(minimum, Some(*t));
}
match minimum {
Some(val) => Ok(val),
None => Err(EmptyList),
}
}
// ANCHOR_END: min_with_result
/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
/// Returns a T which is the minimum value
/// or panics if no minimum value was found.
///
/// # Example
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_with_panic};
/// # fn main() {
/// let tab = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_min_with_panic(&tab);
/// assert!(min == 2);
/// # }
/// ```
///
/// ```should_panic
/// # use gestion_erreurs::find_minimum::{find_min_with_panic};
/// # fn main() {
/// let tab : [i32; 0] = [];
/// let _min = find_min_with_panic(&tab);
/// # }
/// ```
// ANCHOR: min_with_panic
pub fn find_min_with_panic<T: Minimum>(tab: &[T]) -> T {
let mut minimum = None;
// Here, if T is Copyable, t is not moved in the loop
for t in tab {
minimum = Minimum::min(minimum, Some(*t));
}
// We decide that we cannot compute the minimum of an empty array
match minimum {
Some(val) => val,
None => panic!("The array is empty"),
}
}
// ANCHOR_END: min_with_panic
/// Computes the minimum amongst two Arrays of a type T which implements the [Minimum] trait.
/// Returns a [Result::Ok] containing the minimum value
/// or an [Result::Err] containing the error, if no minimum value was found.
///
/// We deal with errors in underlying function calls without the [?] operator.
///
/// # Example
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_amongst_arrays_by_hand};
/// # fn main() {
/// let tab_a = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let tab_b = [22, 34, 11, 4, 52, 99, 71, 13, 43];
/// let min = find_min_amongst_arrays_by_hand(&tab_a, &tab_b);
/// assert!(min == Ok(2));
/// # }
/// ```
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_amongst_arrays_by_hand};
/// # fn main() {
/// let tab_a = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let tab_b : [i32; 0] = [];
/// let min = find_min_amongst_arrays_by_hand(&tab_a, &tab_b);
/// assert!(min.is_err());
/// # }
/// ```
// ANCHOR: min_two_tabs_hand
pub fn find_min_amongst_arrays_by_hand<T: Minimum>(
lhs: &[T],
rhs: &[T],
) -> Result<T, FindMinError> {
let min_result = find_min_with_result(lhs);
let min_l = if let Ok(x) = min_result {
x
} else {
// Since tmp is not Ok, we return the error to the caller
return min_result;
};
let min_result = find_min_with_result(rhs);
let min_r = if let Ok(x) = min_result {
x
} else {
// Since tmp is not Ok, we return the error to the caller
return min_result;
};
Ok(min_l.min(min_r))
}
// ANCHOR_END: min_two_tabs_hand
/// Computes the minimum amongst two Arrays of a type T which implements the [Minimum] trait.
/// Returns a [Result::Ok] containing the minimum value
/// or an [Result::Err] containing the error, if no minimum value was found.
///
/// We deal with errors in underlying function with the [?] operator.
///
/// # Example
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_amongst_arrays_qm_op};
/// # fn main() {
/// let tab_a = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let tab_b = [22, 34, 11, 4, 52, 99, 71, 13, 43];
/// let min = find_min_amongst_arrays_qm_op(&tab_a, &tab_b);
/// assert!(min == Ok(2));
/// # }
/// ```
///
/// ```
/// # use gestion_erreurs::find_minimum::{find_min_amongst_arrays_qm_op};
/// # fn main() {
/// let tab_a = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let tab_b : [i32; 0] = [];
/// let min = find_min_amongst_arrays_qm_op(&tab_a, &tab_b);
/// assert!(min.is_err());
/// # }
/// ```
// ANCHOR: min_two_tabs_qm
pub fn find_min_amongst_arrays_qm_op<T: Minimum>(lhs: &[T], rhs: &[T]) -> Result<T, FindMinError> {
// The question mark operator will unpack the value if the function returns [Result::Ok]
// or end the function and return the [Result:Err] to the caller.
let min_l = find_min_with_result(lhs)?;
let min_r = find_min_with_result(rhs)?;
Ok(min_l.min(min_r))
}
// ANCHOR_END: min_two_tabs_qm
#![allow(unused)]
fn main() {
//! Contains functions to interact with the user, either
//! by reading inputs from the terminal, either by writing values
//! in it.
/// Poorly emulates the parsing of a command line.
pub fn read_command_line_correct() -> [i32; 9] {
[10, 32, 12, 43, 52, 53, 83, 2, 9]
}
/// Poorly emulates the parsing of a command line.
pub fn read_empty_command_line() -> [i32; 0] {
[]
}
/// Prints all the elements of the `tab`.
/// Tab is borrowed here
pub fn print_tab(tab: &[i32]) {
print!("[ ");
for t in tab {
print!("{} ", t);
}
println!("]");
}
}
#![allow(unused)]
fn main() {
//! Contains a generic trait implementation for computing the minimum between two
//! values. It is the equivalent of the `<` operator.
//!
//! # Examples
//!
//! For integers this would look like
//!
//! ```
//! # use gestion_erreurs::minimum::Minimum;
//! let one = 1;
//! let two = 2;
//! assert!(Minimum::min(one, two) == one);
//! ```
/// The [Minimum] trait computes the minimum value between two values of a type
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 }
}
}
// ANCHOR: min_for_option
impl<T: Minimum> Minimum for Option<T> {
fn min(self, rhs: Self) -> Self {
match self {
Some(val_l) => Some(match rhs {
Some(val_r) => val_l.min(val_r),
None => val_l,
}),
None => match rhs {
Some(val_r) => Some(val_r),
None => None,
},
}
}
}
// ANCHOR_END: min_for_option
#[cfg(test)]
mod tests {
use crate::minimum::Minimum;
#[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);
}
}
}
#![allow(unused)]
fn main() {
//! This crate shows us different ways of dealing with errors in a Rust program.
//! You will find examples of [Option], [Result] and [panic!].
pub mod binary_operator;
pub mod find;
pub mod io;
#[cfg(test)]
mod tests {
use crate::binary_operator::*;
use crate::find::find_with_hof;
const TAB: [i32; 9] = [10, 32, 12, 43, 52, 53, 83, 2, 9];
const TAB_EMPTY: [i32; 0] = [];
const MIN_TAB: i32 = 2;
const MAX_TAB: i32 = 83;
#[test]
fn test_find_with_option_min() {
let min: Option<i32> = find_with_hof(&TAB, |x: i32, y: i32| if x <= y { x } else { y });
assert!(min == Some(MIN_TAB));
}
#[test]
fn test_find_with_option_max() {
let max: Option<i32> = find_with_hof(&TAB, |x: i32, y: i32| if x >= y { x } else { y });
assert!(max == Some(MAX_TAB));
}
#[test]
fn test_find_with_option_empty() {
let min: Option<i32> =
find_with_hof(&TAB_EMPTY, |x: i32, y: i32| if x <= y { x } else { y });
assert!(min.is_none());
}
#[test]
fn test_minimum_operator() {
let f = minimum_operator::<i32>();
assert!(f(5, 10) == 5);
}
#[test]
fn test_maximum_operator() {
let f = maximum_operator::<i32>();
assert!(f(5, 10) == 10);
}
#[test]
fn test_sum_operator() {
let f = sum_operator::<i32>();
assert!(f(5, 10) == 15);
}
#[test]
fn test_mul_operator() {
let f = mul_operator::<i32>();
assert!(f(5, 10) == 50);
}
}
}
use closures::binary_operator::{minimum_operator, sum_operator};
use closures::find::find_with_hof;
use closures::io;
fn main() {
let tab = io::read_command_line_correct();
println!("Among the elements in the list:");
io::print_tab(&tab);
//ANCHOR: min_usage
let min = find_with_hof(&tab, minimum_operator());
match min {
Some(val) => println!("The minimum value is {}", val),
None => eprintln!("There is no minimum"),
}
//ANCHOR_END: min_usage
//ANCHOR: max_variable
let max_op: fn(i32, i32) -> i32 = |x, y| if x >= y { x } else { y };
//ANCHOR_END: max_variable
//ANCHOR: option_filter
let max_val: Option<i32> = find_with_hof(&tab, max_op);
let odd_max: Option<i32> = max_val.filter(|x| x % 2 == 1);
match odd_max {
Some(_) => println!("The maximum value is an odd number"),
None => {
if max_val.is_some() {
println!("The maximum value is an even number")
} else {
eprintln!("There is no maximum")
}
}
}
//ANCHOR_END: option_filter
//ANCHOR: option_map
let two: f32 = 2.0f32;
let sum: Option<i32> = find_with_hof(&tab, sum_operator());
let half: Option<f32> = sum.map(|x: i32| (x as f32) / two);
match half {
Some(val) => println!("The sum of the elements divided by two is {}", val),
None => eprintln!("There is no sum"),
}
//ANCHOR_END: option_map
}
// ANCHOR: binary_operator
pub type BinaryOperator<T> = fn(T, T) -> T;
// ANCHOR_END: binary_operator
/// Returns a closure that computes the minimum
/// between two elements of type T.
/// # Example
///
/// ```
/// # use closures::binary_operator::{minimum_operator};
/// # fn main() {
/// let f = minimum_operator();
/// assert!(f(1,2) == 1);
/// # }
/// ```
// ANCHOR: minimum_operator
pub fn minimum_operator<T: PartialOrd>() -> BinaryOperator<T> {
|x: T, y: T| if x <= y { x } else { y }
}
// ANCHOR_END: minimum_operator
/// Returns a closure that computes the maximum
/// between two elements of type T.
/// # Example
///
/// ```
/// # use closures::binary_operator::{maximum_operator};
/// # fn main() {
/// let f = maximum_operator();
/// assert!(f(1,2) == 2);
/// # }
/// ```
// ANCHOR: maximum_operator
pub fn maximum_operator<T: PartialOrd>() -> BinaryOperator<T> {
|x: T, y: T| if x >= y { x } else { y }
}
// ANCHOR_END: maximum_operator
/// Returns a closure that computes the sum
/// of two elements of type T.
/// # Example
///
/// ```
/// # use closures::binary_operator::{sum_operator};
/// # fn main() {
/// let f = sum_operator();
/// assert!(f(1,2) == 3);
/// # }
/// ```
// ANCHOR: sum_operator
pub fn sum_operator<T: std::ops::Add<Output = T>>() -> BinaryOperator<T> {
|x: T, y: T| x + y
}
// ANCHOR_END: sum_operator
/// Returns a closure that computes the product
/// of two elements of type T.
/// # Example
///
/// ```
/// # use closures::binary_operator::{mul_operator};
/// # fn main() {
/// let f = mul_operator();
/// assert!(f(1,2) == 2);
/// # }
/// ```
// ANCHOR: mul_operator
pub fn mul_operator<T: std::ops::Mul<Output = T>>() -> BinaryOperator<T> {
|x: T, y: T| x * y
}
// ANCHOR_END: mul_operator
//! Contains the core logic of the library, allowing to store generic values
//! (or their absence) and manipulate them.
//! We demonstrates three kind of way to deal with errors
use crate::binary_operator::BinaryOperator;
/// Computes the result of a binary reduction of an Array of a type T.
/// Take the binary operation as a function.
/// Returns a [Option::Some] containing the result value
/// or [Option::None] if the array was empty.
///
/// # Example
///
/// ```
/// # use closures::find::{find_with_hof};
/// # fn main() {
/// let tab = [10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_with_hof(&tab,|x, y| if x <= y { x } else { y });
/// assert!(min == Some(2));
/// # }
/// ```
// ANCHOR: find_with_hof
pub fn find_with_hof<T: Copy>(tab: &[T], op: BinaryOperator<T>) -> Option<T> {
let mut res = None;
// Here, if T is Copyable, t is not moved in the loop
for t in tab {
if let Some(val) = res {
res = Some(op(val, *t))
} else {
res = Some(*t)
}
}
res
}
// ANCHOR_END: find_with_hof
#![allow(unused)]
fn main() {
//! Contains functions to interact with the user, either
//! by reading inputs from the terminal, either by writing values
//! in it.
/// Poorly emulates the parsing of a command line.
pub fn read_command_line_correct() -> [i32; 9] {
[10, 32, 12, 43, 52, 53, 83, 2, 9]
}
/// Poorly emulates the parsing of a command line.
pub fn read_empty_command_line() -> [i32; 0] {
[]
}
/// Prints all the elements of the `tab`.
/// Tab is borrowed here
pub fn print_tab(tab: &[i32]) {
print!("[ ");
for t in tab {
print!("{} ", t);
}
println!("]");
}
}
#![allow(unused)]
fn main() {
//! This crate shows us different ways of dealing with errors in a Rust program.
//! You will find examples of [Option], [Result] and [panic!].
pub mod find;
pub mod io;
#[cfg(test)]
mod tests {
use crate::find::{find_absolute_minimum, find_minimum};
const VEC: [i32; 9] = [10, 32, 12, 43, 52, 53, 83, 2, 9];
const VEC_2: [i32; 9] = [-10, 32, 12, -43, 52, -53, 83, -2, 9];
const MIN_VEC: i32 = 2;
const ABS_MIN_VEC_2: i32 = -2;
#[test]
fn test_find_minimum() {
let min: Option<i32> = find_minimum(&(VEC.to_vec()));
assert!(min == Some(MIN_VEC));
}
#[test]
fn test_find_absolute_minimum() {
let min: Option<i32> = find_absolute_minimum(&(VEC_2.to_vec()));
assert!(min == Some(ABS_MIN_VEC_2));
}
}
}
use iterateurs::find::{find_absolute_minimum, find_even_minimum, find_minimum};
use iterateurs::io;
fn main() {
let v = io::read_command_line_correct();
println!("Among the elements in the list:");
io::print_vec(&v);
let min = find_minimum(&v);
match min {
Some(val) => println!("The minimum value is {}", val),
None => eprintln!("There is no minimum"),
}
let min = find_absolute_minimum(&v);
match min {
Some(val) => println!("The minimum by absolute value is {}", val),
None => eprintln!("There is no minimum"),
}
let min = find_even_minimum(&v);
match min {
Some(val) => println!("The smallest even value is {}", val),
None => eprintln!("There is no minimum"),
}
}
//! Contains the core logic of the library, allowing to store generic values
//! (or their absence) and manipulate them.
//! We demonstrate several ways to process collections with iterators.
/// Computes the minimum of a vector of i32.
/// Returns a [Option::Some] containing the minimum value
/// or [Option::None] if the vec was empty.
///
/// # Example
///
/// ```
/// # use iterateurs::find::{find_minimum};
/// # fn main() {
/// let v = vec![-2, 5, 18, 65, 22, 56, -30];
/// let min = find_minimum(&v);
/// assert!(min == Some(-30));
/// # }
/// ```
// ANCHOR: find_minimum
pub fn find_minimum(v: &Vec<i32>) -> Option<i32> {
v.iter().fold(None, |acc, current| {
let next_acc = if let Some(val) = acc {
if val <= *current { val } else { *current }
} else {
*current
};
Some(next_acc)
})
}
// ANCHOR_END: find_minimum
/// Computes the smallest even number in a vector of i32.
/// Returns a [Option::Some] containing the smallest even number
/// or [Option::None] if the vec was empty.
///
/// # Example
///
/// ```
/// # use iterateurs::find::{find_even_minimum};
/// # fn main() {
/// let v = vec![15, 64, 47, 2, 1, 53, 22];
/// let min = find_even_minimum(&v);
/// assert!(min == Some(2));
/// # }
/// ```
// ANCHOR: find_even_minimum
pub fn find_even_minimum(v: &Vec<i32>) -> Option<i32> {
v.iter().filter(|i| *i % 2 == 0).fold(None, |acc, current| {
let next_acc = if let Some(val) = acc {
if val <= *current { val } else { *current }
} else {
*current
};
Some(next_acc)
})
}
// ANCHOR_END: find_even_minimum
/// Computes the minimum absolute value of a vector of i32.
/// Returns a [Option::Some] containing the minimum abs value
/// or [Option::None] if the vec was empty.
///
/// # Example
///
/// ```
/// # use iterateurs::find::{find_absolute_minimum};
/// # fn main() {
/// let v = vec![-2, 5, 18, 65, 22, 56, -30];
/// let min = find_absolute_minimum(&v);
/// assert!(min == Some(-2));
/// # }
/// ```
// ANCHOR: find_absolute_minimum
pub fn find_absolute_minimum(v: &Vec<i32>) -> Option<i32> {
// ANCHOR: find_absolute_minimum_1
let signs = v.iter().map(|i| i.signum());
let abs_values = v.iter().map(|i| i.abs());
// ANCHOR_END: find_absolute_minimum_1
// ANCHOR: find_absolute_minimum_2
signs
.zip(abs_values)
// ANCHOR_END: find_absolute_minimum_2
// ANCHOR: find_absolute_minimum_3
.fold(None, |acc, (c_sign, c_abs_v)| {
let next_acc = if let Some((sign, abs_v)) = acc {
if abs_v <= c_abs_v {
(sign, abs_v)
} else {
(c_sign, c_abs_v)
}
} else {
(c_sign, c_abs_v)
};
Some(next_acc)
})
// ANCHOR_END: find_absolute_minimum_3
// ANCHOR: find_absolute_minimum_4
.map(|(sign, abs_v)| sign * abs_v)
// ANCHOR_END: find_absolute_minimum_4
}
// ANCHOR_END: find_absolute_minimum
#![allow(unused)]
fn main() {
//! Contains functions to interact with the user, either
//! by reading inputs from the terminal, either by writing values
//! in it.
/// Poorly emulates the parsing of a command line.
pub fn read_command_line_correct() -> Vec<i32> {
vec![-10, 32, 12, -43, 52, -53, 83, -2, 9]
}
/// Poorly emulates the parsing of a command line.
pub fn read_empty_command_line() -> Vec<i32> {
vec![]
}
/// Prints all the elements of the vector.
/// vector is borrowed here
pub fn print_vec(v: &Vec<i32>) {
print!("[ ");
for t in v {
print!("{} ", t);
}
println!("]");
}
}
#![allow(unused)]
fn main() {
//! This is an example of Rust crate comments (or inner comments).
//! They will be rendered in the front page of your (crate) library.
//!
//! # How to generate the documentation
//!
//! 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 generated documentation can be found in the `target/doc/collections/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 Common Markdown syntax.
//!
//! Below we will use the `///` comments that will comment the code directly below.
//! We can also use `//` but they will not be rendered.
//! All the lines written here could be enclosed in `/*! ... */` instead of being prefixed by `//!`.
//!
//! For more information about writing documentation [follow that link](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html).
//!
//! # Tooling
//!
//! Also Rust comes with great tooling.
//! - [Clippy](https://doc.rust-lang.org/stable/clippy/): The official Rust linter.
//! - [Rustfmt](https://github.com/rust-lang/rustfmt): The official Rust code formatter.
pub mod io;
pub mod minimum;
pub mod something_or_nothing;
#[test]
fn test_creation() {
use something_or_nothing::SomethingOrNothing;
let n1: SomethingOrNothing<i32> = SomethingOrNothing::default();
assert!(n1 == SomethingOrNothing::Nothing);
let n2: SomethingOrNothing<i32> = SomethingOrNothing::Something(1);
assert!(n2 == SomethingOrNothing::Something(1));
}
#[cfg(test)]
mod tests {
use crate::minimum::Minimum;
use crate::something_or_nothing::{SomethingOrNothing, find_min};
#[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_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 collections::io;
use collections::something_or_nothing::find_min;
fn main() -> Result<(), String> {
//ANCHOR: vec
let tab: Vec<i32> = io::read_command_line(10usize);
println!("Among the Somethings in the list:");
io::print_tab(&tab);
let min = find_min(&tab);
min.print();
//ANCHOR_END: vec
let tab = io::read_command_line_str()?;
println!("Among the Somethings in the list:");
io::print_tab(&tab);
let min = find_min(&tab);
min.print();
//ANCHOR: ref
println!("Among the Somethings in the list:");
io::print_tab(&tab[1..9]);
let min = find_min(&tab[1..9]);
min.print();
//ANCHOR_END: ref
//ANCHOR: tab
let tab = [1, 2, 3, 4, 5, 6];
println!("Among the Somethings in the list:");
io::print_tab(&tab);
let min = find_min(&tab);
min.print();
//ANCHOR_END: tab
Ok(())
}
#![allow(unused)]
fn main() {
//! Contains functions to interact with the user, either
//! by reading inputs from the terminal, either by writing values
//! in it.
use rand::Rng;
// ANCHOR: read_command_line
/// Poorly emulates the parsing of a command line.
pub fn read_command_line(len: usize) -> Vec<i32> {
let mut rng = rand::rng();
// ANCHOR: vec_new
let mut v: Vec<i32> = Vec::new();
// ANCHOR_END: vec_new
// ANCHOR: vec_for
for _i in 0..len {
// ANCHOR: vec_push
v.push(rng.random());
// ANCHOR_END: vec_push
}
// ANCHOR_END: vec_for
v
}
// ANCHOR_END: read_command_line
// ANCHOR: read_command_line_str
/// Poorly emulates the parsing of a command line.
pub fn read_command_line_str() -> Result<Vec<i32>, String> {
// ANCHOR: from
let mut s = String::from("20 10 48 58 29 0 58 -10 39 5485 394");
// ANCHOR_END: from
// ANCHOR: push_str
s.push_str(" -100");
// ANCHOR_END: push_str
// ANCHOR: push_char
s.push(' ');
s.push('1');
s.push('2');
// ANCHOR_END: push_char
// ANCHOR: split
let s: Vec<&str> = s.split_ascii_whitespace().collect();
// ANCHOR_END: split
// ANCHOR: string_for
let mut v = Vec::new();
for i in 0..s.len() {
v.push(
// ANCHOR: conversion
s.get(i)
.ok_or(String::from("Unable to index"))?
.parse()
.map_err(|_| format!("Unable to parse {}", s[i]))?,
// ANCHOR_END: conversion
);
}
// ANCHOR_END: string_for
Ok(v)
}
// ANCHOR_END: read_command_line_str
/// Prints all the elements of the `tab`.
/// Tab is borrowed here
// ANCHOR: print_tab
pub fn print_tab(tab: &[i32]) {
for t in tab {
print!("{} ", t);
}
println!();
}
// ANCHOR_END: print_tab
}
#![allow(unused)]
fn main() {
//! Contains a generic trait implementation for computing the minimum between two
//! values. It is the equivalent of the `<` operator.
//!
//! # Examples
//!
//! For integers this would look like
//!
//! ```
//! # use collections::minimum::Minimum;
//! let one = 1;
//! let two = 2;
//! assert!(Minimum::min(one, two) == one);
//! ```
/// The [Minimum] trait computes the minimum value between two values of a type
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 }
}
}
#[cfg(test)]
mod tests {
use crate::minimum::Minimum;
#[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);
}
}
}
//! Contains the core logic of the library, allowing to store generic values
//! (or their absence) and manipulate them.
use crate::minimum::Minimum;
/// A 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 method that prints the content of a SomethingOrNothing.
pub fn print(&self) {
match self {
SomethingOrNothing::Nothing => println!("Nothing."),
SomethingOrNothing::Something(val) => println!("Something is: {}", val),
}
}
}
/// Implementation of the [Default] trait that creates a [SomethingOrNothing]
/// that is a `Nothing` variant.
///
/// # Example
///
/// ```
/// # use collections::something_or_nothing::SomethingOrNothing;
/// # fn main() {
/// let def: SomethingOrNothing<i32> = SomethingOrNothing::default();
/// assert!(def == SomethingOrNothing::Nothing);
/// # }
/// ```
impl<T> Default for SomethingOrNothing<T> {
/// By Default a [SomethingOrNothing] is a nothing.
fn default() -> Self {
SomethingOrNothing::Nothing
}
}
/// Implementation of the [PartialEq] trait that is useful for tests.
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,
}
}
}
/// Implementation of the [Minimum] trait used for comparing values
/// in this crate.
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 minimum value
/// or [SomethingOrNothing::Nothing] if no minimum value was found.
///
/// # Example
///
/// ```
/// # use collections::something_or_nothing::{SomethingOrNothing, find_min};
/// # fn main() {
/// let tab = vec![10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_min(&tab);
/// assert!(min == SomethingOrNothing::Something(2));
/// # }
/// ```
// ANCHOR: find_min
pub fn find_min<T: Minimum>(tab: &[T]) -> SomethingOrNothing<T> {
let mut minimum = SomethingOrNothing::Nothing;
// Here, if T is Copyable, t is not moved in the loop
for t in tab {
minimum = minimum.min(SomethingOrNothing::Something(*t));
}
minimum
}
// ANCHOR_END: find_min
#![allow(unused)]
fn main() {
/*!
lifetimes illustrates the use of [Vec] and the Error Handling with [Option] and [Result].
It also showcases struct enums.
*/
pub mod custom_int;
pub mod io;
mod minimum;
pub mod something_or_nothing;
#[cfg(test)]
mod tests {
use crate::minimum::Minimum;
use crate::something_or_nothing::{SomethingOrNothing, find_min};
#[test]
fn test_creation() {
let n1: SomethingOrNothing<i32> = SomethingOrNothing::default();
assert!(n1 == SomethingOrNothing::default());
let n2: SomethingOrNothing<i32> = SomethingOrNothing::new(1);
assert!(n2 == SomethingOrNothing::new(1));
}
#[test]
#[should_panic]
fn test_failure_creation() {
let n2: SomethingOrNothing<i32> = SomethingOrNothing::new(1);
assert!(n2 == SomethingOrNothing::default());
assert!(n2 == SomethingOrNothing::new(2));
}
#[test]
fn test_min() {
let a = vec![1, 5, -1, 2, 0, 10, 11, 0, 3];
let min = find_min(&a);
assert!(*min.unwrap() == -1);
}
#[test]
fn test_min_empty() {
let a: Vec<i32> = vec![];
let min = find_min(&a);
assert!(min == SomethingOrNothing::default());
}
#[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::new(5i32);
let y = SomethingOrNothing::new(10i32);
let z = SomethingOrNothing::default();
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 lifetimes::custom_int::CustomInt;
use lifetimes::io;
use lifetimes::something_or_nothing::find_min;
// ANCHOR: main
fn main() -> Result<(), String> {
let v1 = vec![1, 3, 6, 9];
let v2 = vec![2, 4, 2, 1];
let v3 = vec![7, 4, 5, 3];
let v4 = vec![4, 1, 1, 1];
let v5 = vec![2, 5, 1, 8];
let v6 = vec![5, 1, 5, 2];
let v7 = vec![7, 6, 6, 7];
let v8 = vec![8, 2, 2, 2];
let lhs = vec![
CustomInt::try_new(&v1, 1)?,
CustomInt::try_new(&v2, -1)?,
CustomInt::try_new(&v3, 1)?,
CustomInt::try_new(&v4, -1)?,
CustomInt::try_new(&v5, 1)?,
CustomInt::try_new(&v6, 1)?,
CustomInt::try_new(&v7, 1)?,
CustomInt::try_new(&v8, 1)?,
];
println!("Among the custom ints in the list:");
io::print_tab_custom_int(&lhs);
let min = find_min(&lhs);
println!("The minimum is {min}");
Ok(())
}
// ANCHOR_END: main
#![allow(unused)]
fn main() {
use std::cmp::Ordering;
use crate::minimum::Minimum;
/// Larger ints based on a [Vec] of [u8] to represent arbitrary lengthy numbers.
/// The number has a sign as well.
// ANCHOR: custom_int
#[derive(Debug)]
pub struct CustomInt<'a> {
/// The data contains the unsigned integers that are read from right to left
/// The number 1337 is stored as vec![7, 3, 3, 1]. Each number must be in the range [0,9]
/// and no trailing 0s are allowed.
data: &'a Vec<u8>,
/// Contains the sign of the number +/-1;
sign: i8,
}
// ANCHOR_END: custom_int
// ANCHOR: custom_int_impl
impl<'a> CustomInt<'a>
// ANCHOR_END: custom_int_impl
{
/// Tries to create a new [CustomInt]. If the number is valid it returns
/// an Ok(CustomInt) an Error otherwise.
///
/// # Examples
///
/// ```
/// use lifetimes::custom_int::CustomInt;
/// let v1 = vec![1, 2, 3, 4];
/// let num = CustomInt::try_new(&v1, 1);
/// assert!(num.is_ok());
/// let num = CustomInt::try_new(&v1, -1);
/// assert!(num.is_ok());
/// let num = CustomInt::try_new(&v1, 10);
/// assert!(num.is_err());
/// let num = CustomInt::try_new(&v1, -10);
/// assert!(num.is_err());
/// let v1 = vec![];
/// let num = CustomInt::try_new(&v1, -1);
/// assert!(num.is_err());
/// ```
///
// ANCHOR: try_new
pub fn try_new(data: &'a Vec<u8>, sign: i8) -> Result<Self, String> {
if data.is_empty() {
Err(String::from("Data is empty."))
} else if sign == 1 || sign == -1 {
Ok(CustomInt { data, sign })
} else {
Err(String::from("Invalid sign."))
}
}
// ANCHOR_END: try_new
}
// ANCHOR: minimum
impl<'a> Minimum<'a> for CustomInt<'a>
// ANCHOR_END: minimum
{
// ANCHOR: min
fn min(&'a self, rhs: &'a Self) -> &'a Self {
match self.sign.cmp(&rhs.sign) {
Ordering::Less => return self,
Ordering::Greater => return rhs,
Ordering::Equal => match self.data.len().cmp(&rhs.data.len()) {
Ordering::Less => {
if self.sign == 1 {
return self;
} else {
return rhs;
}
}
Ordering::Greater => {
if self.sign == 1 {
return rhs;
} else {
return self;
}
}
Ordering::Equal => {
for (l, r) in self.data.iter().rev().zip(rhs.data.iter().rev()) {
let ls = (*l as i8) * self.sign;
let rs = (*r as i8) * self.sign;
match ls.cmp(&rs) {
Ordering::Less => return self,
Ordering::Greater => return rhs,
Ordering::Equal => {}
}
}
}
},
}
self
}
// ANCHOR_END: min
}
// ANCHOR: partialeq
impl<'a> PartialEq for CustomInt<'a>
// ANCHOR_END: partialeq
{
fn eq(&self, other: &Self) -> bool {
if self.sign == other.sign && self.data.len() == other.data.len() {
self.data
.iter()
.zip(other.data.iter())
.try_fold(true, |_, (l, r)| if *l == *r { Some(true) } else { None })
.is_some()
} else {
false
}
}
}
// ANCHOR: display
impl<'a> std::fmt::Display for CustomInt<'a>
// ANCHOR_END: display
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// This could be replaced by an `?`
if self.sign == -1 {
write!(f, "-")?;
}
// This could be replaced by an `?`
let res = self
.data
.iter()
.rev()
.try_fold((), |_, t| write!(f, "{}", t));
res
}
}
#[cfg(test)]
mod tests {
use crate::custom_int::CustomInt;
use crate::minimum::Minimum;
use crate::something_or_nothing::find_min;
#[test]
fn test_creation() {
let v1 = vec![1, 2, 3, 4];
CustomInt::try_new(&v1, 1).unwrap();
CustomInt::try_new(&v1, -1).unwrap();
}
#[test]
#[should_panic]
fn test_failure_creation_sign() {
let v1 = vec![1, 2, 3, 4];
CustomInt::try_new(&v1, 10).unwrap();
}
#[test]
#[should_panic]
fn test_failure_creation_sign2() {
let v1 = vec![1, 2, 3, 4];
CustomInt::try_new(&v1, 0).unwrap();
}
#[test]
#[should_panic]
fn test_failure_creation_data() {
let v1 = vec![];
CustomInt::try_new(&v1, 1).unwrap();
}
#[test]
fn test_min() {
let mut v = Vec::new();
let v1 = vec![1, 2, 3, 4];
let v2 = vec![1, 2, 3];
let lhs = CustomInt::try_new(&v1, 1).unwrap();
let rhs = CustomInt::try_new(&v2, 1).unwrap();
assert!(rhs == *lhs.min(&rhs));
v.push(lhs);
v.push(rhs);
let lhs = CustomInt::try_new(&v1, -1).unwrap();
let rhs = CustomInt::try_new(&v2, -1).unwrap();
assert!(lhs == *lhs.min(&rhs));
v.push(lhs);
v.push(rhs);
let v1 = vec![1, 2, 3, 4];
let v2 = vec![1, 2, 5, 4];
let lhs = CustomInt::try_new(&v1, -1).unwrap();
let rhs = CustomInt::try_new(&v2, -1).unwrap();
assert!(rhs == *lhs.min(&rhs));
v.push(lhs);
v.push(rhs);
let lhs = CustomInt::try_new(&v1, 1).unwrap();
let rhs = CustomInt::try_new(&v2, 1).unwrap();
assert!(lhs == *lhs.min(&rhs));
let min = find_min(&v);
assert_eq!(*min.unwrap(), CustomInt::try_new(&v2, -1).unwrap());
}
}
}
#![allow(unused)]
fn main() {
use crate::custom_int::CustomInt;
/// Prints all the elements of the `tab`.
/// Tab is borrowed here
pub fn print_tab(tab: &Vec<i32>) {
for t in tab {
print!("{} ", t);
}
println!();
}
/// Prints all the elements of the `tab`.
/// Tab is borrowed here
pub fn print_tab_custom_int(tab: &Vec<CustomInt>) {
for i in tab {
println!("{i} ");
}
println!();
}
}
#![allow(unused)]
fn main() {
// ANCHOR: minimum
pub trait Minimum<'a> {
fn min(&'a self, rhs: &'a Self) -> &'a Self;
}
// ANCHOR_END: minimum
// ANCHOR: min
impl<'a> Minimum<'a> for i32 {
fn min(&'a self, rhs: &'a Self) -> &'a Self {
if self < rhs { self } else { rhs }
}
}
// ANCHOR_END: min
}
use std::fmt::Display;
use crate::minimum::Minimum;
/// A generic newtype that wraps an Option<T>.
// ANCHOR: newtype
#[derive(Debug)]
pub struct SomethingOrNothing<T>(Option<T>);
// ANCHOR_END: newtype
impl<T> SomethingOrNothing<T> {
pub fn new(val: T) -> Self {
SomethingOrNothing(Some(val))
}
// ANCHOR: newtype_unwrap
pub fn unwrap(self) -> T {
self.0.unwrap()
}
// ANCHOR_END: newtype_unwrap
}
// ANCHOR: newtype_display
impl<T: Display> std::fmt::Display for SomethingOrNothing<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
SomethingOrNothing(None) => write!(f, "Nothing.")?,
SomethingOrNothing(Some(val)) => write!(f, "Something is: {}", val)?,
}
Ok(())
}
}
// ANCHOR_END: newtype_display
// ANCHOR: newtype_default
impl<T> Default for SomethingOrNothing<T> {
/// By Default a [SomethingOrNothing] is a nothing.
fn default() -> Self {
SomethingOrNothing(None)
}
}
// ANCHOR_END: newtype_default
// ANCHOR: newtype_partialeq
impl<T: PartialEq> PartialEq for SomethingOrNothing<T> {
fn eq(&self, other: &Self) -> bool {
match (&self, &other) {
(SomethingOrNothing(None), SomethingOrNothing(None)) => true,
(SomethingOrNothing(Some(lhs)), SomethingOrNothing(Some(rhs))) => lhs == rhs,
_ => false,
}
}
}
// ANCHOR_END: newtype_partialeq
// ANCHOR: min
// ANCHOR: impl_min
impl<'a, T: Minimum<'a> + PartialEq> Minimum<'a> for SomethingOrNothing<T>
// ANCHOR_END: impl_min
{
fn min(&'a self, rhs: &'a Self) -> &'a Self {
match (self, rhs) {
(SomethingOrNothing(None), SomethingOrNothing(None)) => self,
(SomethingOrNothing(Some(l)), SomethingOrNothing(Some(r))) => {
if *l == *l.min(r) {
self
} else {
rhs
}
}
(SomethingOrNothing(None), SomethingOrNothing(Some(_))) => rhs,
(SomethingOrNothing(Some(_)), SomethingOrNothing(None)) => self,
}
}
}
// ANCHOR_END: min
/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
/// Returns a [Something] containing the minimum value
/// or [Nothing] if no minimum value was found.
///
/// # Examples
///
/// ```
/// # use lifetimes::something_or_nothing::{SomethingOrNothing, find_min};
/// # fn main() {
/// let tab = vec![10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_min(&tab);
/// assert!(*min.unwrap() == 2);
/// # }
/// ```
///
/// ```
/// # use lifetimes::something_or_nothing::{SomethingOrNothing, find_min};
/// # fn main() {
/// let tab: Vec<i32> = vec![];
/// let min = find_min(&tab);
/// assert!(min == SomethingOrNothing::default());
/// # }
/// ```
// ANCHOR: find_min
pub fn find_min<'a, T: Minimum<'a>>(tab: &'a [T]) -> SomethingOrNothing<&'a T> {
// A very elegant fold applied on an iterator
tab.iter().fold(SomethingOrNothing::default(), |res, x| {
let r = match res {
SomethingOrNothing(None) => x,
SomethingOrNothing(Some(r)) => r.min(x),
};
SomethingOrNothing::new(r)
})
}
// ANCHOR_END: find_min
/// Finds the minimum values contained in two slices and returns the reference
/// towards the slice that contains it.
///
/// # Examples
///
/// ```
/// # use lifetimes::something_or_nothing::{SomethingOrNothing, vec_with_min};
/// # fn main() {
/// let tab1 = vec![10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let tab2 = vec![10, 32, 12, 43, -2, 53, 83, 2, 9];
///
/// let min = vec_with_min(&tab1, &tab2).unwrap();
/// assert!(min == &tab2);
/// # }
/// ```
pub fn vec_with_min<'a, T: Minimum<'a> + PartialEq>(
lhs: &'a [T],
rhs: &'a [T],
) -> SomethingOrNothing<&'a [T]> {
match (find_min(lhs), find_min(rhs)) {
(SomethingOrNothing(None), SomethingOrNothing(None)) => SomethingOrNothing::default(),
(SomethingOrNothing(None), SomethingOrNothing(Some(_))) => SomethingOrNothing::new(rhs),
(SomethingOrNothing(Some(_)), SomethingOrNothing(None)) => SomethingOrNothing::new(lhs),
(SomethingOrNothing(Some(l)), SomethingOrNothing(Some(r))) => {
if *l == *l.min(r) {
SomethingOrNothing::new(lhs)
} else {
SomethingOrNothing::new(rhs)
}
}
}
}
#![allow(unused)]
fn main() {
/*!
cli illustrates the use of [Vec] and the Error Handling with [Option] and [Result].
It also showcases struct enums.
*/
pub mod io;
mod minimum;
pub mod something_or_nothing;
#[cfg(test)]
mod tests {
use crate::minimum::Minimum;
use crate::something_or_nothing::{SomethingOrNothing, find_min};
#[test]
fn test_creation() {
let n1: SomethingOrNothing<i32> = SomethingOrNothing::default();
assert!(n1 == SomethingOrNothing::default());
let n2: SomethingOrNothing<i32> = SomethingOrNothing::new(1);
assert!(n2 == SomethingOrNothing::new(1));
}
#[test]
#[should_panic]
fn test_failure_creation() {
let n2: SomethingOrNothing<i32> = SomethingOrNothing::new(1);
assert!(n2 == SomethingOrNothing::default());
assert!(n2 == SomethingOrNothing::new(2));
}
#[test]
fn test_min() {
let a = vec![1, 5, -1, 2, 0, 10, 11, 0, 3];
let min = find_min(&a);
assert!(min == SomethingOrNothing::new(-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::new(5i32);
let y = SomethingOrNothing::new(10i32);
let z = SomethingOrNothing::default();
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 cli::io;
fn main() -> Result<(), String> {
io::read_command_line_builder()?;
Ok(())
}
#![allow(unused)]
fn main() {
use std::{
fs::File,
io::{BufReader, Read, Write},
};
// ANCHOR: use_clap
use clap::{Arg, Command, Parser, value_parser};
// ANCHOR_END: use_clap
// ANCHOR: consts
const COMMAND: &str = "cli";
const AUTHOR: &str = "Orestis Malaspinas";
const VERSION: &str = "0.1.0";
// ANCHOR_END: consts
use crate::something_or_nothing::find_min;
// ANCHOR: read_from_urandom
fn read_from_urandom(count: usize) -> Result<Vec<i32>, String> {
// ANCHOR: open
let file = File::open("/dev/urandom").map_err(|_| "Could not open /dev/urandom")?;
// ANCHOR_END: open
// ANCHOR: read
let mut buf_reader = BufReader::new(file);
let mut numbers = vec![0; count * 4];
buf_reader
.read_exact(&mut numbers)
.map_err(|_| "Could not read numbers")?;
// ANCHOR_END: read
// ANCHOR: convert_to_i32
Ok(numbers
.chunks(4)
.map(|i| i32::from_be_bytes(i.try_into().unwrap()))
.collect::<Vec<_>>())
// ANCHOR_END: convert_to_i32
}
// ANCHOR_END: read_from_urandom
// ANCHOR: write_to_file
fn write_to_file(output: &str, numbers: &[i32]) -> Result<(), String> {
// ANCHOR: create
let mut file = File::create(output).map_err(|_| format!("Failed to create {output}"))?;
// ANCHOR_END: create
// ANCHOR: write
writeln!(file, "Among the Somethings in the list:")
.map_err(|_| "Failed to write header into file.")?;
for n in numbers {
write!(file, "{n} ").map_err(|_| format!("Failed to write {n} into file."))?;
}
writeln!(file,).map_err(|_| "Failed to write carriage return into file.")?;
writeln!(file, "{}", find_min(numbers).to_string())
.map_err(|_| "Failed to write minimum value into file.")?;
// ANCHOR_END: write
Ok(())
}
// ANCHOR_END: write_to_file
/// Reads i32 from the command line and returns a [Vec] containing
/// these numbers. Returns errors when the parsing fails.
pub fn read_command_line_builder() -> Result<(), String> {
// ANCHOR: matches
let matches =
// ANCHOR: new_command
Command::new(COMMAND)
.author(AUTHOR)
.version(VERSION)
// ANCHOR_END: new_command
// ANCHOR: new_args
.arg(
Arg::new("numbers") // id
.short('n') // version courte -n
.long("numbers") // ou longue --numbers
.help("A list of i32 numbers") // l'aide
.num_args(1..) // combien il y a d'entrées
.allow_negative_numbers(true) // on peut avoir des négatifs
.value_parser(value_parser!(i32)) // on veut s'assurer que ça soit des nombres
.required(false), // optionnel
)
.arg(
Arg::new("count")
.short('c')
.long("count")
.help("How many random numbers we want?")
.value_parser(value_parser!(usize))
.conflicts_with("numbers") // impossible d'avoir -c et -n
.required(false),
)
.arg(
Arg::new("output")
.short('o')
.long("output")
.help("Should we write output in a file?")
.required(false),
)
// ANCHOR: new_args
.get_matches();
// ANCHOR_END: matches
// ANCHOR: numbers_matches
let numbers = if let Some(count) =
// ANCHOR: get_one_matches
matches.get_one::<usize>("count")
// ANCHOR_END: get_one_matches
{
read_from_urandom(*count)?
} else if let Some(numbers) =
// ANCHOR: get_many_matches
matches.get_many::<i32>("numbers")
// ANCHOR_END: get_many_matches
{
numbers.copied().collect()
} else {
Vec::new()
};
// ANCHOR_END: numbers_matches
// ANCHOR: output_matches
if let Some(output) =
// ANCHOR: get_one_string_matches
matches.get_one::<String>("output")
// ANCHOR_END: get_one_string_matches
{
write_to_file(output, &numbers)?;
} else {
println!("Among the Somethings in the list:");
print_tab(&numbers);
println!("{}", find_min(&numbers).to_string());
}
// ANCHOR_END: output_matches
Ok(())
}
/// Does not compile without the feature derive
// ANCHOR: derive
#[derive(Parser)]
// ANCHOR: command
#[command(author, version, about, long_about = None)]
// ANCHOR_END: command
struct CliMin {
// ANCHOR: arg
#[arg(short, long, help = "A list of i32 numbers", num_args=1.., allow_negative_numbers=true, value_parser = clap::value_parser!(i32))]
numbers: Option<Vec<i32>>,
// ANCHOR_END: arg
#[arg(short, long, help = "How many random numbers we want?", value_parser = clap::value_parser!(usize), conflicts_with = "numbers")]
count: Option<usize>,
#[arg(short, long, help = "Filename for writing the numbers.")]
output: Option<String>,
}
// ANCHOR_END: derive
/// Reads i32 from the command line and returns a [Vec] containing
/// these numbers. Returns errors when the parsing fails.
// ANCHOR: read_command_line_derive
pub fn read_command_line_derive() -> Result<(), String> {
// ANCHOR: parse
let cli = CliMin::parse();
// ANCHOR_END: parse
let numbers = if let Some(count) = cli.count {
read_from_urandom(count)?
} else if let Some(numbers) = cli.numbers {
numbers
} else {
Vec::new()
};
if let Some(output) = cli.output {
write_to_file(&output, &numbers)?;
} else {
println!("Among the Somethings in the list:");
print_tab(&numbers);
println!("{}", find_min(&numbers).to_string());
}
Ok(())
}
// ANCHOR_END: read_command_line_derive
/// Prints all the elements of the `tab`.
/// Tab is borrowed here
pub fn print_tab(tab: &Vec<i32>) {
for t in tab {
print!("{} ", t);
}
println!();
}
}
#![allow(unused)]
fn main() {
// 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 std::fmt::Display;
use crate::minimum::Minimum;
/// A generic newtype that wraps an Option<T>.
#[derive(Clone, Copy)]
pub struct SomethingOrNothing<T>(Option<T>);
impl<T: Minimum + Display> SomethingOrNothing<T> {
pub fn new(val: T) -> Self {
SomethingOrNothing(Some(val))
}
/// A method that returns the content of a SomethingOrNothing as a String.
pub fn to_string(&self) -> String {
match self.0 {
None => String::from("Nothing."),
Some(val) => format!("Something is: {}", val),
}
}
}
impl<T> Default for SomethingOrNothing<T> {
/// By Default a [SomethingOrNothing] is a nothing.
fn default() -> Self {
SomethingOrNothing(None)
}
}
impl<T: PartialEq + Minimum> PartialEq for SomethingOrNothing<T> {
fn eq(&self, other: &Self) -> bool {
match (self.0, other.0) {
(None, None) => true,
(Some(lhs), Some(rhs)) => lhs == rhs,
_ => false,
}
}
}
impl<T: Minimum + Display> Minimum for SomethingOrNothing<T> {
fn min(self, rhs: Self) -> Self {
match (self.0, rhs.0) {
(None, None) => SomethingOrNothing(None),
(Some(lhs), Some(rhs)) => SomethingOrNothing::new(lhs.min(rhs)),
(None, Some(rhs)) => SomethingOrNothing::new(rhs),
(Some(lhs), None) => SomethingOrNothing::new(lhs),
}
}
}
/// Computes the minimum of an Array of a type T which implements the [Minimum] trait.
/// Returns a [Some] containing the minimum value
/// or [None] if no minimum value was found.
///
/// # Examples
///
/// ```
/// # use cli::something_or_nothing::{SomethingOrNothing, find_min};
/// # fn main() {
/// let tab = vec![10, 32, 12, 43, 52, 53, 83, 2, 9];
/// let min = find_min(&tab);
/// assert!(min == SomethingOrNothing::new(2));
/// # }
/// ```
///
/// ```
/// # use cli::something_or_nothing::{SomethingOrNothing, find_min};
/// # fn main() {
/// let tab: Vec<i32> = vec![];
/// let min = find_min(&tab);
/// assert!(min == SomethingOrNothing::default());
/// # }
/// ```
pub fn find_min<T: Minimum + Display>(tab: &[T]) -> SomethingOrNothing<T> {
let mut minimum: SomethingOrNothing<T> = SomethingOrNothing(None);
// Here, if T is Copyable, t is not moved in the loop
for t in tab {
minimum = minimum.min(SomethingOrNothing::new(*t));
}
minimum
}
#![allow(unused)]
fn main() {
pub mod immutable_linked_list;
pub mod safe_linked_list;
pub mod unsafe_linked_list;
}
use linked_list::immutable_linked_list::LinkedList as ImmutableList;
use linked_list::safe_linked_list::LinkedList as SafeList;
use linked_list::unsafe_linked_list::LinkedList as UnsafeList;
fn create_lists() -> (ImmutableList, SafeList, UnsafeList) {
(ImmutableList::new(), SafeList::new(), UnsafeList::new())
}
fn main() {
let (immutable_list, mut safe_list, mut unsafe_list) = create_lists();
// Populate lists
let immutable_list = immutable_list.push(1);
let immutable_list = immutable_list.push(2);
let immutable_list = immutable_list.push(3);
safe_list.push(1);
safe_list.push(2);
safe_list.push(3);
unsafe_list.push(1);
unsafe_list.push(2);
unsafe_list.push(3);
let (i_val, immutable_list) = immutable_list.pop();
let s_val = safe_list.pop();
let u_val = unsafe_list.pop();
assert_eq!(i_val, s_val);
assert_eq!(i_val, u_val);
assert_eq!(s_val, u_val);
let immutable_list = immutable_list.push(4);
safe_list.push(4);
unsafe_list.push(4);
immutable_list.print();
safe_list.print();
unsafe_list.print();
for _j in 1..5 {
let mut ul = UnsafeList::new();
for i in 1..1_000_000 {
ul.push(i);
}
}
unsafe_list.print();
}
#![allow(unused)]
fn main() {
// ANCHOR: element
struct Element {
data: i32,
next: Option<Box<Element>>,
}
// ANCHOR_END: element
impl Element {
fn new(data: i32, next: Option<Box<Element>>) -> Self {
Element { data, next }
}
}
// ANCHOR: linked_list
pub struct LinkedList {
head: Option<Box<Element>>,
}
// ANCHOR_END: linked_list
impl LinkedList {
// ANCHOR: new
pub fn new() -> Self {
Self { head: None }
}
// ANCHOR_END: new
// ANCHOR: is_empty
pub fn is_empty(self) -> (bool, Self) {
match self.head {
None => (true, self),
_ => (false, self),
}
}
// ANCHOR_END: is_empty
// ANCHOR: push
pub fn push(self, data: i32) -> Self {
let elem = Box::new(Element::new(data, self.head));
Self { head: Some(elem) }
}
// ANCHOR_END: push
// ANCHOR: pop
pub fn pop(self) -> (Option<i32>, Self) {
if let Some(elem) = self.head {
(Some(elem.data), Self { head: elem.next })
} else {
(None, Self { head: None })
}
}
// ANCHOR_END: pop
// ANCHOR: print
pub fn print(self) -> Self {
// Attention : new_list est reconstruite en ré-empilant chaque élément en
// tête, elle est donc renvoyée dans l'ordre inverse de `self`.
let mut new_list = Self::new();
// ANCHOR: while
let mut current = self.head;
while let Some(tmp) = current {
print!("{} --> ", tmp.data);
new_list = new_list.push(tmp.data);
current = tmp.next;
}
println!("∅");
// ANCHOR_END: while
new_list
}
// ANCHOR_END: print
#[allow(dead_code)]
// ANCHOR: clear
pub fn clear(self) {
let mut current = self.head;
while let Some(tmp) = current {
current = tmp.next;
}
}
// ANCHOR_END: clear
}
#[cfg(test)]
mod tests {
use super::LinkedList;
#[test]
fn new() {
let (is_empty, _) = LinkedList::new().is_empty();
assert!(is_empty);
}
#[test]
fn push() {
let list = LinkedList::new();
let list = list.push(1);
let (is_empty, list) = list.is_empty();
assert!(!is_empty);
assert_eq!(list.head.as_ref().unwrap().data, 1);
let list = list.push(2);
assert_eq!(list.head.unwrap().data, 2);
}
#[test]
fn pop() {
let list = LinkedList::new();
let (e, list) = list.pop();
assert_eq!(e, None);
let list = list.push(1);
let (e, list) = list.pop();
assert_eq!(e, Some(1));
let (e, list) = list.pop();
assert_eq!(e, None);
let list = list.push(2);
let list = list.push(3);
let list = list.push(4);
assert_eq!(list.head.as_ref().unwrap().data, 4);
let (e, list) = list.pop();
assert_eq!(list.head.as_ref().unwrap().data, 3);
assert_eq!(e, Some(4));
let (_, list) = list.pop();
let (_, list) = list.pop();
let (is_empty, _) = list.is_empty();
assert!(is_empty);
}
}
}
#![allow(unused)]
fn main() {
// ANCHOR: element
struct Element {
data: i32,
next: Option<Box<Element>>,
}
// ANCHOR_END: element
impl Element {
fn new(data: i32, next: Option<Box<Element>>) -> Self {
Element { data, next }
}
}
// ANCHOR: linked_list
pub struct LinkedList {
head: Option<Box<Element>>,
}
// ANCHOR_END: linked_list
impl LinkedList {
// ANCHOR: new
pub fn new() -> Self {
Self { head: None }
}
// ANCHOR_END: new
// ANCHOR: is_empty
pub fn is_empty(&self) -> bool {
self.head.is_none()
}
// ANCHOR_END: is_empty
// ANCHOR: push
pub fn push(&mut self, data: i32) {
// let new_element = Box::new(Element::new(data, self.head));
// Cela ne peut pas fonctionner, parce qu'on est derrière une référence partagée
// et donc on ne peut pas "move" self.head
// ANCHOR: take
let new_head = Box::new(Element::new(data, self.head.take()));
// ANCHOR_END: take
// take retourne la valeur qui se trouve dans Some et laisse un None
// à la place de l'option.
// C'est strictement équivalent au replace (ci-dessous)
self.head = Some(new_head);
}
// ANCHOR_END: push
// ANCHOR: push_replace
pub fn push_replace(&mut self, data: i32) {
// ANCHOR: replace
let old_head = std::mem::replace(&mut self.head, None);
let new_head = Box::new(Element::new(data, old_head));
// ANCHOR_END: replace
// replace retourne self.head et remplace l'ancienne valeur par None (comme ça le compilateur est content)
self.head = Some(new_head);
}
// ANCHOR_END: push_replace
// ANCHOR: push_unsafe
pub fn push_unsafe(&mut self, data: i32) {
let old_head = unsafe {
// De la documentation:
// `read` crée une copie bit à bit de `T`, que `T` soit [`Copy`] ou non.
// Si `T` n'est pas [`Copy`], utiliser à la fois la valeur renvoyée et la valeur de
// `*src` peut violer la sécurité de la mémoire. Notez que l'assignation à `*src` compte comme une
// utilisation parce qu'elle tentera de `drop` la valeur à `*src`.
let result = std::ptr::read(&self.head);
std::ptr::write(&mut self.head, None);
// Ce `write` est en fait un "truc" pour enlever l'aliasing entre
// self.head et result. Il écrase la valeur à self.head avec None
// sans `drop` self.head et donc result.
result
};
let new_head = Box::new(Element::new(data, old_head));
self.head = Some(new_head);
}
// ANCHOR_END: push_unsafe
// ANCHOR: pop
pub fn pop(&mut self) -> Option<i32> {
// map prend la valeur dans Some, lui applique la fonction anonyme
// et remballe la valeur obtenue dans un Some. Si l'Option
// originale est None, il se passe rien.
self.head.take().map(|element| {
self.head = element.next;
element.data
})
}
// ANCHOR_END: pop
// ANCHOR: print
pub fn print(&self) {
let mut current = &self.head;
while let Some(tmp) = ¤t {
print!("{} --> ", tmp.data);
current = &tmp.next;
}
println!("∅");
}
// ANCHOR_END: print
}
impl Drop for LinkedList {
fn drop(&mut self) {
let mut current = self.head.take();
while let Some(mut tmp) = current {
current = tmp.next.take();
}
}
}
#[cfg(test)]
mod test {
use super::LinkedList;
#[test]
fn new() {
assert!(LinkedList::new().is_empty());
}
#[test]
fn push() {
let mut list = LinkedList::new();
list.push(1);
assert_eq!(list.head.as_ref().unwrap().data, 1);
list.push(2);
assert_eq!(list.head.as_ref().unwrap().data, 2);
}
#[test]
fn pop() {
let mut list = LinkedList::new();
let e = list.pop();
assert_eq!(e, None);
list.push(1);
let e = list.pop();
assert_eq!(e, Some(1));
let e = list.pop();
assert_eq!(e, None);
list.push(2);
list.push(3);
list.push(4);
assert_eq!(list.head.as_ref().unwrap().data, 4);
let e = list.pop();
assert_eq!(list.head.as_ref().unwrap().data, 3);
assert_eq!(e, Some(4));
list.push(5);
list.push(6);
let e = list.pop();
assert_eq!(list.head.as_ref().unwrap().data, 5);
assert_eq!(e, Some(6));
}
}
}
#![allow(unused)]
fn main() {
use std::alloc::{Layout, alloc, dealloc, handle_alloc_error};
use std::ptr;
// ANCHOR: element
struct Element {
data: i32,
next: *mut Element,
}
// ANCHOR_END: element
impl Element {
// ANCHOR: new
fn new(data: i32, next: *mut Element) -> *mut Element {
let layout = Layout::new::<Element>();
let e = unsafe { alloc(layout) as *mut Element };
if e.is_null() {
handle_alloc_error(layout);
}
// On écrit dans la mémoire fraîchement allouée, encore non initialisée.
// L'opérateur `=` tenterait normalement de `drop` l'ancienne valeur du champ :
// c'est sans danger ici, `i32` et `*mut Element` n'ayant pas de destructeur.
// Pour un champ avec destructeur, il faudrait passer par `ptr::write`.
unsafe {
(*e).data = data;
(*e).next = next;
}
e
}
// ANCHOR_END: new
}
//ANCHOR: drop
impl Drop for Element {
fn drop(&mut self) {
let elem = self as *mut Element;
if !elem.is_null() {
let layout = Layout::new::<Element>();
unsafe {
dealloc(elem as *mut u8, layout);
}
}
}
}
//ANCHOR_END: drop
// ANCHOR: linked_list
pub struct LinkedList {
head: *mut Element,
}
// ANCHOR_END: linked_list
impl LinkedList {
// ANCHOR: ll_new
pub fn new() -> LinkedList {
LinkedList {
head: ptr::null_mut(),
}
}
// ANCHOR_END: ll_new
// ANCHOR: is_empty
fn is_empty(&self) -> bool {
self.head.is_null()
}
// ANCHOR_END: is_empty
// ANCHOR: push
pub fn push(&mut self, data: i32) {
let new_head = Element::new(data, self.head);
self.head = new_head;
}
// ANCHOR_END: push
// ANCHOR: pop
pub fn pop(&mut self) -> Option<i32> {
if self.is_empty() {
None
} else {
let old_head = self.head;
unsafe {
self.head = (*self.head).next;
}
let val = unsafe { (*old_head).data };
unsafe {
old_head.drop_in_place();
}
Some(val)
}
}
// ANCHOR_END: pop
// ANCHOR: print
pub fn print(&self) {
let mut current_head = self.head;
while !current_head.is_null() {
unsafe {
print!("{} --> ", (*current_head).data);
current_head = (*current_head).next;
}
}
println!("∅");
}
// ANCHOR_END: print
}
// ANCHOR: ll_drop
impl Drop for LinkedList {
fn drop(&mut self) {
while !self.is_empty() {
let _ = self.pop();
}
}
}
// ANCHOR_END: ll_drop
#[cfg(test)]
mod tests {
use super::LinkedList;
#[test]
fn new() {
assert!(LinkedList::new().is_empty());
}
#[test]
fn push() {
let mut list = LinkedList::new();
list.push(1);
assert_eq!(unsafe { (*list.head).data }, 1);
list.push(2);
assert_eq!(unsafe { (*list.head).data }, 2);
}
#[test]
fn pop() {
let mut list = LinkedList::new();
let e = list.pop();
assert_eq!(e, None);
list.push(1);
let e = list.pop();
assert_eq!(e, Some(1));
let e = list.pop();
assert_eq!(e, None);
list.push(2);
list.push(3);
list.push(4);
assert_eq!(unsafe { (*list.head).data }, 4);
let e = list.pop();
assert_eq!(unsafe { (*list.head).data }, 3);
assert_eq!(e, Some(4));
list.push(5);
list.push(6);
let e = list.pop();
assert_eq!(unsafe { (*list.head).data }, 5);
assert_eq!(e, Some(6));
}
}
}
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INT 100
typedef enum _result { ok, err_invalid_size, err_is_null } result;
const char *usage_msg =
"Error wrong number of arguments.\n"
"Usage: ./min_list <num1> <num2> ...\n"
" where <num1>, <num2>, ... must be valid integers.\n";
// Copies the value of the smallest value in the tab array in the min variable.
// Returns the pointer to a newly allocated value of the minimum value of the
// array if everything went fine. Returns NULL otherwise
int *list_find_min(int32_t *tab, int size);
// Prints all the element in the tab array.
// Returns err_invalid_size if size <= 0
// Returns err_is_null if tab is NULL
// Returns ok if everything went fine
result list_print(int32_t *tab, int size);
// Exits if the error code shows invalidity
void error_handling(result error_code, int32_t **tab);
// Parses a string to an integer.
// Returns a pointer to newly allocated data.
// Returns NULL if conversion failed.
int *parse_int32(char *arg_to_transform);
// Reads the command line inputs and stores them
// in a newly allocated array.
// Returns the array with the parsed numbers or NULL if allocation failed or an
// invalid number was parsed.
int *read_input(int size, char *char_num[]) {
int32_t *tab = malloc(size * sizeof(*tab));
if (NULL == tab) {
fprintf(stderr, "Memory allocation failed\n");
return NULL;
}
for (int i = 0; i < size; ++i) {
int *num = parse_int32(char_num[i]);
if (NULL == num) {
free(tab);
fprintf(stderr, "Tried to parse %s which is not a valid integer.\n",
char_num[i]);
return NULL;
}
tab[i] = *num;
free(num);
}
return tab;
}
int main(int argc, char *argv[]) {
if (argc == 1) {
fprintf(stderr, "%s", usage_msg);
return EXIT_FAILURE;
}
int size = argc - 1;
int32_t *tab = read_input(size, &argv[1]);
if (NULL == tab) {
fprintf(stderr, "Failure during argument parsing.\n");
return EXIT_FAILURE;
}
printf("Among the numbers in the list:\n");
error_handling(list_print(tab, size), &tab);
int *min = list_find_min(tab, size);
if (NULL == min) {
fprintf(stderr, "Could not find the minimum of the array.\n");
free(tab);
tab = NULL;
return EXIT_FAILURE;
}
printf("The value of the minimum of the numbers is: %d\n", *min);
free(min);
free(tab);
tab = NULL;
return EXIT_SUCCESS;
}
int min_i32(int32_t lhs, int32_t rhs) {
if (lhs < rhs) {
return lhs;
} else {
return rhs;
}
}
// Checks if size is valid and tab is not NULL
result list_is_valid(int32_t *tab, int size) {
if (size <= 0) {
return err_invalid_size;
}
if (NULL == tab) {
return err_is_null;
}
return ok;
}
result list_print(int32_t *tab, int size) {
result code = list_is_valid(tab, size);
if (code != ok) {
return code;
}
for (int i = 0; i < size; ++i) {
printf("%d ", tab[i]);
}
printf("\n");
return code;
}
int32_t *list_find_min(int32_t *tab, int size) {
result code = list_is_valid(tab, size);
if (code != ok) {
return NULL;
}
int32_t *min = malloc(sizeof(*min));
*min = tab[0];
for (int i = 1; i < size; ++i) {
*min = min_i32(*min, tab[i]);
}
return min;
}
void error_handling(result error_code, int32_t **tab) {
switch (error_code) {
case err_invalid_size:
fprintf(stderr, "Return value, %d. Size is <= 0.\n", error_code);
free(*tab);
*tab = NULL;
exit(EXIT_FAILURE);
break;
case err_is_null:
fprintf(stderr, "Tab is NULL.\n");
free(*tab);
*tab = NULL;
exit(EXIT_FAILURE);
break;
case ok:
break;
}
}
int32_t *parse_int32(char *arg_to_transform) {
if (strlen(arg_to_transform) == 0) {
return NULL; // empty string to parse
}
char *remaining;
errno = 0; // errno == 0 (defined in errno.h) means everything went fine
long arg = strtol(arg_to_transform, &remaining,
10); // number is parsed in base 10
if (*remaining != '\0' || errno != 0) {
return NULL; // Empty string parsed or an error occurred
}
if (arg < INT_MIN || arg > INT_MAX) {
return NULL; // Not within the limits of an int
}
int32_t *num = malloc(sizeof(*num));
*num = (int32_t)arg;
return num;
}