Chapter01
rodzic
02f1951a86
commit
dc15440c03
|
@ -0,0 +1,31 @@
|
|||
use std::io::{self, Write};
|
||||
use std::f64;
|
||||
|
||||
fn main() {
|
||||
println!("Let's print some lines:");
|
||||
println!();
|
||||
println!("Hello, world!");
|
||||
println!("{}, {}!", "Hello", "world");
|
||||
println!("Arguments can be referred to by their position: {0}, {1}! and {1}, {0}! are built from the same arguments", "Hello", "world");
|
||||
|
||||
println!("Furthermore the arguments can be named: \"{greeting}, {object}!\"", greeting = "Hello", object = "World");
|
||||
|
||||
println!("Number formatting: Pi is {0:.3} or {0:.0} for short", f64::consts::PI);
|
||||
|
||||
println!("... and there is more: {0:>0width$}={0:>width$}={0:#x}", 1535, width = 5);
|
||||
print!("Printing without newlines ... ");
|
||||
println!("is great");
|
||||
|
||||
let _ = write!(&mut io::stdout(), "Underneath, it's all writing to a stream...");
|
||||
println!();
|
||||
|
||||
println!("Write something!");
|
||||
let mut input = String::new();
|
||||
if let Ok(n) = io::stdin().read_line(&mut input) {
|
||||
println!("You wrote: {} ({} bytes) ", input, n);
|
||||
}
|
||||
else {
|
||||
eprintln!("There was an error :(");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
pub struct ArithmeticResults{
|
||||
sum: i32,
|
||||
difference: i32,
|
||||
product: i32,
|
||||
quotient: f32,
|
||||
}
|
||||
|
||||
pub fn print_basic_arithmetics(a: i32, b: i32) -> ArithmeticResults {
|
||||
ArithmeticResults {
|
||||
sum: a + b,
|
||||
difference: a - b,
|
||||
product: a * b,
|
||||
quotient: a / b
|
||||
}
|
||||
}
|
|
@ -15,4 +15,4 @@ fn main(){
|
|||
// Shifts
|
||||
println!("{ten:>ws$}",ten=10, ws=5 );
|
||||
println!("{ten:>0ws$}",ten=10, ws=5 );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
mod variables
|
||||
mod mutablility
|
||||
mod numbers
|
||||
mod arithmetics
|
||||
mod strings
|
||||
|
||||
mod arrays
|
||||
mod vectors
|
||||
mod tuples
|
||||
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
Plik binarny nie jest wyświetlany.
|
@ -1,21 +0,0 @@
|
|||
// Task : To explain assignment operations in rust
|
||||
// Author : Vigneshwer
|
||||
// Version : 1.0
|
||||
// Date : 3 Dec 2016
|
||||
|
||||
// Primitive libraries in rust
|
||||
use std::{i8,i16,i32,i64,u8,u16,u32,u64,f32,f64,isize,usize};
|
||||
use std::io::stdin;
|
||||
|
||||
fn main() {
|
||||
println!("Understanding assignment");
|
||||
// Complier will automatically figure out the datatype if not mentioned
|
||||
// Cannot change the value
|
||||
let num =10;
|
||||
println!("Num is {}", num);
|
||||
|
||||
// immutuable can change the value
|
||||
let age: i32 =40;
|
||||
println!("Age is {}", age);
|
||||
|
||||
}
|
Plik binarny nie jest wyświetlany.
|
@ -1,40 +0,0 @@
|
|||
// Task : Basic mathematical model on 2 numbers
|
||||
// Date : 26th Dec 2016
|
||||
// Version : 1.0
|
||||
// Author : Vigneshwer
|
||||
|
||||
// Libraries in rust
|
||||
use std::io;
|
||||
use std::{i32};
|
||||
|
||||
// Main Functions
|
||||
fn main() {
|
||||
|
||||
// Entering number 1
|
||||
println!("Enter First number ? ");
|
||||
let mut input_1 = String::new();
|
||||
io::stdin().read_line(&mut input_1)
|
||||
.expect("Failed to read line");
|
||||
|
||||
// Entering number 2
|
||||
println!("Enter second number ? ");
|
||||
let mut input_2 = String::new();
|
||||
io::stdin().read_line(&mut input_2)
|
||||
.expect("Failed to read line");
|
||||
|
||||
// Convert to int
|
||||
let a_int: i32 = input_1.trim().parse()
|
||||
.ok()
|
||||
.expect("Please type a number!");
|
||||
|
||||
let b_int: i32 = input_2.trim().parse()
|
||||
.ok()
|
||||
.expect("Please type a number!");
|
||||
|
||||
// output of basic operations
|
||||
println!("sum is: {}", a_int + b_int);
|
||||
println!("difference is: {}", a_int - b_int);
|
||||
println!("mutlipy is: {}", a_int * b_int);
|
||||
println!("division is: {}", a_int / b_int);
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "data-types"
|
||||
version = "0.1.0"
|
||||
authors = ["Claus Matzinger <claus.matzinger+kb@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,107 @@
|
|||
|
||||
// Rust allows another macro type: derive. It allows to "auto-implement"
|
||||
// supported traits. Clone, Debug, Copy are typically handy to derive.
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
struct MyCustomStruct {
|
||||
a: i32,
|
||||
b: u32,
|
||||
pub c: f32
|
||||
}
|
||||
|
||||
// A typical Rust struct has an impl block for behavior
|
||||
impl MyCustomStruct {
|
||||
|
||||
// The new function is static function, and by convention a constructor
|
||||
pub fn new(a: i32, b: u32, c: f32) -> MyCustomStruct {
|
||||
MyCustomStruct {
|
||||
a: a, b: b, c: c
|
||||
}
|
||||
}
|
||||
|
||||
// Instance functions feature a "self" reference as the first parameter
|
||||
// This self reference can be mutable or owned, just like other variables
|
||||
pub fn sum(&self) -> f32 {
|
||||
self.a as f32 + self.b as f32 + self.c
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::mem;
|
||||
use super::MyCustomStruct;
|
||||
|
||||
#[test]
|
||||
fn test_custom_struct() {
|
||||
// Rust features zero-overhead structs!
|
||||
assert_eq!(mem::size_of::<MyCustomStruct>(),
|
||||
mem::size_of::<i32>() + mem::size_of::<u32>() + mem::size_of::<f32>());
|
||||
|
||||
let m = MyCustomStruct::new(1, 2, 3_f32);
|
||||
assert_eq!(m.a, 1);
|
||||
assert_eq!(m.b, 2);
|
||||
assert_eq!(m.c, 3_f32);
|
||||
|
||||
// Let's call the instance method
|
||||
assert_eq!(m.sum(), 6_f32);
|
||||
|
||||
// The derived clone trait adds a method clone() and does a deep copy
|
||||
let m2 = m.clone();
|
||||
// We use the Debug formatter to format the struct
|
||||
assert_eq!(format!("{:?}", m2), "MyCustomStruct { a: 1, b: 2, c: 3.0 }");
|
||||
|
||||
// This is an implicit (deep) copy, possible only with the Copy trait
|
||||
// Added mutability allows to change struct members
|
||||
let mut m3 = m;
|
||||
|
||||
// As a copy, this should not affect the other instances
|
||||
m3.a = 100;
|
||||
|
||||
// We'll make sure that the values didn't change anywhere else
|
||||
assert_eq!(m2.a, 1);
|
||||
assert_eq!(m.a, 1);
|
||||
assert_eq!(m3.a, 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_math_stuff() {
|
||||
// Works as expected
|
||||
assert_eq!(2 + 2, 4);
|
||||
|
||||
// Rust lets you specify the datatype on literals by appending
|
||||
// them to the constant. Splitting them by _ is optional.
|
||||
assert_eq!(3.14 + 22.86, 26_f32);
|
||||
|
||||
// Some functions are only available on certain types
|
||||
assert_eq!(2_i32.pow(2), 4);
|
||||
assert_eq!(4_f32.sqrt(), 2_f32);
|
||||
|
||||
// Rust features unsigned variations of integer types
|
||||
let a: u64 = 32;
|
||||
let b: u64 = 64;
|
||||
|
||||
// Risky, this could overflow
|
||||
assert_eq!(b - a, 32);
|
||||
|
||||
// ... this is why there is an overflowing_sub() function available
|
||||
assert_eq!(a.overflowing_sub(b), (18446744073709551584, true));
|
||||
|
||||
// By default, Rust variables are immutable, add the mut qualifier
|
||||
// to be able to change the value
|
||||
let mut c = 100;
|
||||
c += 1;
|
||||
assert_eq!(c, 101);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn attempt_overflows() {
|
||||
let a = 10_u32;
|
||||
let b = 11_u32;
|
||||
|
||||
// This will panic since the result is going to be an unsigned
|
||||
// type which cannot handle negative numbers
|
||||
// Note: _ means ignore the result
|
||||
let _ = a - b;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'debug-me'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=debug-me",
|
||||
"--package=debug-me"
|
||||
],
|
||||
"filter": {
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in executable 'debug-me'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--bin=debug-me",
|
||||
"--package=debug-me"
|
||||
],
|
||||
"filter": {
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "debug-me"
|
||||
version = "0.1.0"
|
||||
authors = ["Claus Matzinger <claus.matzinger+kb@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug",
|
||||
"program": "${workspaceRoot}/target/debug/${workspaceRootFolderName}",
|
||||
"args": [],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"sourceLanguages": ["rust"]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
struct MyStruct {
|
||||
prop: usize,
|
||||
}
|
||||
|
||||
struct Point(f32, f32);
|
||||
|
||||
fn main() {
|
||||
let a = 42;
|
||||
let b = vec![0, 0, 0, 100];
|
||||
let c = [1, 2, 3, 4, 5];
|
||||
let d = 0x5ff;
|
||||
let e = MyStruct { prop: 10 };
|
||||
let p = Point(3.14, 3.14);
|
||||
|
||||
println!("Hello, world!");
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "execution-flow"
|
||||
version = "0.1.0"
|
||||
authors = ["Claus Matzinger <claus.matzinger+kb@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,86 @@
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn conditionals() {
|
||||
let i = 20;
|
||||
// Rust's if statement does not require parenthesis
|
||||
if i < 2 {
|
||||
assert!(i < 2);
|
||||
} else if i > 2 {
|
||||
assert!(i > 2);
|
||||
} else {
|
||||
assert_eq!(i, 2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loops() {
|
||||
|
||||
let mut i = 42;
|
||||
let mut broke = false;
|
||||
|
||||
// a basic loop with control statements
|
||||
loop {
|
||||
i -= 1;
|
||||
if i < 2 {
|
||||
broke = true;
|
||||
break;
|
||||
} else if i > 2 {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
assert!(broke);
|
||||
|
||||
// loops and other constructs can be named for better readability ...
|
||||
'outer: loop {
|
||||
'inner: loop {
|
||||
break 'inner; // ... and specifically jumped out of
|
||||
}
|
||||
break 'outer;
|
||||
}
|
||||
let mut iterations: u32 = 0;
|
||||
|
||||
// loops can even have return values on breaks
|
||||
let total_squared = loop {
|
||||
iterations += 1;
|
||||
|
||||
if iterations >= 10 {
|
||||
break iterations.pow(2);
|
||||
}
|
||||
};
|
||||
assert_eq!(total_squared, 100);
|
||||
|
||||
// for loops can use ranges ...
|
||||
for i in 0..10 {
|
||||
assert!(i >= 0 && i < 10)
|
||||
}
|
||||
|
||||
// or anything that is an iterator
|
||||
for v in vec![1, 1, 1, 1].iter() {
|
||||
assert_eq!(v, &1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn more_conditionals() {
|
||||
let my_option = Some(10);
|
||||
|
||||
// If let statements can do simple pattern matching
|
||||
if let Some(unpacked) = my_option {
|
||||
assert_eq!(unpacked, 10);
|
||||
}
|
||||
|
||||
let mut other_option = Some(2);
|
||||
// there is also while let, which does the same thing
|
||||
while let Some(unpacked) = other_option {
|
||||
|
||||
// if can also return values in assignments
|
||||
other_option = if unpacked > 0 {
|
||||
Some(unpacked - 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
assert_eq!(other_option, None)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
**/*.rs.bk
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
authors = ["Claus Matzinger <claus.matzinger+kb@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,40 @@
|
|||
use std::io::{self, Write};
|
||||
use std::f64;
|
||||
|
||||
fn main() {
|
||||
// Basic printing with arguments
|
||||
println!("Let's print some lines:");
|
||||
println!();
|
||||
println!("Hello, world!");
|
||||
println!("{}, {}!", "Hello", "world");
|
||||
// No newlines
|
||||
print!("Hello, ");
|
||||
println!("world!");
|
||||
|
||||
println!("Arguments can be referred to by their position: {0}, {1}! and {1}, {0}! are built from the same arguments", "Hello", "world");
|
||||
|
||||
// More complex arguments
|
||||
println!("Furthermore the arguments can be named: \"{greeting}, {object}!\"", greeting = "Hello", object = "World");
|
||||
|
||||
// Number formatting
|
||||
println!("Number formatting: Pi is {0:.3} or {0:.0} for short", f64::consts::PI);
|
||||
|
||||
// Padding and hex formatting
|
||||
println!("... and there is more: {0:>0width$}={0:>width$}={0:#x}", 1535, width = 5);
|
||||
|
||||
// Writing to a stream directly
|
||||
let _ = write!(&mut io::stdout(), "Underneath, it's all writing to a stream...");
|
||||
println!();
|
||||
|
||||
// Reading from std::in
|
||||
println!("Write something!");
|
||||
let mut input = String::new();
|
||||
if let Ok(n) = io::stdin().read_line(&mut input) {
|
||||
println!("You wrote: {} ({} bytes) ", input, n);
|
||||
}
|
||||
else {
|
||||
// Printing to std::err
|
||||
eprintln!("There was an error :(");
|
||||
}
|
||||
}
|
||||
|
Plik binarny nie jest wyświetlany.
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "pi-estimator"
|
||||
version = "0.1.0"
|
||||
authors = ["Claus Matzinger <claus.matzinger+kb@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
rust-pilib = { path = '../rust-pilib', version = '*'}
|
|
@ -0,0 +1,26 @@
|
|||
// declare the module by its file name
|
||||
mod rounding;
|
||||
|
||||
// Rust will also accept if you implement it right away
|
||||
mod printer {
|
||||
// import a function from an external crate (no more extern declaration required!)
|
||||
use rust_pilib::monte_carlo_pi;
|
||||
|
||||
// crates present in the parent can be imported using the crate prefix
|
||||
use crate::rounding::round;
|
||||
|
||||
pub fn pretty_print_pi_approx(iterations: usize) {
|
||||
let pi = monte_carlo_pi(iterations);
|
||||
let places: usize = 2;
|
||||
|
||||
println!("Pi is ~ {} and rounded to {} places {}", pi, places, round(pi, places));
|
||||
}
|
||||
}
|
||||
|
||||
// import from the module above
|
||||
use printer::pretty_print_pi_approx;
|
||||
|
||||
|
||||
fn main() {
|
||||
pretty_print_pi_approx(100_000);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
pub fn round(nr: f32, places: usize) -> f32 {
|
||||
let multiplier = 10_f32.powi(places as i32);
|
||||
(nr * multiplier + 0.5).floor() / multiplier
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::round;
|
||||
|
||||
#[test]
|
||||
fn round_positive() {
|
||||
assert_eq!(round(3.123456, 2), 3.12);
|
||||
assert_eq!(round(3.123456, 4), 3.1235);
|
||||
assert_eq!(round(3.999999, 2), 4.0);
|
||||
assert_eq!(round(3.0, 2), 3.0);
|
||||
assert_eq!(round(9.99999, 2), 10.0);
|
||||
assert_eq!(round(0_f32, 2), 0_f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_negative() {
|
||||
assert_eq!(round(-3.123456, 2), -3.12);
|
||||
assert_eq!(round(-3.123456, 4), -3.1235);
|
||||
assert_eq!(round(-3.999999, 2), -4.0);
|
||||
assert_eq!(round(-3.0, 2), -3.0);
|
||||
assert_eq!(round(-9.99999, 2), -10.0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "rust-pilib"
|
||||
version = "0.1.0"
|
||||
authors = ["Claus Matzinger <claus.matzinger+kb@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
rand = "^0.5"
|
|
@ -0,0 +1,54 @@
|
|||
use rand::prelude::*;
|
||||
|
||||
pub fn monte_carlo_pi(iterations: usize) -> f32 {
|
||||
let mut inside_circle = 0;
|
||||
for _ in 0..iterations {
|
||||
|
||||
// generate two random coordinates between 0 and 1
|
||||
let x: f32 = random::<f32>();
|
||||
let y: f32 = random::<f32>();
|
||||
|
||||
// calculate the circular distance from 0, 0
|
||||
if x.powi(2) + y.powi(2) <= 1_f32 {
|
||||
// if it's within the circle, increase the count
|
||||
inside_circle += 1;
|
||||
}
|
||||
}
|
||||
// return the ratio of 4 times the hits to the total iterations
|
||||
(4_f32 * inside_circle as f32) / iterations as f32
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// import the parent crate's functions
|
||||
|
||||
use super::*;
|
||||
|
||||
fn is_reasonably_pi(pi: f32) -> bool {
|
||||
pi >= 3_f32 && pi <= 4.5_f32
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_monte_carlo_pi_1() {
|
||||
let pi = monte_carlo_pi(1);
|
||||
assert!(pi == 0_f32 || pi == 4_f32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_monte_carlo_pi_500() {
|
||||
let pi = monte_carlo_pi(500);
|
||||
assert!(is_reasonably_pi(pi));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_monte_carlo_pi_1000() {
|
||||
let pi = monte_carlo_pi(1000);
|
||||
assert!(is_reasonably_pi(pi));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_monte_carlo_pi_5000() {
|
||||
let pi = monte_carlo_pi(5000);
|
||||
assert!(is_reasonably_pi(pi));
|
||||
}
|
||||
}
|
BIN
Chapter01/sample
BIN
Chapter01/sample
Plik binarny nie jest wyświetlany.
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "sequences"
|
||||
version = "0.1.0"
|
||||
authors = ["Claus Matzinger <claus.matzinger+kb@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,89 @@
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::mem;
|
||||
|
||||
#[test]
|
||||
fn exploring_vec() {
|
||||
// a Vec<T> is almost always initialized using a macro
|
||||
assert_eq!(vec![0; 3], [0, 0, 0]);
|
||||
let mut v: Vec<i32> = vec![];
|
||||
|
||||
// a Vec<T> is defined by a triple (pointer, capacity, length)
|
||||
assert_eq!(mem::size_of::<Vec<i32>>(), mem::size_of::<usize>() * 3);
|
||||
|
||||
// empty vectors point to no memory (yet)
|
||||
assert_eq!(mem::size_of_val(&*v), 0);
|
||||
|
||||
v.push(10);
|
||||
|
||||
// a vector will also over-allocate on insert
|
||||
// *by how much is an implementation detail and may change!*
|
||||
assert_eq!(mem::size_of::<Vec<i32>>(), mem::size_of::<i32>() * 6);
|
||||
|
||||
// vectors support indexing
|
||||
assert_eq!(v[0], 10);
|
||||
|
||||
// vectors have some convenience methods
|
||||
v.insert(0, 11);
|
||||
v.push(12);
|
||||
assert_eq!(v, [11, 10, 12]);
|
||||
assert!(!v.is_empty());
|
||||
|
||||
// ... like one to create a heap in only a few lines
|
||||
assert_eq!(v.swap_remove(0), 11);
|
||||
assert_eq!(v, [12, 10]);
|
||||
|
||||
// ... or a stack
|
||||
assert_eq!(v.pop(), Some(10));
|
||||
assert_eq!(v, [12]);
|
||||
|
||||
// vectors also support regular removals
|
||||
assert_eq!(v.remove(0), 12);
|
||||
|
||||
// and can go back to occupying no memory..
|
||||
v.shrink_to_fit();
|
||||
assert_eq!(mem::size_of_val(&*v), 0);
|
||||
}
|
||||
|
||||
struct Point(f32, f32);
|
||||
|
||||
#[test]
|
||||
fn exploring_tuples() {
|
||||
let mut my_tuple: (i32, usize, f32) = (10, 0, -3.42);
|
||||
|
||||
// members can be accessed like that
|
||||
assert_eq!(my_tuple.0, 10);
|
||||
assert_eq!(my_tuple.1, 0);
|
||||
assert_eq!(my_tuple.2, -3.42);
|
||||
|
||||
my_tuple.0 = 100;
|
||||
assert_eq!(my_tuple.0, 100);
|
||||
|
||||
|
||||
|
||||
// tuples can be unpacked
|
||||
let (_val1, _val2, _val3) = my_tuple;
|
||||
|
||||
// structs can be based on tuples too
|
||||
let point = Point(1.2, 2.1);
|
||||
assert_eq!(point.0, 1.2);
|
||||
assert_eq!(point.1, 2.1);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn exploring_arrays() {
|
||||
// arrays use a familiar signature
|
||||
// (type declarations are not necessary)
|
||||
let mut arr: [usize; 3] = [0; 3];
|
||||
assert_eq!(arr, [0, 0, 0]);
|
||||
|
||||
let arr2: [usize; 5] = [1,2,3,4,5];
|
||||
assert_eq!(arr2, [1,2,3,4,5]);
|
||||
|
||||
arr[0] = 1;
|
||||
assert_eq!(arr, [1, 0, 0]);
|
||||
assert_eq!(arr[0], 1);
|
||||
assert_eq!(mem::size_of_val(&arr), mem::size_of::<usize>() * 3);
|
||||
}
|
||||
}
|
BIN
Chapter01/string
BIN
Chapter01/string
Plik binarny nie jest wyświetlany.
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "testing"
|
||||
version = "0.1.0"
|
||||
authors = ["Claus Matzinger <claus.matzinger+kb@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,272 @@
|
|||
//!
|
||||
//! A simple singly-linked list for the Rust-Cookbook by Packt Publishing.
|
||||
//!
|
||||
//! Recipes covered in this module:
|
||||
//! - Documenting your code
|
||||
//! - Testing your documentation
|
||||
//! - Writing tests and benchmarks
|
||||
//!
|
||||
|
||||
|
||||
#![feature(test)]
|
||||
#![doc(html_logo_url = "https://blog.x5ff.xyz/img/main/logo.png",
|
||||
test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
type Link<T> = Option<Rc<RefCell<Node<T>>>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Node<T> where T: Sized + Clone {
|
||||
value: T,
|
||||
next: Link<T>,
|
||||
}
|
||||
|
||||
|
||||
impl<T> Node<T> where T: Sized + Clone {
|
||||
fn new(value: T) -> Rc<RefCell<Node<T>>> {
|
||||
Rc::new(RefCell::new(Node {
|
||||
value: value,
|
||||
next: None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// A singly-linked list, with nodes allocated on the heap using `Rc`s and `RefCell`s. Here's an image illustrating a linked list:
|
||||
///
|
||||
///
|
||||
/// 
|
||||
///
|
||||
/// *Found on https://en.wikipedia.org/wiki/Linked_list*
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```ignore
|
||||
/// let list = List::new_empty();
|
||||
/// ```
|
||||
///
|
||||
#[derive(Clone)]
|
||||
pub struct List<T> where T: Sized + Clone {
|
||||
head: Link<T>,
|
||||
tail: Link<T>,
|
||||
|
||||
///
|
||||
/// The length of the list.
|
||||
///
|
||||
pub length: usize,
|
||||
}
|
||||
|
||||
impl<T> List<T> where T: Sized + Clone {
|
||||
|
||||
///
|
||||
/// Creates a new empty list.
|
||||
///
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use testing::List;
|
||||
/// let list: List<i32> = List::new_empty();
|
||||
/// ```
|
||||
///
|
||||
pub fn new_empty() -> List<T> {
|
||||
List { head: None, tail: None, length: 0 }
|
||||
}
|
||||
|
||||
///
|
||||
/// Appends a node to the list at the end.
|
||||
///
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This never panics (probably).
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// No unsafe code was used.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use testing::List;
|
||||
///
|
||||
/// let mut list = List::new_empty();
|
||||
/// list.append(10);
|
||||
/// ```
|
||||
///
|
||||
pub fn append(&mut self, value: T) {
|
||||
let new = Node::new(value);
|
||||
match self.tail.take() {
|
||||
Some(old) => old.borrow_mut().next = Some(new.clone()),
|
||||
None => self.head = Some(new.clone())
|
||||
};
|
||||
self.length += 1;
|
||||
self.tail = Some(new);
|
||||
}
|
||||
|
||||
///
|
||||
/// Removes the list's head and returns the result.
|
||||
///
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Whenever when a node unexpectedly is `None`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use testing::List;
|
||||
///
|
||||
/// let mut list = List::new_empty();
|
||||
/// list.append(10);
|
||||
/// assert_eq!(list.pop(), Some(10));
|
||||
/// ```
|
||||
///
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
self.head.take().map(|head| {
|
||||
if let Some(next) = head.borrow_mut().next.take() {
|
||||
self.head = Some(next);
|
||||
} else {
|
||||
self.tail.take();
|
||||
}
|
||||
self.length -= 1;
|
||||
Rc::try_unwrap(head)
|
||||
.ok()
|
||||
.expect("Something is terribly wrong")
|
||||
.into_inner()
|
||||
.value
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Splits off and returns `n` nodes as a `List<T>`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// `n: usize` - The number of elements after which to split the list.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics when:
|
||||
/// - The list is empty
|
||||
/// - `n` is larger than the length
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use testing::List;
|
||||
///
|
||||
/// let mut list = List::new_empty();
|
||||
/// list.append(12);
|
||||
/// list.append(11);
|
||||
/// list.append(10);
|
||||
/// let mut list2 = list.split(1);
|
||||
/// assert_eq!(list2.pop(), Some(12));
|
||||
/// assert_eq!(list.pop(), Some(11));
|
||||
/// assert_eq!(list.pop(), Some(10));
|
||||
/// ```
|
||||
///
|
||||
pub fn split(&mut self, n: usize) -> List<T> {
|
||||
|
||||
// Don't do this in real life. Use Results, Options, or anything that
|
||||
// doesn't just kill the program
|
||||
if self.length == 0 || n >= self.length - 1 {
|
||||
panic!("That's not working");
|
||||
}
|
||||
|
||||
let mut n = n;
|
||||
let mut new_list = List::new_empty();
|
||||
while n > 0 {
|
||||
new_list.append(self.pop().unwrap());
|
||||
n -= 1;
|
||||
}
|
||||
new_list
|
||||
}
|
||||
}
|
||||
|
||||
impl <T>Drop for List<T> where T: Clone + Sized {
|
||||
|
||||
fn drop(&mut self) {
|
||||
while self.length > 0 {
|
||||
let n = self.pop();
|
||||
drop(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
extern crate test;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_list_append(b: &mut Bencher) {
|
||||
let mut list = List::new_empty();
|
||||
b.iter(|| {
|
||||
list.append(10);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_new_empty() {
|
||||
let mut list: List<i32> = List::new_empty();
|
||||
assert_eq!(list.length, 0);
|
||||
assert_eq!(list.pop(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_append() {
|
||||
let mut list = List::new_empty();
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
assert_eq!(list.length, 5);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_list_pop() {
|
||||
let mut list = List::new_empty();
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
assert_eq!(list.length, 5);
|
||||
assert_eq!(list.pop(), Some(1));
|
||||
assert_eq!(list.pop(), Some(1));
|
||||
assert_eq!(list.pop(), Some(1));
|
||||
assert_eq!(list.pop(), Some(1));
|
||||
assert_eq!(list.pop(), Some(1));
|
||||
assert_eq!(list.length, 0);
|
||||
assert_eq!(list.pop(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_split() {
|
||||
let mut list = List::new_empty();
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
list.append(1);
|
||||
assert_eq!(list.length, 5);
|
||||
let list2 = list.split(3);
|
||||
assert_eq!(list.length, 2);
|
||||
assert_eq!(list2.length, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_list_split_panics() {
|
||||
let mut list: List<i32> = List::new_empty();
|
||||
let _ = list.split(3);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
use testing::List;
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_list_insert_10k_items() {
|
||||
let mut list = List::new_empty();
|
||||
for _ in 0..10_000 {
|
||||
list.append(100);
|
||||
}
|
||||
assert_eq!(list.length, 10_000);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "traits"
|
||||
version = "0.1.0"
|
||||
authors = ["Claus Matzinger <claus.matzinger+kb@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,140 @@
|
|||
use std::io::{Write, Read};
|
||||
// Structs
|
||||
|
||||
///
|
||||
/// Configuration for our application
|
||||
///
|
||||
pub struct Config {
|
||||
values: Vec<(String, String)>
|
||||
}
|
||||
|
||||
///
|
||||
/// A service for managing a configuration
|
||||
///
|
||||
pub struct KeyValueConfigService {
|
||||
|
||||
}
|
||||
|
||||
// Traits
|
||||
|
||||
///
|
||||
/// Provides a get() function to return valuse associated with
|
||||
/// the specified key.
|
||||
///
|
||||
pub trait ValueGetter {
|
||||
fn get(&self, s: &str) -> Option<String>;
|
||||
}
|
||||
|
||||
///
|
||||
/// Write a config
|
||||
///
|
||||
pub trait ConfigWriter {
|
||||
fn write(&self, config: Config, to: &mut impl Write) -> std::io::Result<()>;
|
||||
}
|
||||
|
||||
///
|
||||
/// Read a config
|
||||
///
|
||||
pub trait ConfigReader {
|
||||
fn read(&self, from: &mut impl Read) -> std::io::Result<Config>;
|
||||
}
|
||||
|
||||
// Impls
|
||||
|
||||
impl Config {
|
||||
pub fn new(values: Vec<(String, String)>) -> Config {
|
||||
Config {
|
||||
values: values
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyValueConfigService {
|
||||
pub fn new() -> KeyValueConfigService {
|
||||
KeyValueConfigService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigWriter for KeyValueConfigService {
|
||||
fn write(&self, config: Config, mut to: &mut impl Write) -> std::io::Result<()> {
|
||||
for v in config.values {
|
||||
writeln!(&mut to, "{0}={1}", v.0, v.1)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigReader for KeyValueConfigService {
|
||||
fn read(&self, from: &mut impl Read) -> std::io::Result<Config> {
|
||||
let mut buffer = String::new();
|
||||
from.read_to_string(&mut buffer)?;
|
||||
|
||||
// chain iterators together and collect the results
|
||||
let values: Vec<(String, String)> = buffer
|
||||
.split_terminator("\n") // split
|
||||
.map(|line| line.trim()) // remove whitespace
|
||||
.filter(|line| { // filter invalid lines
|
||||
let pos = line.find("=")
|
||||
.unwrap_or(0);
|
||||
pos > 0 && pos < line.len() - 1
|
||||
})
|
||||
.map(|line| { // create a tuple from a line
|
||||
let parts = line.split("=").collect::<Vec<&str>>();
|
||||
(parts[0].to_string(), parts[1].to_string())
|
||||
})
|
||||
.collect(); // transform it into a vector
|
||||
Ok(Config::new(values))
|
||||
}
|
||||
}
|
||||
|
||||
impl ValueGetter for Config {
|
||||
fn get(&self, s: &str) -> Option<String> {
|
||||
self.values.iter()
|
||||
.find_map(|tuple| if &tuple.0 == s {
|
||||
Some(tuple.1.clone())
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[test]
|
||||
fn config_get_value() {
|
||||
let config = Config::new(vec![("hello".to_string(), "world".to_string())]);
|
||||
assert_eq!(config.get("hello"), Some("world".to_string()));
|
||||
assert_eq!(config.get("HELLO"), None);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn keyvalueconfigservice_write_config() {
|
||||
let config = Config::new(vec![("hello".to_string(), "world".to_string())]);
|
||||
|
||||
let service = KeyValueConfigService::new();
|
||||
let mut target = vec![];
|
||||
assert!(service.write(config, &mut target).is_ok());
|
||||
|
||||
assert_eq!(String::from_utf8(target).unwrap(), "hello=world\n".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keyvalueconfigservice_read_config() {
|
||||
|
||||
let service = KeyValueConfigService::new();
|
||||
let readable = &format!("{}\n{}", "hello=world", "a=b").into_bytes();
|
||||
|
||||
let config = service.read(&mut Cursor::new(readable))
|
||||
.expect("Couldn't read from the vector");
|
||||
|
||||
assert_eq!(config.values, vec![
|
||||
("hello".to_string(), "world".to_string()),
|
||||
("a".to_string(), "b".to_string())]);
|
||||
}
|
||||
}
|
BIN
Chapter01/tuples
BIN
Chapter01/tuples
Plik binarny nie jest wyświetlany.
Ładowanie…
Reference in New Issue