exercises

Log | Files | Refs | README

commit 5d8af9cdd7d664569998db6f327d98b89828f519
parent dc9f1fd329c0e4edf9c3eb1cde10109d07807d97
Author: ling0x <ling0x@users.noreply.github.com>
Date:   Mon, 15 Jun 2026 17:12:44 +0100

refactor: exercises

Diffstat:
Aasync_programming_in_rust/event_queue/Cargo.lock | 7+++++++
Aasync_programming_in_rust/event_queue/Cargo.toml | 6++++++
Aasync_programming_in_rust/event_queue/src/ffi.rs | 2++
Aasync_programming_in_rust/event_queue/src/lib.rs | 2++
Aasync_programming_in_rust/event_queue/src/main.rs | 3+++
Aasync_programming_in_rust/event_queue/src/poll.rs | 1+
Aasync_programming_in_rust/syscalls/Cargo.lock | 7+++++++
Aasync_programming_in_rust/syscalls/Cargo.toml | 6++++++
Aasync_programming_in_rust/syscalls/src/assembly_syscall.rs | 40++++++++++++++++++++++++++++++++++++++++
Aasync_programming_in_rust/syscalls/src/highest_absraction_syscall.rs | 3+++
Aasync_programming_in_rust/syscalls/src/lib.rs | 7+++++++
Aasync_programming_in_rust/syscalls/src/main.rs | 19+++++++++++++++++++
Aasync_programming_in_rust/syscalls/src/os_abstraction_syscall.rs | 41+++++++++++++++++++++++++++++++++++++++++
Rdesign_patterns_in_rust/bad_calculator/Cargo.lock -> design_patterns_in_rust/anti_patterns/bad_calculator/Cargo.lock | 0
Rdesign_patterns_in_rust/bad_calculator/Cargo.toml -> design_patterns_in_rust/anti_patterns/bad_calculator/Cargo.toml | 0
Rdesign_patterns_in_rust/bad_calculator/src/main.rs -> design_patterns_in_rust/anti_patterns/bad_calculator/src/main.rs | 0
Rdesign_patterns_in_rust/bad_calculator_2/Cargo.lock -> design_patterns_in_rust/anti_patterns/bad_calculator_2/Cargo.lock | 0
Rdesign_patterns_in_rust/bad_calculator_2/Cargo.toml -> design_patterns_in_rust/anti_patterns/bad_calculator_2/Cargo.toml | 0
Rdesign_patterns_in_rust/bad_calculator_2/src/cloning_bad_example.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_2/src/cloning_bad_example.rs | 0
Rdesign_patterns_in_rust/bad_calculator_2/src/cloning_better_example.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_2/src/cloning_better_example.rs | 0
Rdesign_patterns_in_rust/bad_calculator_2/src/lib.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_2/src/lib.rs | 0
Rdesign_patterns_in_rust/bad_calculator_2/src/main.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_2/src/main.rs | 0
Rdesign_patterns_in_rust/bad_calculator_2/src/ownership_bad_example.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_2/src/ownership_bad_example.rs | 0
Rdesign_patterns_in_rust/bad_calculator_2/src/ownership_better_example.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_2/src/ownership_better_example.rs | 0
Rdesign_patterns_in_rust/bad_calculator_2/src/smart_pointers_bad_example.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_2/src/smart_pointers_bad_example.rs | 0
Rdesign_patterns_in_rust/bad_calculator_2/src/smart_pointers_better_example.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_2/src/smart_pointers_better_example.rs | 0
Rdesign_patterns_in_rust/bad_calculator_3/Cargo.lock -> design_patterns_in_rust/anti_patterns/bad_calculator_3/Cargo.lock | 0
Rdesign_patterns_in_rust/bad_calculator_3/Cargo.toml -> design_patterns_in_rust/anti_patterns/bad_calculator_3/Cargo.toml | 0
Rdesign_patterns_in_rust/bad_calculator_3/src/bad_example.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_3/src/bad_example.rs | 0
Rdesign_patterns_in_rust/bad_calculator_3/src/bad_example_statics.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_3/src/bad_example_statics.rs | 0
Rdesign_patterns_in_rust/bad_calculator_3/src/bad_example_unsafe.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_3/src/bad_example_unsafe.rs | 0
Rdesign_patterns_in_rust/bad_calculator_3/src/better_example.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_3/src/better_example.rs | 0
Rdesign_patterns_in_rust/bad_calculator_3/src/better_example_no_statics.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_3/src/better_example_no_statics.rs | 0
Rdesign_patterns_in_rust/bad_calculator_3/src/better_example_no_unsafe.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_3/src/better_example_no_unsafe.rs | 0
Rdesign_patterns_in_rust/bad_calculator_3/src/lib.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_3/src/lib.rs | 0
Rdesign_patterns_in_rust/bad_calculator_3/src/main.rs -> design_patterns_in_rust/anti_patterns/bad_calculator_3/src/main.rs | 0
Rdesign_patterns_in_rust/not_so_bad_calculator/Cargo.lock -> design_patterns_in_rust/anti_patterns/not_so_bad_calculator/Cargo.lock | 0
Rdesign_patterns_in_rust/not_so_bad_calculator/Cargo.toml -> design_patterns_in_rust/anti_patterns/not_so_bad_calculator/Cargo.toml | 0
Rdesign_patterns_in_rust/not_so_bad_calculator/src/main.rs -> design_patterns_in_rust/anti_patterns/not_so_bad_calculator/src/main.rs | 0
Rdesign_patterns_in_rust/slightly_worse_calculator/Cargo.lock -> design_patterns_in_rust/anti_patterns/slightly_worse_calculator/Cargo.lock | 0
Rdesign_patterns_in_rust/slightly_worse_calculator/Cargo.toml -> design_patterns_in_rust/anti_patterns/slightly_worse_calculator/Cargo.toml | 0
Rdesign_patterns_in_rust/slightly_worse_calculator/src/main.rs -> design_patterns_in_rust/anti_patterns/slightly_worse_calculator/src/main.rs | 0
Rdesign_patterns_in_rust/the_worst_calculator/Cargo.lock -> design_patterns_in_rust/anti_patterns/the_worst_calculator/Cargo.lock | 0
Rdesign_patterns_in_rust/the_worst_calculator/Cargo.toml -> design_patterns_in_rust/anti_patterns/the_worst_calculator/Cargo.toml | 0
Rdesign_patterns_in_rust/the_worst_calculator/src/main.rs -> design_patterns_in_rust/anti_patterns/the_worst_calculator/src/main.rs | 0
Adesign_patterns_in_rust/creational_patterns/Cargo.lock | 7+++++++
Adesign_patterns_in_rust/creational_patterns/Cargo.toml | 6++++++
Rdesign_patterns_in_rust/good_calculator/src/builder.rs -> design_patterns_in_rust/creational_patterns/src/builder.rs | 0
Rdesign_patterns_in_rust/good_calculator/src/calculator.rs -> design_patterns_in_rust/creational_patterns/src/calculator.rs | 0
Rdesign_patterns_in_rust/good_calculator/src/factory.rs -> design_patterns_in_rust/creational_patterns/src/factory.rs | 0
Rdesign_patterns_in_rust/good_calculator/src/lib.rs -> design_patterns_in_rust/creational_patterns/src/lib.rs | 0
Adesign_patterns_in_rust/creational_patterns/src/main.rs | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rdesign_patterns_in_rust/good_calculator/src/number.rs -> design_patterns_in_rust/creational_patterns/src/number.rs | 0
Rdesign_patterns_in_rust/good_calculator/src/operator.rs -> design_patterns_in_rust/creational_patterns/src/operator.rs | 0
Rdesign_patterns_in_rust/good_calculator/src/token.rs -> design_patterns_in_rust/creational_patterns/src/token.rs | 0
Ddesign_patterns_in_rust/good_calculator/Cargo.lock | 7-------
Ddesign_patterns_in_rust/good_calculator/Cargo.toml | 6------
Ddesign_patterns_in_rust/good_calculator/src/main.rs | 92-------------------------------------------------------------------------------
Ddesign_patterns_in_rust/good_calculator_2/Cargo.lock | 7-------
Ddesign_patterns_in_rust/good_calculator_2/Cargo.toml | 6------
Ddesign_patterns_in_rust/good_calculator_2/src/main.rs | 43-------------------------------------------
Mdesign_patterns_in_rust/index.md | 4++--
Adesign_patterns_in_rust/structural_patterns/Cargo.lock | 7+++++++
Adesign_patterns_in_rust/structural_patterns/Cargo.toml | 6++++++
Rdesign_patterns_in_rust/good_calculator_2/src/adapters.rs -> design_patterns_in_rust/structural_patterns/src/adapters.rs | 0
Rdesign_patterns_in_rust/good_calculator_2/src/bridge_pattern.rs -> design_patterns_in_rust/structural_patterns/src/bridge_pattern.rs | 0
Rdesign_patterns_in_rust/good_calculator_2/src/builder.rs -> design_patterns_in_rust/structural_patterns/src/builder.rs | 0
Rdesign_patterns_in_rust/good_calculator_2/src/calculator.rs -> design_patterns_in_rust/structural_patterns/src/calculator.rs | 0
Rdesign_patterns_in_rust/good_calculator_2/src/facade.rs -> design_patterns_in_rust/structural_patterns/src/facade.rs | 0
Rdesign_patterns_in_rust/good_calculator_2/src/factory.rs -> design_patterns_in_rust/structural_patterns/src/factory.rs | 0
Rdesign_patterns_in_rust/good_calculator_2/src/lib.rs -> design_patterns_in_rust/structural_patterns/src/lib.rs | 0
Adesign_patterns_in_rust/structural_patterns/src/main.rs | 43+++++++++++++++++++++++++++++++++++++++++++
Rdesign_patterns_in_rust/good_calculator_2/src/number.rs -> design_patterns_in_rust/structural_patterns/src/number.rs | 0
Rdesign_patterns_in_rust/good_calculator_2/src/operator.rs -> design_patterns_in_rust/structural_patterns/src/operator.rs | 0
Rdesign_patterns_in_rust/good_calculator_2/src/token.rs -> design_patterns_in_rust/structural_patterns/src/token.rs | 0
Rdesign_patterns_in_rust/good_calculator_2/src/utilities.rs -> design_patterns_in_rust/structural_patterns/src/utilities.rs | 0
76 files changed, 307 insertions(+), 163 deletions(-)

diff --git a/async_programming_in_rust/event_queue/Cargo.lock b/async_programming_in_rust/event_queue/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "event_queue" +version = "0.1.0" diff --git a/async_programming_in_rust/event_queue/Cargo.toml b/async_programming_in_rust/event_queue/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "event_queue" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/async_programming_in_rust/event_queue/src/ffi.rs b/async_programming_in_rust/event_queue/src/ffi.rs @@ -0,0 +1,2 @@ +//! This contain the code related to the syscalls we need to communicate +//! with the host operating system diff --git a/async_programming_in_rust/event_queue/src/lib.rs b/async_programming_in_rust/event_queue/src/lib.rs @@ -0,0 +1,2 @@ +mod ffi; +mod poll; diff --git a/async_programming_in_rust/event_queue/src/main.rs b/async_programming_in_rust/event_queue/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/async_programming_in_rust/event_queue/src/poll.rs b/async_programming_in_rust/event_queue/src/poll.rs @@ -0,0 +1 @@ +//! This contains the main abstraction, which is a think layer over `epoll`. diff --git a/async_programming_in_rust/syscalls/Cargo.lock b/async_programming_in_rust/syscalls/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "syscalls" +version = "0.1.0" diff --git a/async_programming_in_rust/syscalls/Cargo.toml b/async_programming_in_rust/syscalls/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "syscalls" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/async_programming_in_rust/syscalls/src/assembly_syscall.rs b/async_programming_in_rust/syscalls/src/assembly_syscall.rs @@ -0,0 +1,40 @@ +use std::arch::asm; + +#[inline(never)] +pub fn syscall(message: String) { + let msg_ptr = message.as_ptr(); + let len = message.len(); + + // We can only call inline assembly using unsafe Rust + unsafe { + asm!( + // The first line of assembly puts the value 1 in the rax register. + // The kernel knows that a value of 1 in the rax means that we + // want to make a `write`. + "mov rax, 1", + // The second line puts the value 1 in the rdi register. + // This tells the kernel where we want to write to. + "mov rdi, 1", + // This calls the syscall instruction. This issues a software + // interrupt, and the CPU passes on control to the OS. + "syscall", + // This writes the address to the buffer where our text is stored + // in the rsi register. + in("rsi") msg_ptr, + // This writes the length (in bytes) of our text buffer to the + // rdx register. + in("rdx") len, + // These four lines are not instructions to the CPU; they're + // meant to tell the compiler that it can't store anything in + // these registers and assume the data is untouched when we + // exit the inline assembly block. + // + // We tell the compiler that there will be some unspecified + // data (indicated by underscore) written to these registers. + out("rax") _, + out("rdi") _, + lateout("rsi") _, + lateout("rdx") _ + ); + } +} diff --git a/async_programming_in_rust/syscalls/src/highest_absraction_syscall.rs b/async_programming_in_rust/syscalls/src/highest_absraction_syscall.rs @@ -0,0 +1,3 @@ +pub fn syscall(message: String) { + println!("{}", message) +} diff --git a/async_programming_in_rust/syscalls/src/lib.rs b/async_programming_in_rust/syscalls/src/lib.rs @@ -0,0 +1,7 @@ +mod assembly_syscall; +mod highest_absraction_syscall; +mod os_abstraction_syscall; + +pub use assembly_syscall::syscall as assembly_syscall; +pub use highest_absraction_syscall::syscall as std_syscall; +pub use os_abstraction_syscall::syscall as os_syscall; diff --git a/async_programming_in_rust/syscalls/src/main.rs b/async_programming_in_rust/syscalls/src/main.rs @@ -0,0 +1,19 @@ +use std::io; + +use syscalls::{assembly_syscall, os_syscall, std_syscall}; + +fn main() -> io::Result<()> { + let assembly_message = "Hello world from raw syscall with inline assembly in Rust!\n"; + let assembly_message = String::from(assembly_message); + assembly_syscall(assembly_message); + + let normal_message = "Hello world from operating system libc syscall in Rust!\n"; + let normal_message = String::from(normal_message); + os_syscall(normal_message)?; + + let std_message = "Hello world from std syscall in Rust!\n"; + let std_message = String::from(std_message); + std_syscall(std_message); + + Ok(()) +} diff --git a/async_programming_in_rust/syscalls/src/os_abstraction_syscall.rs b/async_programming_in_rust/syscalls/src/os_abstraction_syscall.rs @@ -0,0 +1,41 @@ +//! This is the next level of abstraction: instead of calling assembly directly, +//! we use the operating system's API. Instead of `asm` module we use `io`. + +use std::io; + +// This is specific to the Linux operating system and macOS. +// Every Linux (and maxOS) installation comes with a version `libc`, which is +// C library for communicating with the operating system. +// +// Having `libc`, with a consistent API, allows us to program the same way +// without worrying about the underlying platform architecture. +// +// Kernel developers can also make changes to the underlying ABI without +// breaking everyone's program. +#[cfg(target_family = "unix")] +// This flag tells the compiler to link to the "c" library on the system: +#[link(name = "c")] +// This defines what functions in the linked library we want to call: +unsafe extern "C" { + /// This uses Rusts FFI to call external functions + /// + /// The write function takes: + /// - The file descriptor `fd`, which in this case is a handle to `stdout`. + /// - A pointer to an array of u8, `buf` values. + /// - The length of that buffer, `count`. + fn write(fd: u32, buf: *const u8, count: usize) -> i32; +} + +#[cfg(target_family = "unix")] +pub fn syscall(message: String) -> io::Result<()> { + let msg_ptr = message.as_ptr(); + let len = message.len(); + // This needs to be wrapped in unsafe block, since Rust can't guarantee + // safety when calling external functions: + let res = unsafe { write(1, msg_ptr, len) }; + + if res == -1 { + return Err(io::Error::last_os_error()); + } + Ok(()) +} diff --git a/design_patterns_in_rust/bad_calculator/Cargo.lock b/design_patterns_in_rust/anti_patterns/bad_calculator/Cargo.lock diff --git a/design_patterns_in_rust/bad_calculator/Cargo.toml b/design_patterns_in_rust/anti_patterns/bad_calculator/Cargo.toml diff --git a/design_patterns_in_rust/bad_calculator/src/main.rs b/design_patterns_in_rust/anti_patterns/bad_calculator/src/main.rs diff --git a/design_patterns_in_rust/bad_calculator_2/Cargo.lock b/design_patterns_in_rust/anti_patterns/bad_calculator_2/Cargo.lock diff --git a/design_patterns_in_rust/bad_calculator_2/Cargo.toml b/design_patterns_in_rust/anti_patterns/bad_calculator_2/Cargo.toml diff --git a/design_patterns_in_rust/bad_calculator_2/src/cloning_bad_example.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_2/src/cloning_bad_example.rs diff --git a/design_patterns_in_rust/bad_calculator_2/src/cloning_better_example.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_2/src/cloning_better_example.rs diff --git a/design_patterns_in_rust/bad_calculator_2/src/lib.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_2/src/lib.rs diff --git a/design_patterns_in_rust/bad_calculator_2/src/main.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_2/src/main.rs diff --git a/design_patterns_in_rust/bad_calculator_2/src/ownership_bad_example.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_2/src/ownership_bad_example.rs diff --git a/design_patterns_in_rust/bad_calculator_2/src/ownership_better_example.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_2/src/ownership_better_example.rs diff --git a/design_patterns_in_rust/bad_calculator_2/src/smart_pointers_bad_example.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_2/src/smart_pointers_bad_example.rs diff --git a/design_patterns_in_rust/bad_calculator_2/src/smart_pointers_better_example.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_2/src/smart_pointers_better_example.rs diff --git a/design_patterns_in_rust/bad_calculator_3/Cargo.lock b/design_patterns_in_rust/anti_patterns/bad_calculator_3/Cargo.lock diff --git a/design_patterns_in_rust/bad_calculator_3/Cargo.toml b/design_patterns_in_rust/anti_patterns/bad_calculator_3/Cargo.toml diff --git a/design_patterns_in_rust/bad_calculator_3/src/bad_example.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_3/src/bad_example.rs diff --git a/design_patterns_in_rust/bad_calculator_3/src/bad_example_statics.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_3/src/bad_example_statics.rs diff --git a/design_patterns_in_rust/bad_calculator_3/src/bad_example_unsafe.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_3/src/bad_example_unsafe.rs diff --git a/design_patterns_in_rust/bad_calculator_3/src/better_example.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_3/src/better_example.rs diff --git a/design_patterns_in_rust/bad_calculator_3/src/better_example_no_statics.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_3/src/better_example_no_statics.rs diff --git a/design_patterns_in_rust/bad_calculator_3/src/better_example_no_unsafe.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_3/src/better_example_no_unsafe.rs diff --git a/design_patterns_in_rust/bad_calculator_3/src/lib.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_3/src/lib.rs diff --git a/design_patterns_in_rust/bad_calculator_3/src/main.rs b/design_patterns_in_rust/anti_patterns/bad_calculator_3/src/main.rs diff --git a/design_patterns_in_rust/not_so_bad_calculator/Cargo.lock b/design_patterns_in_rust/anti_patterns/not_so_bad_calculator/Cargo.lock diff --git a/design_patterns_in_rust/not_so_bad_calculator/Cargo.toml b/design_patterns_in_rust/anti_patterns/not_so_bad_calculator/Cargo.toml diff --git a/design_patterns_in_rust/not_so_bad_calculator/src/main.rs b/design_patterns_in_rust/anti_patterns/not_so_bad_calculator/src/main.rs diff --git a/design_patterns_in_rust/slightly_worse_calculator/Cargo.lock b/design_patterns_in_rust/anti_patterns/slightly_worse_calculator/Cargo.lock diff --git a/design_patterns_in_rust/slightly_worse_calculator/Cargo.toml b/design_patterns_in_rust/anti_patterns/slightly_worse_calculator/Cargo.toml diff --git a/design_patterns_in_rust/slightly_worse_calculator/src/main.rs b/design_patterns_in_rust/anti_patterns/slightly_worse_calculator/src/main.rs diff --git a/design_patterns_in_rust/the_worst_calculator/Cargo.lock b/design_patterns_in_rust/anti_patterns/the_worst_calculator/Cargo.lock diff --git a/design_patterns_in_rust/the_worst_calculator/Cargo.toml b/design_patterns_in_rust/anti_patterns/the_worst_calculator/Cargo.toml diff --git a/design_patterns_in_rust/the_worst_calculator/src/main.rs b/design_patterns_in_rust/anti_patterns/the_worst_calculator/src/main.rs diff --git a/design_patterns_in_rust/creational_patterns/Cargo.lock b/design_patterns_in_rust/creational_patterns/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "creational_patterns" +version = "0.1.0" diff --git a/design_patterns_in_rust/creational_patterns/Cargo.toml b/design_patterns_in_rust/creational_patterns/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "creational_patterns" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/design_patterns_in_rust/good_calculator/src/builder.rs b/design_patterns_in_rust/creational_patterns/src/builder.rs diff --git a/design_patterns_in_rust/good_calculator/src/calculator.rs b/design_patterns_in_rust/creational_patterns/src/calculator.rs diff --git a/design_patterns_in_rust/good_calculator/src/factory.rs b/design_patterns_in_rust/creational_patterns/src/factory.rs diff --git a/design_patterns_in_rust/good_calculator/src/lib.rs b/design_patterns_in_rust/creational_patterns/src/lib.rs diff --git a/design_patterns_in_rust/creational_patterns/src/main.rs b/design_patterns_in_rust/creational_patterns/src/main.rs @@ -0,0 +1,92 @@ +use creational_patterns::{ + builder::{Expression, SubExpression}, + calculator::{Calculator, CalculatorConfig}, + factory::{ScientificFactory, StandardFactory}, + number::StandardNumber, + operator::{Operator, StandardOperator}, + token::Token, +}; + +fn main() -> Result<(), String> { + // 1. Enum in Vec + // + // In Rust Vec has to be a single type, the Token enum conviniently allows + // this by providing a unified type that can hold any token variant + // let numbers = [ + // Token::number(6.0), + // Token::operator(Operator::Add), + // Token::Number(3.0) + // ] + + /// 2. Abstract Factory + /// + /// With the abstract factory pattern, we can create different kinds of + /// calculators just by specifying which factory we would like to use: + let standard_calc = Calculator::new(StandardFactory); + let scientific_calc = Calculator::new(ScientificFactory); + + /// 3. Builder Pattern + /// + /// This is how the Builder Pattern and Abstract Factory Pattern compose: + /// the builder delegates token creation to whichever factory it was given + // With standard calculator factory + let expr = Expression::builder(StandardFactory) + .number("2")? + .operator("+")? + .open_paren() + .number("3")? + .operator("*")? + .number("4")? + .close_paren()? + .build(); + // With scientific calculator factory + let expr = Expression::builder(ScientificFactory) + .number("1.23e-4")? + .operator("sin")? + .build()?; + + /// 3. Specialized Builder Pattern + /// + /// This encapsulate common expression patterns, so that we can write our + /// expressions even more consicely + let expr = Expression::builder(StandardFactory) + .binary_op("2", "+", "3")? + .build()?; + let expr = Expression::builder(ScientificFactory) + .function("sin", "0.5")? + .build()?; + + /// 4. Prototype Pattern + /// + /// The quadratic_template method creates a prototype with placeholder + /// coefficients. We can clone this template and modify the coefficients. + let expr = Expression::quadratic_template(StandardFactory)?.build()?; + let expr2 = expr.clone(); + expr2.set_coefficient(2, -4.0)?; + /// The sub expression can be cloned and inserted into larger expressions + let squared = SubExpression::new( + vec![ + Token::variable("x".to_string()), + Token::Operator(StandardOperator(Operator::Power)), + Token::Number(StandardNumber(2.0)), + ], + StandardFactory, + ); + /// prototype patterns that use Clone trait naturally: + let expr1 = Expression::builder(StandardFactory) + .extend(squared.clone().tokens) + .operator("+")? + .number("1")? + .build()?; + let expr2 = Expression::builder(StandardFactory) + .number("2")? + .operator("*")? + .extend(squared.tokens) + .build()?; + /// use Default trait + let default_calc = Calculator::new(StandardFactory); + let scientific_calc = + Calculator::with_config(ScientificFactory, CalculatorConfig::scientific()); + + Ok(()) +} diff --git a/design_patterns_in_rust/good_calculator/src/number.rs b/design_patterns_in_rust/creational_patterns/src/number.rs diff --git a/design_patterns_in_rust/good_calculator/src/operator.rs b/design_patterns_in_rust/creational_patterns/src/operator.rs diff --git a/design_patterns_in_rust/good_calculator/src/token.rs b/design_patterns_in_rust/creational_patterns/src/token.rs diff --git a/design_patterns_in_rust/good_calculator/Cargo.lock b/design_patterns_in_rust/good_calculator/Cargo.lock @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "good_calculator" -version = "0.1.0" diff --git a/design_patterns_in_rust/good_calculator/Cargo.toml b/design_patterns_in_rust/good_calculator/Cargo.toml @@ -1,6 +0,0 @@ -[package] -name = "good_calculator" -version = "0.1.0" -edition = "2024" - -[dependencies] diff --git a/design_patterns_in_rust/good_calculator/src/main.rs b/design_patterns_in_rust/good_calculator/src/main.rs @@ -1,92 +0,0 @@ -use good_calculator::{ - builder::{Expression, SubExpression}, - calculator::{Calculator, CalculatorConfig}, - factory::{ScientificFactory, StandardFactory}, - number::StandardNumber, - operator::{Operator, StandardOperator}, - token::Token, -}; - -fn main() -> Result<(), String> { - // 1. Enum in Vec - // - // In Rust Vec has to be a single type, the Token enum conviniently allows - // this by providing a unified type that can hold any token variant - // let numbers = [ - // Token::number(6.0), - // Token::operator(Operator::Add), - // Token::Number(3.0) - // ] - - /// 2. Abstract Factory - /// - /// With the abstract factory pattern, we can create different kinds of - /// calculators just by specifying which factory we would like to use: - let standard_calc = Calculator::new(StandardFactory); - let scientific_calc = Calculator::new(ScientificFactory); - - /// 3. Builder Pattern - /// - /// This is how the Builder Pattern and Abstract Factory Pattern compose: - /// the builder delegates token creation to whichever factory it was given - // With standard calculator factory - let expr = Expression::builder(StandardFactory) - .number("2")? - .operator("+")? - .open_paren() - .number("3")? - .operator("*")? - .number("4")? - .close_paren()? - .build(); - // With scientific calculator factory - let expr = Expression::builder(ScientificFactory) - .number("1.23e-4")? - .operator("sin")? - .build()?; - - /// 3. Specialized Builder Pattern - /// - /// This encapsulate common expression patterns, so that we can write our - /// expressions even more consicely - let expr = Expression::builder(StandardFactory) - .binary_op("2", "+", "3")? - .build()?; - let expr = Expression::builder(ScientificFactory) - .function("sin", "0.5")? - .build()?; - - /// 4. Prototype Pattern - /// - /// The quadratic_template method creates a prototype with placeholder - /// coefficients. We can clone this template and modify the coefficients. - let expr = Expression::quadratic_template(StandardFactory)?.build()?; - let expr2 = expr.clone(); - expr2.set_coefficient(2, -4.0)?; - /// The sub expression can be cloned and inserted into larger expressions - let squared = SubExpression::new( - vec![ - Token::variable("x".to_string()), - Token::Operator(StandardOperator(Operator::Power)), - Token::Number(StandardNumber(2.0)), - ], - StandardFactory, - ); - /// prototype patterns that use Clone trait naturally: - let expr1 = Expression::builder(StandardFactory) - .extend(squared.clone().tokens) - .operator("+")? - .number("1")? - .build()?; - let expr2 = Expression::builder(StandardFactory) - .number("2")? - .operator("*")? - .extend(squared.tokens) - .build()?; - /// use Default trait - let default_calc = Calculator::new(StandardFactory); - let scientific_calc = - Calculator::with_config(ScientificFactory, CalculatorConfig::scientific()); - - Ok(()) -} diff --git a/design_patterns_in_rust/good_calculator_2/Cargo.lock b/design_patterns_in_rust/good_calculator_2/Cargo.lock @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "good_calculator" -version = "0.1.0" diff --git a/design_patterns_in_rust/good_calculator_2/Cargo.toml b/design_patterns_in_rust/good_calculator_2/Cargo.toml @@ -1,6 +0,0 @@ -[package] -name = "good_calculator" -version = "0.1.0" -edition = "2024" - -[dependencies] diff --git a/design_patterns_in_rust/good_calculator_2/src/main.rs b/design_patterns_in_rust/good_calculator_2/src/main.rs @@ -1,43 +0,0 @@ -use std::collections::HashMap; - -use good_calculator::{ - BinaryOperation, CachingExpression, ConsoleLogger, Expression, LoggingExpression, - NumberExpression, Operator, TimingExpression, -}; - -fn main() -> Result<(), String> { - /// Structural Patterns - /// - /// 1. Decorator Pattern - let expr = Box::new(NumberExpression::new(42.0)); - let cached = Box::new(CachingExpression::new(expr)); - let timed = Box::new(TimingExpression::new(cached)); - let logged = LoggingExpression::new(timed, Box::new(ConsoleLogger)); - // When evaluate is called on the outermost decorator, the call flows through - // each layer. The order of wrapping matters. - let result = logged.evaluate(&HashMap::new()); - - /// 2. Composite Pattern - /// Because all nodes implement Expression, Decorator Pattern work seamlessly - /// with Composite Pattern trees. - /// The tree structure encodes operator precedence directly: - let multiply = Box::new(BinaryOperation::new( - Box::new(NumberExpression::new(3.0)), - Box::new(NumberExpression::new(4.0)), - Operator::Multiply, - )); - let add = Box::new(BinaryOperation::new( - Box::new(NumberExpression::new(2.0)), - multiply, - Operator::Add, - )); - /// Evaluating the tree is a single method call: - let variables = HashMap::new(); - println!("Expression: {}", add.to_string()); - match add.evaluate(&variables) { - Ok(result) => println!("Result: {}", result), - Err(error) => eprintln!("Error: {}", error), - } - - Ok(()) -} diff --git a/design_patterns_in_rust/index.md b/design_patterns_in_rust/index.md @@ -70,7 +70,7 @@ The advantages the better example offers that the bad examples don't: - Prototype Pattern > [!info] Source Code: -> [exercises/design_patterns_in_rust/good_calculator/src/main.rs](https://github.com/ling0x/notes/blob/main/content/exercises/design_patterns_in_rust/good_calculator/src/main.rs) +> [exercises/design_patterns_in_rust/creational_patterns/src/main.rs](https://github.com/ling0x/notes/blob/main/content/exercises/design_patterns_in_rust/creational_patterns/src/main.rs) ### Structural patterns @@ -81,4 +81,4 @@ The advantages the better example offers that the bad examples don't: - The Bridge pattern > [!info] Source Code: -> [exercises/design_patterns_in_rust/good_calculator_2/src/main.rs](https://github.com/ling0x/notes/blob/main/content/exercises/design_patterns_in_rust/good_calculator_2/src/main.rs) +> [exercises/design_patterns_in_rust/structural_patterns/src/main.rs](https://github.com/ling0x/notes/blob/main/content/exercises/design_patterns_in_rust/structural_patterns/src/main.rs) diff --git a/design_patterns_in_rust/structural_patterns/Cargo.lock b/design_patterns_in_rust/structural_patterns/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "structural_patterns" +version = "0.1.0" diff --git a/design_patterns_in_rust/structural_patterns/Cargo.toml b/design_patterns_in_rust/structural_patterns/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "structural_patterns" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/design_patterns_in_rust/good_calculator_2/src/adapters.rs b/design_patterns_in_rust/structural_patterns/src/adapters.rs diff --git a/design_patterns_in_rust/good_calculator_2/src/bridge_pattern.rs b/design_patterns_in_rust/structural_patterns/src/bridge_pattern.rs diff --git a/design_patterns_in_rust/good_calculator_2/src/builder.rs b/design_patterns_in_rust/structural_patterns/src/builder.rs diff --git a/design_patterns_in_rust/good_calculator_2/src/calculator.rs b/design_patterns_in_rust/structural_patterns/src/calculator.rs diff --git a/design_patterns_in_rust/good_calculator_2/src/facade.rs b/design_patterns_in_rust/structural_patterns/src/facade.rs diff --git a/design_patterns_in_rust/good_calculator_2/src/factory.rs b/design_patterns_in_rust/structural_patterns/src/factory.rs diff --git a/design_patterns_in_rust/good_calculator_2/src/lib.rs b/design_patterns_in_rust/structural_patterns/src/lib.rs diff --git a/design_patterns_in_rust/structural_patterns/src/main.rs b/design_patterns_in_rust/structural_patterns/src/main.rs @@ -0,0 +1,43 @@ +use std::collections::HashMap; + +use structural_patterns::{ + BinaryOperation, CachingExpression, ConsoleLogger, Expression, LoggingExpression, + NumberExpression, Operator, TimingExpression, +}; + +fn main() -> Result<(), String> { + /// Structural Patterns + /// + /// 1. Decorator Pattern + let expr = Box::new(NumberExpression::new(42.0)); + let cached = Box::new(CachingExpression::new(expr)); + let timed = Box::new(TimingExpression::new(cached)); + let logged = LoggingExpression::new(timed, Box::new(ConsoleLogger)); + // When evaluate is called on the outermost decorator, the call flows through + // each layer. The order of wrapping matters. + let result = logged.evaluate(&HashMap::new()); + + /// 2. Composite Pattern + /// Because all nodes implement Expression, Decorator Pattern work seamlessly + /// with Composite Pattern trees. + /// The tree structure encodes operator precedence directly: + let multiply = Box::new(BinaryOperation::new( + Box::new(NumberExpression::new(3.0)), + Box::new(NumberExpression::new(4.0)), + Operator::Multiply, + )); + let add = Box::new(BinaryOperation::new( + Box::new(NumberExpression::new(2.0)), + multiply, + Operator::Add, + )); + /// Evaluating the tree is a single method call: + let variables = HashMap::new(); + println!("Expression: {}", add.to_string()); + match add.evaluate(&variables) { + Ok(result) => println!("Result: {}", result), + Err(error) => eprintln!("Error: {}", error), + } + + Ok(()) +} diff --git a/design_patterns_in_rust/good_calculator_2/src/number.rs b/design_patterns_in_rust/structural_patterns/src/number.rs diff --git a/design_patterns_in_rust/good_calculator_2/src/operator.rs b/design_patterns_in_rust/structural_patterns/src/operator.rs diff --git a/design_patterns_in_rust/good_calculator_2/src/token.rs b/design_patterns_in_rust/structural_patterns/src/token.rs diff --git a/design_patterns_in_rust/good_calculator_2/src/utilities.rs b/design_patterns_in_rust/structural_patterns/src/utilities.rs