diff --git a/.gitignore b/.gitignore index 9f97022..5f32e70 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -target/ \ No newline at end of file +target/ +.env \ No newline at end of file diff --git a/src/bin/02ca_strings.rs b/src/bin/02ca_strings.rs index 2718120..64f8f43 100644 --- a/src/bin/02ca_strings.rs +++ b/src/bin/02ca_strings.rs @@ -1,5 +1,10 @@ +// Some Notes: +// clones are expensive, since the data in the heap for the strings must be copied into another heap location +// borrowed strings &str are fixed sized references to the underlying str data + fn main() { let speech = "\"Ouch!\" said the well.\n"; + // All Strings are the same size because they are simply the size of the Fat pointer pointing to some region in the heap memory println!("Speech: {speech}"); diff --git a/src/bin/0a_intro.rs b/src/bin/0a_intro.rs index e7323d1..82799da 100644 --- a/src/bin/0a_intro.rs +++ b/src/bin/0a_intro.rs @@ -12,4 +12,14 @@ fn main() { the current directory the user must explicity specify the current directory as the path to check for the script */ + + let name = String::from("Brian"); + println!("Outer {name}"); + + { + let name = String::from("Hello"); + println!("Inner {name}"); + } + + println!("Outer {name}"); } diff --git a/src/bin/17bb_hashset.rs b/src/bin/17bb_hashset.rs new file mode 100644 index 0000000..c06f432 --- /dev/null +++ b/src/bin/17bb_hashset.rs @@ -0,0 +1,13 @@ +use std::collections::{HashMap, HashSet}; + +fn main() { + let mut _ages = HashMap::::new(); + let mut seen = HashSet::<&str>::new(); + + // the insert method on hashset returns a boolean indicating whethere the item was added or not + // the item is added when it's not already present in the hashset else is it not added + let _inserted = seen.insert("Brian"); + let _inserted = seen.insert("Joseph"); + + let _ = _ages.keys(); +} diff --git a/src/bin/22d_more_on_iterators.rs b/src/bin/22d_more_on_iterators.rs new file mode 100644 index 0000000..7f59ed9 --- /dev/null +++ b/src/bin/22d_more_on_iterators.rs @@ -0,0 +1,27 @@ +fn main() { + let v = vec![1, 2, 3, 4, 5, 6]; + let v_iter = v.iter(); + + for item in v_iter { + println!("Item: {item}") + } + + for item in v { + println!("I: {item}"); + } + + // methods that call the next method in iterators are called consumers + // methods that do not call next method are called adapters + let sum_of_values = [1, 2, 3, 4, 5].iter().sum::(); + println!("Sum of values = {sum_of_values}"); + + // after using a consumer, the iterator is well, CONSUMED + // adapters are methods that produce other iterators + // in this case, the map method is an adapter method + let _v2_iter = [2, 3, 4, 5].iter().map(|x| x * x).collect::>(); + + // let sum_of_squares: i32 = v.iter() + // .filter(|&x| x % 2 == 0) + // .map(|x| x*x) + // .sum(); +} diff --git a/src/bin/45_strings_and_text.rs b/src/bin/45_strings_and_text.rs index 0af9c16..7503511 100644 --- a/src/bin/45_strings_and_text.rs +++ b/src/bin/45_strings_and_text.rs @@ -1,4 +1,3 @@ - fn main() { // Rust treats strings as UTF-8 Encoded by default let s = "你好 Rust"; @@ -31,4 +30,3 @@ fn main() { // .is_ascii_alphabetic() ... // } - diff --git a/src/bin/48c_send_and_sync.rs b/src/bin/48c_send_and_sync.rs new file mode 100644 index 0000000..ad2284c --- /dev/null +++ b/src/bin/48c_send_and_sync.rs @@ -0,0 +1,31 @@ +use std::{sync::Arc, thread}; + +fn main() { + // Send data types can be sent across thread + let string = String::from("Data"); + let handle = thread::spawn(move || { + println!("{string}"); + }); + + handle.join().unwrap(); + + // Sync data types can be referenced from multiple threads + // the Arc is placed on the heap and a reference count it maintained + let data = Arc::new(5); + + let clone1 = Arc::clone(&data); + let clone2 = Arc::clone(&data); + + let handle_2 = thread::spawn(move || { + println!("{}", clone1); + }); + + let handle_3 = thread::spawn(move || { + println!("{}", clone2); + }); + + handle_2.join().unwrap(); + handle_3.join().unwrap(); + + // T is Sync if &T is Send +} diff --git a/src/bin/49_macros.rs b/src/bin/49_macros.rs new file mode 100644 index 0000000..fe1d2be --- /dev/null +++ b/src/bin/49_macros.rs @@ -0,0 +1,146 @@ +fn main() { + // an example of a macro is the assert_eq! macro + // this functionality could have been written as a generic function + // but macros do more than functions can do, for example, when an assert_eq! macro fails + // it prints the filename and the line number where the failure happened, fucntions have no way of getting that information + + // macros are expanded during the compilation phase before types are checked and well before + // any machine code is generated, they are expanded recursively into rust code, since macros expansion + // can themselves contain macros + // + // macros are differentiated from functions with the bang symbol before their parenthesis + // + // macro_rules! macro is the main way to define macros in Rust + // when defining macros, the ! is not used, it is only used when calling them + // a macro defined by macro_rules works entirely by pattern matching + /* + * (pattern 1) => (template 1) + * (pattern 2) => (template 2) + * + */ + + // you can use square brackets or curly braces for macros, they are still work + println!("Hello"); + println!["Hello"]; // this is why vec! is possible + println! {"Hello"}; + + // by convention, () are used for assert_*! macros, [] for vec! and {} for macro_rules! + // assert_eq! expands to + // assert_eq![2, 1 + 1]; + + /* + * match (&2, &(1 + 1)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + let kind = ::core::panicking::AssertKind::Eq; + ::core::panicking::assert_failed( + kind, + &*left_val, + &*right_val, + ::core::option::Option::None, + ); + } + } + }; + */ + + macro_rules! answer { + () => { + 42 + }; + } + + macro_rules! double { + ($x:expr) => { + $x * 2 + }; + } + + let result = double!(answer!()); + println!("Result: {}", result); + + // Some interestig macros + // file!() return a string path of the current file + // line!() return the line which the first macro that call it was called from + // column!() same as above, but for column + // include!("filename.rs"), includes the content of the file in the current line, the content must be valid Rust code + // include_str!("file.txt"), include the text content of the specified file + // include_bytes!("file.dat") same as above, but the file is treated a binary data + // todo!(), unimplemented!() + // matches!(value, pattern) + + // Building the json! Macro + use std::collections::HashMap; + + #[allow(dead_code)] + #[derive(Clone, PartialEq, Debug)] + enum Json { + Null, + Boolean(bool), + Number(f64), + String(String), + Array(Vec), + #[allow(clippy::box_collection)] + Object(Box>), + } + + macro_rules! json { + // the null literal must be matched directly + (null) => { Json::Null }; + ([ $( $element:tt ),* ]) => { Json::Array(vec![ $( json!($element) ),* ]) }; + ({ $( $key:tt : $value:tt ),* }) => { Json::Object(Box::new(vec![ + $( ($key.to_string(), json!($value)) ),* + ])) }; + ( $other:tt ) => { + Json::from($other) + } + } + + impl From for Json { + fn from(b: bool) -> Json { + Json::Boolean(b) + } + } + + impl From for Json { + fn from(value: String) -> Json { + Json::String(value) + } + } + + impl<'a> From<&'a str> for Json { + fn from(value: &'a str) -> Json { + Json::String(value.to_string()) + } + } + + macro_rules! impl_from_num_for_json { + ( $( $t:ident ),* ) => { + $( + impl From<$t> for Json { + fn from(n: $t) -> Json { + Json::Number(n as f64) + } + } + )* + }; + } + + impl_from_num_for_json!( + u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64 + ); + + assert_eq!(json!(null), Json::Null); + + let macro_generated_array = json!([1, 2, 3, 4]); + let hand_coded_array = Json::Array(vec![ + Json::Number(1.), + Json::Number(2.), + Json::Number(3.), + Json::Number(4.), + ]); + + assert_eq!(macro_generated_array, hand_coded_array); + + // Macros marked with #[macro_export] are automatically public to other modules +} diff --git a/src/bin/50_unsafe_code.rs b/src/bin/50_unsafe_code.rs new file mode 100644 index 0000000..9744b8e --- /dev/null +++ b/src/bin/50_unsafe_code.rs @@ -0,0 +1,14 @@ +macro_rules! capitalize { + ($a: expr) => { + let mut v: Vec = $a.chars().collect(); + v[0] = v[0].to_uppercase().nth(0).unwrap(); + $a = v.into_iter().collect(); + }; +} + +fn main() { + let mut name = String::from("test"); + capitalize!(name); + + println!("{name}"); +} diff --git a/src/bin/51_environment_variables.rs b/src/bin/51_environment_variables.rs new file mode 100644 index 0000000..df637f2 --- /dev/null +++ b/src/bin/51_environment_variables.rs @@ -0,0 +1,3 @@ +// const API_KEY: &'static str = env!("API_KEY"); + +fn main() {}