diff --git a/README.md b/README.md index 67c3a49..598d47a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,66 @@ # Learning -Rust Concepts: https://sociocyber.site/rust_concepts_v2.html -Exploration a Rust Programming Language - (33 concepts) -And ETC. \ No newline at end of file +Rust Concepts: [https://sociocyber.site/rust_concepts_v2.html](https://sociocyber.site/rust_concepts_v2.html) +Exploration a Rust Programming Language - (33 concepts) + +## Memory + +--- + +1. [Ownership](./Rust_Concepts/src/ownership.rs) +2. [Borrowing ](./Rust_Concepts/src/borrowing.rs)(shared &) +3. [Mutable Borrow](./Rust_Concepts/src/mutable_borrow.rs) (&mut) +4. [Clone](./Rust_Concepts/src/clone.rs) +5. [Stack vs Heap](./Rust_Concepts/src/stack_vs_heap.rs) + +## TYPES + +--- + +// Todo + +## CONTROL + +--- + +// Todo + +## TRAITS + +--- + +// Todo + +## ERROR + +--- + +// Todo + +## LIFETIME + +--- + +## ITER + +--- + +// Todo + +## CLOSURES + +--- + +// Todo + +## CONCUR + +--- + +// Todo + +## MODULES + +--- + +// Todo \ No newline at end of file diff --git a/Rust_Concepts/Cargo.toml b/Rust_Concepts/Cargo.toml index 8a4da07..3e6ad26 100644 --- a/Rust_Concepts/Cargo.toml +++ b/Rust_Concepts/Cargo.toml @@ -5,6 +5,11 @@ edition = "2024" [dependencies] + + +# To run examples use +# cargo run --bin [Something] + [[bin]] name = "Ownership" # the name you’ll use with --bin path = "src/ownership.rs" # path to the source file @@ -19,4 +24,14 @@ path = "src/borrowing.rs" # path to the source file [[bin]] name = "MutBorrowing" # the name you’ll use with --bin path = "src/mutable_borrow.rs" # path to the source file -# cargo run --bin MutBorrowing \ No newline at end of file +# cargo run --bin MutBorrowing + +[[bin]] +name = "Clone" # the name you’ll use with --bin +path = "src/clone.rs" # path to the source file +# cargo run --bin Clone + +[[bin]] +name = "StackVSHeap" # the name you’ll use with --bin +path = "src/stack_vs_heap.rs" # path to the source file +# cargo run --bin StackVSHeap \ No newline at end of file diff --git a/Rust_Concepts/src/Notes.txt b/Rust_Concepts/src/Notes.txt new file mode 100644 index 0000000..bc6c28b --- /dev/null +++ b/Rust_Concepts/src/Notes.txt @@ -0,0 +1,21 @@ +### lifetimes 'a +lifetime = how long a reference is valid +scope = { } defines the time period +'a = name you give to a lifetime +&'a str = reference tagged with that lifetime + +compiler uses 'a and somename for lifetime to check: +"is output used after input died?" + +you write 'a only when compiler asks +most code — compiler infers alone + + +You can add any name with apostrophe: +'a +'b +'c +'x +'input +'output +'banana <-- Any name! you write 'Anyname only when compiler asks \ No newline at end of file diff --git a/Rust_Concepts/src/clone.rs b/Rust_Concepts/src/clone.rs new file mode 100644 index 0000000..b6f8f12 --- /dev/null +++ b/Rust_Concepts/src/clone.rs @@ -0,0 +1,97 @@ +/* Rust Concepts: https://sociocyber.site/rust_concepts_v2.html + Concept: Clone + Usage: clone from variable a value into new variable , not borrowing, not shadowing. + let variable2 = variable1.clone() + + (heap-space1) (heap-space2) + (data1) -> (data1) +*/ + +fn main() { + let owner1 = String::from("I am saved only in one heap-space1, not others. Value in heap-space1 Not coped into heap-space2."); // owner + let owner2 = owner1; // Move ownership (pointer only) from owner1 to owner2. Then owner1 not accsessable. Can't be used. + //println!("owner1 {}", owner1); // NOT ACCESS, not-valid compiler mark this variable as not accsessable. Pointer (--> heap --> ['v' 'a' 'l' 'u' 'e']) moved in new owner2 + // compiler: value borrowed here after move + println!("Owner2: {}", owner2); + /* + ╔════════════════════════════════════════════════════════════════════════════╗ + ║ MOVE ownership (Default Behavior) let owner2 = owner1; ║ + ╚════════════════════════════════════════════════════════════════════════════╝ + + * owner1 ptr (pointer) moved into (owner2) + + STACK HEAP + ┌─────────────────────┐ ┌──────────────────────────────────┐ + │ owner1: String │ │ "I am saved only in one..." │ + │ ┌─────────────────┐ │ │ [Offset: 0] │ + │ │ ptr ────────────┼─┼──────────► │ [Length: 97 bytes] │ + │ │ len: 97 │ │ │ [Capacity: 97] │ + │ │ cap: 97 │ │ └──────────────────────────────────┘ + │ └─────────────────┘ │ + └─────────────────────┘ + │ + │ let owner2 = owner1; (MOVE: transfer ownership) + │ + ▼ + ┌─────────────────────┐ ┌──────────────────────────────────┐ + │ owner1: ❌ INVALID │ │ "I am saved only in one..." │ + │ (moved out) │ │ [Same address1 in memory] │ + └─────────────────────┘ └──────────────────────────────────┘ + + ┌─────────────────────┐ + │ owner2: String │ + │ ┌─────────────────┐ │ (address1) + │ │ ptr ────────────┼─┼──────────► (points to SAME address1 heap allocation) + │ │ len: 97 │ │ + │ │ cap: 97 │ │ + │ └─────────────────┘ │ + └─────────────────────┘ + (VALID: still accessible) + */ + + // But with "Clone" we can not just move ownership, we can copy value from heap, to new memory area (new heap address space) + let owner_1 = String::from("I am saved in 2 heap-spaces. (I am a copy from heap-space1, if you see me in heap-space2)"); // ACCESSABLE! Valid, Not shaddowed. Compiler not mark this. Ownership not moved. + let owner_2 = owner_1.clone(); // Clone heap-space1 to new heap-space2 (copy a value, not borrowing, NOT mark owner_1 to not accsessable) + println!("heap-space1: {}", owner_1); // valid + println!("heap-space2: {}", owner_2); // valid + + /* + ╔════════════════════════════════════════════════════════════════════════════╗ + ║ CLONE (Deep Copy) .clone() ║ + ╚════════════════════════════════════════════════════════════════════════════╝ + + STACK HEAP (Heap-space1) Pointers point to 0x1000 and 0x2000 + ┌─────────────────────┐ ┌──────────────────────────────────┐ + │ owner_1: String │ │ "I am saved in 2 heap-spaces..." │ + │ ┌─────────────────┐ │ │ [Address: 0x1000] │ + │ │ ptr ────────────┼─┼──────────► │ [Length: 99 bytes] │ + │ │ len: 99 │ │ │ [Capacity: 99] │ + │ │ cap: 99 │ │ └──────────────────────────────────┘ + │ └─────────────────┘ │ + └─────────────────────┘ + │ + │ let owner_2 = owner_1.clone(); (CLONE: deep copy heap data) + │ + ▼ [After] Heap-space1 Pointers point to 0x1000 and 0x2000 + ┌─────────────────────┐ ┌──────────────────────────────────┐ + │ owner_1: String ✓ │ │ "I am saved in 2 heap-spaces..." │ + │ ┌─────────────────┐ │ │ [Address: 0x1000] ◄── ORIGINAL │ + │ │ ptr ────────────┼─┼──────────► │ [Length: 99 bytes] │ + │ │ len: 99 │ │ │ [Capacity: 99] │ + │ │ cap: 99 │ │ └──────────────────────────────────┘ + │ └─────────────────┘ │ + └─────────────────────┘ + (VALID: still accessible) + Heap-space2 Pointers point to 0x2000 and 0x3000 + ┌─────────────────────┐ ┌──────────────────────────────────┐ + │ owner_2: String ✓ │ │ "I am saved in 2 heap-spaces..." │ + │ ┌─────────────────┐ │ │ [Address: 0x2000] ◄── COPY │ + │ │ ptr ────────────┼─┼──────────► │ [Length: 99 bytes] │ + │ │ len: 99 │ │ │ [Capacity: 99] │ + │ │ cap: 99 │ │ └──────────────────────────────────┘ + │ └─────────────────┘ │ + └─────────────────────┘ + (VALID: still accessible) + */ + +} \ No newline at end of file diff --git a/Rust_Concepts/src/main.rs b/Rust_Concepts/src/main.rs index 2a778e4..d66f458 100644 --- a/Rust_Concepts/src/main.rs +++ b/Rust_Concepts/src/main.rs @@ -1,3 +1,5 @@ fn main() { - + // to run examples use + // cargo run --bin [Something] + // check a Cargo.toml file } diff --git a/Rust_Concepts/src/stack_vs_heap.rs b/Rust_Concepts/src/stack_vs_heap.rs new file mode 100644 index 0000000..338a4f2 --- /dev/null +++ b/Rust_Concepts/src/stack_vs_heap.rs @@ -0,0 +1,168 @@ +/* Rust Concepts: https://sociocyber.site/rust_concepts_v2.html + Concept: Stack vs Heap + Usage: Save data in Stack (CPU's registers, L1, L2, L3,. caches) or in Heap (MEMory) + + * Box() make a pointer to data in HEAP + * Primitive Types saved in STACK + + Stack = fast, fixed-size, automatic cleanup. + Heap = flexible, dynamic size, manually managed (but Rust does it for you). + + (Analogy) + Stack = your desk (fast, limited). + Heap = a warehouse (vast, slower to retrieve). + + P.S. '_' in '_variable' means = hide compiler warnings: unused variable + + +*/ + +fn main() { + + /* + ┌─────────────────────────────────────┬─────────────────────────────────────┐ + │ STACK │ HEAP │ + ├─────────────────────────────────────┼─────────────────────────────────────┤ + │ │ │ + │ number: i32 │ │ + │ ┌──────────────┐ │ │ + │ │ 40 │ │ │ + │ └──────────────┘ │ │ + │ │ │ + │ │ │ + └─────────────────────────────────────┴─────────────────────────────────────┘ + */ + // primitive type + let _number: i32 = 40; // saved in stack + + /* + ┌─────────────────────────────────────┬─────────────────────────────────────┐ + │ STACK │ HEAP │ + ├─────────────────────────────────────┼─────────────────────────────────────┤ + │ ... │ ... │ + │ │ │ + │ string: String │ │ + │ ┌──────────────────────────────┐ │ 0x1000: │ + │ │ ptr: 0x1000 │ │ ┌──────────────────────────────────┤ + │ │ len: 19 │───┼─►│ "This data in a heap" │ + │ │ cap: 19 │ │ │ 19 bytes │ + │ └──────────────────────────────┘ │ └──────────────────────────────────┤ + │ │ │ + │ │ │ + └─────────────────────────────────────┴─────────────────────────────────────┘ + */ + // non-primitive types saved in heap, like as structs and etc (about it in later lessons) + let _string: String = String::from("This data in a heap"); + + + /* + ┌─────────────────────────────────────┬─────────────────────────────────────┐ + │ STACK │ HEAP │ + ├─────────────────────────────────────┼─────────────────────────────────────┤ + │ ... │ ... │ + │ │ │ + │ │ │ + │ number_in_heap: Box │ │ + │ ┌──────────────────────────────┐ │ 0x2000: │ + │ │ ptr: 0x2000 │ │ ┌──────────────────────────────────┤ + │ └──────────────────────────────────┼─►│ 78 │ + │ │ │ 4 bytes │ + │ │ └──────────────────────────────────┤ + │ │ │ + └─────────────────────────────────────┴─────────────────────────────────────┘ + */ + // What if i want save big array of numbers in heap (may we read a big files, get big data from server like files, images, video streams,.) + // let _numbers_array: [i32; 12] = [1,23,3,56,57,6,868,34,3,5,246,23]; + // Use Box::new(variable) + // For specific cases use Box::::new(variable) + let number_in_heap = Box::new(78); // i32, saved in heap + println!("number_in_heap = {}", number_in_heap); // easy to accsess. + + + /* + ┌─────────────────────────────────────┬─────────────────────────────────────┐ + │ STACK │ HEAP │ + ├─────────────────────────────────────┼─────────────────────────────────────┤ + │ ... │ ... │ + │ │ │ + │ │ │ + │ numbers_array_in_heap: │ │ + │ Box<[i32; 10]> │ │ + │ ┌──────────────────────────────┐ │ 0x3000: │ + │ │ ptr: 0x3000 │ │ ┌──────────────────────────────────┤ + │ └──────────────────────────────────┼─►│ [1][2][3][4][5][6][7][8][9][10] │ + │ │ │ 40 bytes │ + │ │ └──────────────────────────────────┤ + │ │ │ + └─────────────────────────────────────┴─────────────────────────────────────┘ + i32 = 4 bytes + 4 bytes * 10 elements = 40 bytes -> size of array, + size of heap-space 40 bytes => 40bytes * 8bit = 320 bits (1's and 0's) + */ + // not worry about this. In Later lessons we'll explore "arrays" + let numbers_array_in_heap = Box::<[i32; 10]>::new([1,2,3,4,5,6,7,8,9,10]); // saved in heap, Box means create a POINTER to heap-data, + // save ONLY A POINTER in stack, Data save in HEAP. + // Print all elements of array + // Need iter() - iterator, not worry about this. In Later lessons we'll explore "loops" + for number in numbers_array_in_heap.iter() { + println!("number in heap from array: {}", number); + } + + + + /* + Full map + ┌─────────────────────────────────────────────────────────────────────────────┐ + │ MEMORY BREAKDOWN │ + ├─────────────────────┬──────────────────┬──────────────────┬─────────────────┤ + │ Variable │ Stack Size │ Heap Address │ Heap Size │ + ├─────────────────────┼──────────────────┼──────────────────┼─────────────────┤ + │ number │ 4 bytes │ (none) │ 0 bytes │ + │ string │ 24 bytes │ 0x1000 │ 19 bytes │ + │ number_in_heap │ 8 bytes │ 0x2000 │ 4 bytes │ + │ numbers_array... │ 8 bytes │ 0x3000 │ 40 bytes │ + ├─────────────────────┼──────────────────┼──────────────────┼─────────────────┤ + │ TOTAL │ 44 bytes │ │ 63 bytes │ + └─────────────────────┴──────────────────┴──────────────────┴─────────────────┘ + + Box() make pointer to data in HEAP + Primitive Types saved in STACK + ┌─────────────────────────────────────┬─────────────────────────────────────┐ + │ STACK │ HEAP │ + ├─────────────────────────────────────┼─────────────────────────────────────┤ + │ │ │ + │ number: i32 │ │ + │ ┌──────────────┐ │ │ + │ │ 40 │ │ │ + │ └──────────────┘ │ │ + │ │ │ + │ │ │ + │ string: String │ │ + │ ┌──────────────────────────────┐ │ 0x1000: │ + │ │ ptr: 0x1000 │ │ ┌──────────────────────────────────┤ + │ │ len: 19 │───┼─►│ "This data in a heap" │ + │ │ cap: 19 │ │ │ 19 bytes │ + │ └──────────────────────────────┘ │ └──────────────────────────────────┤ + │ │ │ + │ │ │ + │ number_in_heap: Box │ │ + │ ┌──────────────────────────────┐ │ 0x2000: │ + │ │ ptr: 0x2000 │ │ ┌──────────────────────────────────┤ + │ └──────────────────────────────────┼─►│ 78 │ + │ │ │ 4 bytes │ + │ │ └──────────────────────────────────┤ + │ │ │ + │ │ │ + │ numbers_array_in_heap: │ │ + │ Box<[i32; 10]> │ │ + │ ┌──────────────────────────────┐ │ 0x3000: │ + │ │ ptr: 0x3000 │ │ ┌──────────────────────────────────┤ + │ └──────────────────────────────────┼─►│ [1][2][3][4][5][6][7][8][9][10] │ + │ │ │ 40 bytes │ + │ │ └──────────────────────────────────┤ + │ │ │ + └─────────────────────────────────────┴─────────────────────────────────────┘ + + + */ +} // all freed automatically (stack, heap data drops) \ No newline at end of file