diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..d20f32d --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,103 @@ +// Group functionality with different types +// Define special syntac for specific purpose +// Variable number of arguments +// Different combination of arguments +macro_rules! say_hello { + () => { + println!("Hello world!"); + }; +} + +// Types of arguments have designators: +// block +// expr is used for expressions +// ident is used for variable/function names +// item +// literal is used for literal constants +// pat (pattern) +// path +// stmt (statement) +// tt (token tree) +// ty (type) +// vis (visibility qualifier) +macro_rules! generate_function { + ($func_name:ident) => { + fn $func_name() { + println!("You called {:?}()", stringify!($func_name)); + } + }; +} + +generate_function!(foo); + +macro_rules! process_expression { + ($expression: expr) => { + println!("{:?} = {:?}", stringify!($expression), $expression); + }; +} + +// Overload +macro_rules! match_block { + ($left: expr; and $right: expr) => { + println!("A: {:?} and {:?}", stringify!($left), stringify!($right)) + }; + + ($left: expr; or $right:expr) => { + println!( + "B: {:?} or {:?} is {:?}", + stringify!($left), + stringify!($right), + $left || $right + ) + }; +} + +// Repeat: variable number of args o a type +macro_rules! find_max { + ($x:expr) => ($x); + ($x:expr, $($y:expr), +) => (std::cmp::max($x, find_max!($($y), +))); +} + +// DSLs: Domain Specific Languages +// macro_rules allows you to create your own syntax +macro_rules! calc { + (eval $e:expr) => { + println!("{} = {}", stringify!($e), $e); + }; +} + +macro_rules! calculate { + (eval $e: expr) => { + { + let val: usize = $e; // Force types to be integers + println!("{} = {}", stringify!{$e}, val); + } + }; + (eval $e: expr, $(eval $y: expr), +) => {{ + calculate!{eval $e} + calculate!{ $(eval $y), + } + }}; +} + +pub fn macros_rule() { + foo(); + say_hello!(); + process_expression!(1 + 5 * 3); + + match_block!(1i32 + 1 == 2i32; and 2i32 * 2 == 4i32); // Enters first branch + match_block!(true; or false); // Enter second branch + match_block!(true; and true); // Enters first branch + + println!("Max is {}", find_max!(5, 3 * 8, 4, 9 * 5)); + + calc! { + eval (1 + 2) * 4 + } + + calculate! { + eval (1 + 2) * 4, + eval 1 + 5, + eval 7 + 4, + eval 3 + 9 + } +} diff --git a/src/main.rs b/src/main.rs index 1bf624d..ce92a5b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,18 +5,8 @@ // : /// Doc comment: generate library docs for the following item // : //! Doc comment -// mod helloworld; -// mod primitives; -// mod customtypes; -//mod variablebindings; -// mod types; -//mod conversion; -// mod controlflow; -// mod traits; -// mod str_types; -// mod functions; -// mod exercises; -mod concepts; +mod macros; +use macros::macros_rule; #[cfg(test)] #[path = "./test/basic_test.rs"] @@ -30,10 +20,12 @@ fn main() { //types::types_module(); //conversion::conversion_module(); // controlflow::control_flow_module(); - //traits::traits_exercise(); + // traits::traits_exercise(); // str_types::str_types_module(); // exercises::run_easy(); // my_lib::public_function(); // functions::functions_module(); - concepts::box_basics(); + // concepts::box_basics(); + // operators::operators_module(); + macros_rule(); } diff --git a/src/operators.rs b/src/operators.rs new file mode 100644 index 0000000..0abaa91 --- /dev/null +++ b/src/operators.rs @@ -0,0 +1,24 @@ +use std::ops; +use std::ops::Add; + +/* + * Operators are syntectic sugar for method calls + * The + operator calls the add method and so on + * */ +pub fn operators_module() { + let a = 3u32.add(3); + println!("a is {a}"); + + // Operator overloading + struct Foo; + impl ops::Add for Foo { + type Output = Foo; + fn add(self, rhs: u32) -> Self::Output { + println!("> add called with {}", rhs); + Foo + } + } + + let foo = Foo; + let _too = foo + 3; // > add called with 3 +} diff --git a/src/traits.rs b/src/traits.rs index 9b31633..1650201 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -6,6 +6,8 @@ * 4. Extend the trait with a second function and see what happens * */ +use std::thread::current; + pub trait Move { fn to(&mut self, x: i32, y: i32); } @@ -32,4 +34,91 @@ pub fn traits_exercise() { me.to(10, 20); println!("My name is {} and i'm at {:?}", me.name, me.position); + + // Drop trait: called with an object goes out of scope + struct Foo; + impl Drop for Foo { + fn drop(&mut self) { + println!("Foo went out of scope..."); + } + } + + let mut counter = 0u32; + loop { + if counter > 5 { + break; + } + counter += 1; + let _foo = Foo; + } + + // Iterator traits + // Example: Fibonacci + struct Fibonacci { + current: u32, + next: u32, + } + + impl Iterator for Fibonacci { + type Item = u32; + fn next(&mut self) -> Option { + let current = self.current; + self.current = self.next; + self.next = self.next + current; + Some(current) + } + } + + let mut fib = Fibonacci { + current: 0, + next: 1, + }; + + for _ in 0..21 { + println!("Fib {:?}", fib.next()); + } + + let mut fib = Fibonacci { + current: 0, + next: 1, + }; + println!("Fib 20 {:?}", fib.nth(20)); + let fib = Fibonacci { + current: 0, + next: 1, + }; + println!("Fib skip 20 {:?}", fib.skip(20).next()); + + // Disambiguating overlapping traits + struct Fee { + a: u32, + b: String, + } + + trait A { + fn get(&self) -> u32; + } + trait B { + fn get(&self) -> String; + } + + impl A for Fee { + fn get(&self) -> u32 { + self.a + } + } + impl B for Fee { + fn get(&self) -> String { + self.b.clone() + } + } + + let fee = Fee { + a: 1234, + b: "asdf".to_string(), + }; + + let a = ::get(&fee); + let b = ::get(&fee); + println!("The a is {} and the b is {}", a, b); }