Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
main.exe
main.pdb

# Added by cargo
## Added by cargo ##

/target
4 changes: 2 additions & 2 deletions 10_loops/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ fn main(){

// Loop keyword
fn loop_fn(){
let mut counter = 8;
let mut counter = 7;

let result = loop{
let result = loop{2

counter += 1;

Expand Down
137 changes: 137 additions & 0 deletions 15_mini_project/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// A Rust mini-project demonstrating all core concepts from this crash course!
// We will write a Bookstore Inventory CLI as our mini project.
// This makes use of variables, constants, structs, enums, ownership, borrowing, functions, conditionals, loops, vectors, hashmaps, error handling, and more.

use std::collections::HashMap;
//std::collections::HashMap is a module that provides a hashmap data structure
use std::io;
//std::io is a module that provides input and output operations

// Constants
const MAX_STOCK: u32 = 100; // 100 books in the inventory

// Enum (for Book genre)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Genre {
Fiction,
NonFiction,
Science,
Fantasy,
}

// Struct (for Book)
#[derive(Debug)]
struct Book {
title: String,
author: String,
genre: Genre,
pages: u32,
}

// Ownership, Borrowing, Compound Types, Collections
struct Inventory {
stock: HashMap<Genre, Vec<Book>>,
}

impl Inventory {
fn new() -> Self {
Inventory {
stock: HashMap::new(),
}
}

fn add_book(&mut self, book: Book) -> Result<(), String> {
let entry = self.stock.entry(book.genre).or_insert(Vec::new());
if entry.len() >= MAX_STOCK as usize {
return Err(format!("Cannot add more books to genre {:?} (stock limit reached)", book.genre));
}
entry.push(book);
Ok(())
}

fn list_books(&self, genre: Option<Genre>) {
println!("--- INVENTORY ---");
for (g, books) in &self.stock {
if let Some(target) = genre {
if *g != target { continue; }
}
println!("\nGenre: {:?}", g);
for (i, b) in books.iter().enumerate() {
println!("{}. '{}' by {}, {} pages", i+1, b.title, b.author, b.pages);
}
}
}
}

fn parse_genre(input: &str) -> Option<Genre> {
match input.trim().to_lowercase().as_str() {
"fiction" => Some(Genre::Fiction),
"nonfiction" => Some(Genre::NonFiction),
"science" => Some(Genre::Science),
"fantasy" => Some(Genre::Fantasy),
_ => None,
}
}

fn main() {
let mut inventory = Inventory::new();
println!("Welcome to the Rust Bookstore Inventory CLI!");

loop {
// Demonstrate shadowing
let mut action = String::new();
println!("\nChoose action: [add/list/quit]: ");
io::stdin().read_line(&mut action).expect("Failed to read");
let action = action.trim(); // shadowing action

if action == "quit" {
println!("Goodbye!");
break;
} else if action == "add" {
// Adding a book (Ownership, references/borrowing for input)
let mut title = String::new();
let mut author = String::new();
let mut genre_str = String::new();
let mut pages_str = String::new();

println!("Title: "); io::stdin().read_line(&mut title).unwrap();
println!("Author: "); io::stdin().read_line(&mut author).unwrap();
println!("Genre (fiction/nonfiction/science/fantasy): "); io::stdin().read_line(&mut genre_str).unwrap();
println!("Pages: "); io::stdin().read_line(&mut pages_str).unwrap();

let genre = match parse_genre(&genre_str) {
Some(g) => g,
None => {
println!("Invalid genre!");
continue;
}
};
let pages: u32 = match pages_str.trim().parse() {
Ok(v) => v,
Err(_) => {
println!("Pages must be a number!");
continue;
}
};
let book = Book {
title: title.trim().to_string(),
author: author.trim().to_string(),
genre,
pages,
};
// Error handling with Result
match inventory.add_book(book) {
Ok(_) => println!("Book added to inventory!"),
Err(e) => println!("Error: {}", e),
}
} else if action == "list" {
let mut filter = String::new();
println!("Filter by genre (press Enter to show all): ");
io::stdin().read_line(&mut filter).unwrap();
let genre = parse_genre(&filter);
inventory.list_books(genre);
} else {
println!("Invalid action! Try again.");
}
}
}
21 changes: 14 additions & 7 deletions 1_primitive_data_types/main.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
// Primitive data types
// int, float, bool, char
// Primitive data types are the basic building blocks of the language
// integers, floats, booleans, characters:

// Integers are used to store whole numbers
// Floats are used to store decimal numbers
// Booleans are used to store true or false values
// Characters are used to store single characters

fn main() {
println!("Hello, world!");

// Integer
// Rust has signed (+ & -) and unsigned integer (only '+') types of different sizes
// Integers
// Rust has signed (+ & -) and unsigned integers (only '+') types of different sizes
// i8, i16, i32, i64, i128: Signed integers
// u8, i16, u32, u64, u128: Unsigned integers

// u8, u16, u32, u64, u128: Unsigned integers
let x = -42;
let y: u8 = 100;
let z = -123_i16;
println!("Signed Integer: {}", x);
println!("Unsigned Integer: {}", y);

println!("Signed Integer: {}", z);

// Floats [floating point types]
// f32, f64
let pi: f64 = 3.14;
Expand Down
20 changes: 19 additions & 1 deletion 2_compound_data_types/main.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
// Compound Data Types

// Arrays, tuples, slices and strings (slice string)
// Arrays are fixed size, ordered, and homogeneous (all elements must be of the same type)
// Tuples are fixed size, ordered, and heterogeneous (elements can be of different types)
// Slices are views into a contiguous sequence of elements
// Strings are growable and mutable

// Which ones are stored on the stack and which ones are stored on the heap?
// Arrays are stored on the stack
// Tuples are stored on the stack
// Slices are stored on the stack
// Strings are stored on the heap

fn main() {
// Arrays
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
println!("Array of numbers: {:?}", numbers);

// &str is a string slice
// it's a pointer to a string in the heap
let fruits: [&str; 2] = ["Apple", "Orange"];
println!("Array of fruits: {:?}", fruits);
// {:?} is a placeholder for the array

// Tuples
let bio_data: (String, i32, bool) = ("Alice".to_string(), 30, false);
println!("Bio data Tuple: {:?}", bio_data);
// .to.string() is a method that converts a string literal to a string

let mixed_tuples = ("Joe", 23, true, [1, 2, 3, 4, 5]);
println!("Mixed Tuple: {:?} \n", mixed_tuples);
Expand All @@ -35,6 +48,11 @@ fn main() {
// immutable string
let name: String = String::from("John");
println!("Name is {}", name);
// String::from is a method that converts a string literal to a string
// what is the difference between to_string() and String::from()?
// to_string() is a method that converts a string literal to a string
// String::from() is a function that converts a string literal to a string
// String::from() is more efficient than to_string() because it does not allocate memory on the heap

// Mutable string
let mut full_name: String = String::from("Joe");
Expand Down
12 changes: 5 additions & 7 deletions 3_functions/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,11 @@ fn bmi_calculator(weight: f64, height: f64) -> f64 {

// Expressions and Statements
// Expression: Anything that returns a value.
/*
* let X = {
* let a = 50;
* let b = 10;
* b + a
* }
*/
let X = {
let a = 50;
let b = 10;
b + a
};
// Statement: Anything that does not return a value.
// let x = 10;
// Other examples includes function declaration themselves and conditional statements
32 changes: 18 additions & 14 deletions 4_ownership/main.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
// Ownership
// Solves the issue created by Garbage collections and manual memory handling
/*
Ownership
Solves the issue created by garbage collection and manual memory handling
OWNERSHIP introduced by Rust solves memory safety issues and high performance at the same time.
What is Ownership ?
Every value has a single owner [every variable has one value, and it is its sole owner].
*/

// Ownership
// [stopping/Resuming the program]
// OWNERSHIP introduced by Rust to solve memory safety issues and high performance at the same time.
// What is Ownership ?
// Every value has a single owner [every variable has one value, and it is its sole owner].

// Ownership Rules
// 1- Each value in Rust has a variable that's its owner.
// 2- There can be only one owner at a time.
// 3— When the owner goes out of scope, the value will be dropped.
/*
Ownership Rules
1- Each value has a variable that is its owner.
2- There can be only one owner at a time.
3— When the owner goes out of scope, the value will be dropped.
*/

fn main(){
// s1 is the owner of this string value
let s1: String = String::from("Hello");
// String::from is a function that creates a String from a string literal and a string literal is a fixed size
// String is a heap allocated data structure that is growable and mutable

// Borrow reference to s1
let len = calculate_str_length(&s1);
println!("Length of '{}' is {}", s1, len);

let s2 = s1;
println!("Value: {}", s2);
println!("Value: {}", s2);
println!("Value of s2: {}", s2);

/*
* There can only be one owner at a time
Expand All @@ -33,4 +35,6 @@ fn main(){

fn calculate_str_length(s: &String) -> usize {
s.len()
// s.len() is a method that returns the length of the string
// -> usize is the return type of the function
}
4 changes: 2 additions & 2 deletions 5_references_and_borrowing/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ struct BankAccount{
owner: String,
balance: f64
}

//impl is a keyword that implements the methods for the BankAccount struct
impl BankAccount{
fn withdraw(&mut self, amount: f64){
fn withdraw(&mut self, amount: f64){ // self is a reference to the BankAccount struct
println!("Withdrawing {} from account owned by {}", amount, self.owner);
self.balance -= amount;
}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ To run a lesson, just navigate into the directory and use the `make run` command

#### Example

If you want to run the `1_primivitive_data_types` lesson. Use the command below.
If you want to run the `1_primitive_data_types` lesson. Use the command below.

```bash
# We are currently inside the `rust-full-course` directory
Expand Down
Binary file added main
Binary file not shown.