From 229c240cd75f4d3336aa810210cb8bcfeb5eccd4 Mon Sep 17 00:00:00 2001 From: lukeify <5379845+lukeify@users.noreply.github.com> Date: Wed, 3 Jan 2024 15:51:55 +1300 Subject: [PATCH 1/4] chore: intial commit --- Memory Management.md | 29 +++++++++++ Rust.md | 119 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 Memory Management.md create mode 100644 Rust.md diff --git a/Memory Management.md b/Memory Management.md new file mode 100644 index 0000000..35cfe9e --- /dev/null +++ b/Memory Management.md @@ -0,0 +1,29 @@ +# Memory Management + +[Stack vs. Heap quick comparison](https://stackoverflow.com/questions/79923) + +## Stack + +* LIFO (Last in, first out) approach, with `push` and `pop` paradigm of addition and removal. +* All stored data has fixed sizes that are always known. +* Pushing to stack is faster than allocation to heap—no process is needed to locate where data could be placed. +* Popping from the stack is faster than accessing from the heap because no lookup process is needed. +* Integrated tightly into code. + When a function is called, values passed to the function, and local variables are pushed onto the stack. + When the function is complete, this data is popped off. + +## Heap + +Significantly less structured way of storing data. Anything with unknown or changeable size must be stored on the heap. + +High level approach to putting data on the heap: + +* Request an amount of space. +* Memory allocator will find an empty spot that's big enough for your request. + * Marked as being used. +* Pointer to address of memory is returned. + * (This pointer can then be stored in the stack). +* Data with unknown size at compile time, or that may change is stored on the heap. + +https://www.metservice.com/publicData/rainRadar/image/Otago/120K/2024-01-03T12:36:00+13:00 +https://www.metservice.com/publicData/rainRadar/image/Otago/120K/2024-01-03T13:07:00+13:00 diff --git a/Rust.md b/Rust.md new file mode 100644 index 0000000..3826d60 --- /dev/null +++ b/Rust.md @@ -0,0 +1,119 @@ +# Rust + +## Ownership + +[Ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html) involves managing accessing, cleaning up, and tracking data stored in the heap. +Rules of ownership: + +* Each value has an owner. +* Only one owner allowed simultaneously. +* Owner goes out of scope = value is dropped. + +```rust +{ + let s = String::from("hello."); // s is valid from this point forward +} +``` + +At the end of the scope, denoted by the braces, `s` is no longer valid and is deallocated from the heap, as Rust internally calls [`drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html#tymethod.drop). +This can also be seen with heap-allocated variables being duplicated (only one owner allowed). + +```rust +let s1 = String::from("hello."); +let s2 = s1; +``` + +In this scenario s1 and s2 both are values that contain a pointer to the _same address in memory_ for the heap-stored data. + +When `s2` is assigned, `s1` becomes invalid because if both were to go out of scope simultaneously, they will both be freed from memory simultaneously—despite pointing to only one location in memory. +This is known as a _double free error_ and rust prevents this. + +Thus, Rust nearly always _shallow copies_ data, also known in Rust terms as a "move". The underlying data on the heap is not touched, only the pointer and metadata to it. +To perform what would be called a _deep copy_ in Rust, the `clone` method exists: + +```rust +let s1 = String::from("hello"); +let s2 = s1.clone(); +``` + +Both `s1` and `s2` are valid at the end of this code example. + +## `Copy` trait + +## `String` vs `&str` + +`String` is a dynamic vector of bytes (`Vec`) and is heap-allocated, growable, and not null-terminated. +It can be owned, and is frankly the easiest to understand data type here. It can be defined at a high level as: + +```rust +pub struct String { + vec: Vec +} +``` + +When a "string literal" is declared, it + + + + + +[Summary comparison](https://stackoverflow.com/a/24159933) + + + +A string literal when declared are of type `str`: + + + + + + +To access a string literal, a slice is used. +A slice stores an address where the `str` starts, and how many bytes is being stored. +This is also called a "fat pointer". + + + +This is a "string slice" (`&[u8]`), and are immutable. +When declared like this, they are hardcoded into the final executable as they are known at compile-time. + + + +## Pointers + +Types: + +* "Reference" + +## `Box` + +`Box` data types are pointers that store data in the heap. + +## `dyn` keyword + +If instead of returning a known concrete object, a function returns a `trait`; then the size of the object cannot be known at compile-time; as even though each concrete implementation will adhere to the trait, the object size will differ. + +Thus, the return type is said to be "dynamic", and the `dyn` keyword is needed to prefix the trait name in the return type +([before Edition 2021 though, this keyword could be omitted](https://doc.rust-lang.org/reference/types/trait-object.html)). +Additionally, this will be wrapped in a `Box` to heap-allocate it. +Thus, the return type is actually a pointer reference to memory on the heap. + +```rust +fn get_random_traitable() -> Box { + // ... +} +``` + +[Rust by example](https://doc.rust-lang.org/rust-by-example/trait/dyn.html) reference. + +## `pub(crate)` for struct members + +## Attributes + +### `derive(Debug)` + +## "Dynamic dispatch" + +## Apostrophes (related to types) + +## Lifetimes From d9959560cc91f02c8bb3f6eba260eba5cb6b0877 Mon Sep 17 00:00:00 2001 From: lukeify <5379845+lukeify@users.noreply.github.com> Date: Wed, 3 Jan 2024 17:25:06 +1300 Subject: [PATCH 2/4] feat: complete "Strings" section --- Rust.md | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/Rust.md b/Rust.md index 3826d60..aac340b 100644 --- a/Rust.md +++ b/Rust.md @@ -40,10 +40,12 @@ Both `s1` and `s2` are valid at the end of this code example. ## `Copy` trait -## `String` vs `&str` +## Strings -`String` is a dynamic vector of bytes (`Vec`) and is heap-allocated, growable, and not null-terminated. -It can be owned, and is frankly the easiest to understand data type here. It can be defined at a high level as: +**`String`** is a dynamic vector of bytes (`Vec`) and is heap-allocated, growable, UTF-8 encoded, and not [null-terminated](https://en.wikipedia.org/wiki/Null-terminated_string). +It is an _owned type_ (as it owns the underlying bytes representing the string) and is frankly the easiest to understand data type here. +It consists of a pointer to the string on the heap, its length, and its capacity. +It can be [defined](https://doc.rust-lang.org/src/alloc/string.rs.html#365-367) at a high level as: ```rust pub struct String { @@ -51,33 +53,35 @@ pub struct String { } ``` -When a "string literal" is declared, it - - - - - -[Summary comparison](https://stackoverflow.com/a/24159933) - - - -A string literal when declared are of type `str`: - +(With an addition that the bytes of the `vec` are guaranteed to be valid UTF-8). +**`&str`** is a _string slice_, also known as a "view into a string". +It consists of a pointer to the string, and the string length, offering a view into a string. +It is called a _borrowed type_, because it doesn't own the underlying data, and are immutable (and is therefore not growable). +```rust +let my_string: String = String::from("Hello!":); +let my_string_slice: &str = &my_string; +``` +The pointer can point to _either_ data on the heap, data in the compiled binary (in the case of string literals), or on the stack. +The string slice is made up of two parts: -To access a string literal, a slice is used. -A slice stores an address where the `str` starts, and how many bytes is being stored. -This is also called a "fat pointer". +* The `str` type. This cannot be used directly because its size is not known at compile time. +* The reference operator (`&`). We use this to get a pointer to the bytes of the string and its length. +A **string literal** is a `&str` that is stored within the compiled binary itself: +```rust +let my_string_literal = "Hello, world!"; // Type is `&str`, which is syntactic sugar for `&'static str`. +``` -This is a "string slice" (`&[u8]`), and are immutable. When declared like this, they are hardcoded into the final executable as they are known at compile-time. +String literals have a "static lifetime", which is to say their lifetime persists for the duration of the program execution. - +* [Summary comparison from StackOverflow](https://stackoverflow.com/a/24159933) +* [All Rust string types explained (Let's Get Rusty)](https://www.youtube.com/watch?v=CpvzeyzgQdw) ## Pointers From 700c98812037eb4ae5c81bc65e86b27f3e78a973 Mon Sep 17 00:00:00 2001 From: lukeify <5379845+lukeify@users.noreply.github.com> Date: Wed, 3 Jan 2024 17:31:15 +1300 Subject: [PATCH 3/4] ci(appease): prettier --- Memory Management.md | 26 +++++++++++++------------- Rust.md | 16 ++++++++-------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Memory Management.md b/Memory Management.md index 35cfe9e..63b36b2 100644 --- a/Memory Management.md +++ b/Memory Management.md @@ -4,13 +4,13 @@ ## Stack -* LIFO (Last in, first out) approach, with `push` and `pop` paradigm of addition and removal. -* All stored data has fixed sizes that are always known. -* Pushing to stack is faster than allocation to heap—no process is needed to locate where data could be placed. -* Popping from the stack is faster than accessing from the heap because no lookup process is needed. -* Integrated tightly into code. - When a function is called, values passed to the function, and local variables are pushed onto the stack. - When the function is complete, this data is popped off. +- LIFO (Last in, first out) approach, with `push` and `pop` paradigm of addition and removal. +- All stored data has fixed sizes that are always known. +- Pushing to stack is faster than allocation to heap—no process is needed to locate where data could be placed. +- Popping from the stack is faster than accessing from the heap because no lookup process is needed. +- Integrated tightly into code. + When a function is called, values passed to the function, and local variables are pushed onto the stack. + When the function is complete, this data is popped off. ## Heap @@ -18,12 +18,12 @@ Significantly less structured way of storing data. Anything with unknown or chan High level approach to putting data on the heap: -* Request an amount of space. -* Memory allocator will find an empty spot that's big enough for your request. - * Marked as being used. -* Pointer to address of memory is returned. - * (This pointer can then be stored in the stack). -* Data with unknown size at compile time, or that may change is stored on the heap. +- Request an amount of space. +- Memory allocator will find an empty spot that's big enough for your request. + - Marked as being used. +- Pointer to address of memory is returned. + - (This pointer can then be stored in the stack). +- Data with unknown size at compile time, or that may change is stored on the heap. https://www.metservice.com/publicData/rainRadar/image/Otago/120K/2024-01-03T12:36:00+13:00 https://www.metservice.com/publicData/rainRadar/image/Otago/120K/2024-01-03T13:07:00+13:00 diff --git a/Rust.md b/Rust.md index aac340b..c0b8720 100644 --- a/Rust.md +++ b/Rust.md @@ -5,9 +5,9 @@ [Ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html) involves managing accessing, cleaning up, and tracking data stored in the heap. Rules of ownership: -* Each value has an owner. -* Only one owner allowed simultaneously. -* Owner goes out of scope = value is dropped. +- Each value has an owner. +- Only one owner allowed simultaneously. +- Owner goes out of scope = value is dropped. ```rust { @@ -68,8 +68,8 @@ The pointer can point to _either_ data on the heap, data in the compiled binary The string slice is made up of two parts: -* The `str` type. This cannot be used directly because its size is not known at compile time. -* The reference operator (`&`). We use this to get a pointer to the bytes of the string and its length. +- The `str` type. This cannot be used directly because its size is not known at compile time. +- The reference operator (`&`). We use this to get a pointer to the bytes of the string and its length. A **string literal** is a `&str` that is stored within the compiled binary itself: @@ -80,14 +80,14 @@ let my_string_literal = "Hello, world!"; // Type is `&str`, which is syntactic s When declared like this, they are hardcoded into the final executable as they are known at compile-time. String literals have a "static lifetime", which is to say their lifetime persists for the duration of the program execution. -* [Summary comparison from StackOverflow](https://stackoverflow.com/a/24159933) -* [All Rust string types explained (Let's Get Rusty)](https://www.youtube.com/watch?v=CpvzeyzgQdw) +- [Summary comparison from StackOverflow](https://stackoverflow.com/a/24159933) +- [All Rust string types explained (Let's Get Rusty)](https://www.youtube.com/watch?v=CpvzeyzgQdw) ## Pointers Types: -* "Reference" +- "Reference" ## `Box` From 7c8ca87085eca4216bbf0c3ef7ed566211ee28c4 Mon Sep 17 00:00:00 2001 From: lukeify <5379845+lukeify@users.noreply.github.com> Date: Wed, 21 Feb 2024 15:55:21 +1300 Subject: [PATCH 4/4] chore(rust): reorganise --- Rust.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Rust.md b/Rust.md index c0b8720..efe665b 100644 --- a/Rust.md +++ b/Rust.md @@ -23,7 +23,7 @@ let s1 = String::from("hello."); let s2 = s1; ``` -In this scenario s1 and s2 both are values that contain a pointer to the _same address in memory_ for the heap-stored data. +In this scenario `s1` and `s2` both are values that contain a pointer to the _same address in memory_ for the heap-stored data. When `s2` is assigned, `s1` becomes invalid because if both were to go out of scope simultaneously, they will both be freed from memory simultaneously—despite pointing to only one location in memory. This is known as a _double free error_ and rust prevents this. @@ -38,8 +38,6 @@ let s2 = s1.clone(); Both `s1` and `s2` are valid at the end of this code example. -## `Copy` trait - ## Strings **`String`** is a dynamic vector of bytes (`Vec`) and is heap-allocated, growable, UTF-8 encoded, and not [null-terminated](https://en.wikipedia.org/wiki/Null-terminated_string). @@ -57,7 +55,7 @@ pub struct String { **`&str`** is a _string slice_, also known as a "view into a string". It consists of a pointer to the string, and the string length, offering a view into a string. -It is called a _borrowed type_, because it doesn't own the underlying data, and are immutable (and is therefore not growable). +It is called a _borrowed type_, because it doesn't own the underlying data, and is immutable (and is therefore not growable). ```rust let my_string: String = String::from("Hello!":); @@ -110,6 +108,8 @@ fn get_random_traitable() -> Box { [Rust by example](https://doc.rust-lang.org/rust-by-example/trait/dyn.html) reference. +## `Copy` trait + ## `pub(crate)` for struct members ## Attributes @@ -121,3 +121,7 @@ fn get_random_traitable() -> Box { ## Apostrophes (related to types) ## Lifetimes + +## Self vs self + +https://stackoverflow.com/questions/32304595/whats-the-difference-between-self-and-self