Skip to content

Instantly share code, notes, and snippets.

@mooreniemi
Created September 23, 2024 03:59
Show Gist options
  • Save mooreniemi/5779706e4d6d787a1ca63b36fa7fb005 to your computer and use it in GitHub Desktop.
Save mooreniemi/5779706e4d6d787a1ca63b36fa7fb005 to your computer and use it in GitHub Desktop.
use std::time::Instant;
// Define a trait with a simple operation
trait Operation {
fn execute(&self, input: i32) -> i32;
}
// Implement the trait for a specific type
struct AddOperation;
impl Operation for AddOperation {
fn execute(&self, input: i32) -> i32 {
input + 1
}
}
// Benchmark using dynamic dispatch (dyn)
fn benchmark_dynamic_dispatch(op: &dyn Operation, iterations: i32) -> i32 {
let mut result = 0;
for _ in 0..iterations {
result = op.execute(result);
}
result
}
// Benchmark using static dispatch (generics)
fn benchmark_static_dispatch<T: Operation>(op: &T, iterations: i32) -> i32 {
let mut result = 0;
for _ in 0..iterations {
result = op.execute(result);
}
result
}
// Helper function to run trials
fn run_benchmark(iterations: i32) {
let op = AddOperation;
println!("\nRunning benchmark with {} iterations:", iterations);
// Benchmark dynamic dispatch
let start = Instant::now();
let result_dynamic = benchmark_dynamic_dispatch(&op, iterations);
let duration_dynamic = start.elapsed();
println!(
"Dynamic Dispatch Result: {}, Time: {:?}",
result_dynamic, duration_dynamic
);
// Benchmark static dispatch
let start = Instant::now();
let result_static = benchmark_static_dispatch(&op, iterations);
let duration_static = start.elapsed();
println!(
"Static Dispatch Result: {}, Time: {:?}",
result_static, duration_static
);
println!(
"Delta (Dynamic - Static): {:?}",
duration_dynamic.checked_sub(duration_static)
);
}
/*
An example run:
Running benchmark with 100000 iterations:
Dynamic Dispatch Result: 100000, Time: 1.71875ms
Static Dispatch Result: 100000, Time: 1.716292ms
Delta (Dynamic - Static): 2.458µs
Running benchmark with 1000000 iterations:
Dynamic Dispatch Result: 1000000, Time: 13.648916ms
Static Dispatch Result: 1000000, Time: 10.246375ms
Delta (Dynamic - Static): 3.402541ms
Running benchmark with 10000000 iterations:
Dynamic Dispatch Result: 10000000, Time: 57.021833ms
Static Dispatch Result: 10000000, Time: 37.303916ms
Delta (Dynamic - Static): 19.717917ms
Running benchmark with 100000000 iterations:
Dynamic Dispatch Result: 100000000, Time: 393.276125ms
Static Dispatch Result: 100000000, Time: 382.62025ms
Delta (Dynamic - Static): 10.655875ms
*/
fn main() {
// Run the benchmarks with different iteration counts
let trials = vec![100_000, 1_000_000, 10_000_000, 100_000_000];
for &iterations in &trials {
run_benchmark(iterations);
}
}
use rand::Rng;
use std::fs::File;
use std::io::{self, Read};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
// Define traits
trait Readable: Send + Sync {
fn read(&self);
}
trait Addable: Send + Sync {
fn add(&self, new_content: &str);
}
// Trait for content generation
trait ContentGenerator: Send {
fn get_new_content(&self) -> String;
}
// Random content generator
struct RandomContentGenerator;
impl ContentGenerator for RandomContentGenerator {
fn get_new_content(&self) -> String {
let random_number: u32 = rand::thread_rng().gen_range(1000..9999);
format!("Generated random content: {}\n", random_number)
}
}
// File content generator
struct FileContentGenerator {
file_path: String,
}
impl FileContentGenerator {
fn new(file_path: String) -> Self {
Self { file_path }
}
}
impl ContentGenerator for FileContentGenerator {
fn get_new_content(&self) -> String {
let mut file = File::open(&self.file_path).expect("Failed to open file");
let mut content = String::new();
file.read_to_string(&mut content)
.expect("Failed to read file");
format!("Content from file: {}\n", content)
}
}
// ImmutableFile only supports reading
struct ImmutableFile {
content: String,
}
impl ImmutableFile {
fn new(file_path: &str) -> io::Result<Self> {
let mut file = File::open(file_path)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(Self { content })
}
}
impl Readable for ImmutableFile {
fn read(&self) {
println!("Immutable Read: {}", self.content);
}
}
// MutableFile supports reading and adding content using Mutex for locking
struct MutableFile {
content: Arc<Mutex<String>>, // Mutex for thread-safe access
}
impl MutableFile {
fn new(file_path: &str) -> io::Result<Self> {
let mut file = File::open(file_path)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(Self {
content: Arc::new(Mutex::new(content)),
})
}
}
impl Readable for MutableFile {
fn read(&self) {
let content = self.content.lock().unwrap();
println!("Mutable Read: {}", content);
}
}
impl Addable for MutableFile {
fn add(&self, new_content: &str) {
let mut content = self.content.lock().unwrap();
content.push_str(new_content);
println!("Added content: {}", new_content);
}
}
// Enum to represent either an ImmutableFile or a MutableFile
#[derive(Clone)]
enum FileType {
Immutable(Arc<ImmutableFile>),
Mutable(Arc<MutableFile>),
}
// ReadEngine handles multiple files: one required and two optional
struct ReadEngine {
one: FileType,
two: Option<FileType>,
three: Option<FileType>,
}
impl ReadEngine {
fn new(one: FileType, two: Option<FileType>, three: Option<FileType>) -> Self {
Self { one, two, three }
}
fn read(&self) {
println!("Reading from file one:");
match &self.one {
FileType::Immutable(file) => file.read(),
FileType::Mutable(file) => file.read(),
}
if let Some(ref file) = self.two {
println!("Reading from file two:");
match file {
FileType::Immutable(file) => file.read(),
FileType::Mutable(file) => file.read(),
}
}
if let Some(ref file) = self.three {
println!("Reading from file three:");
match file {
FileType::Immutable(file) => file.read(),
FileType::Mutable(file) => file.read(),
}
}
}
}
// AddEngine using dynamic dispatch for Addable
struct AddEngine {
one: Arc<dyn Addable>,
two: Option<Arc<dyn Addable>>,
three: Option<Arc<dyn Addable>>,
content_generator: Box<dyn ContentGenerator>,
}
impl AddEngine {
fn new(
one: Arc<dyn Addable>,
two: Option<Arc<dyn Addable>>,
three: Option<Arc<dyn Addable>>,
content_generator: Box<dyn ContentGenerator>,
) -> Self {
Self {
one,
two,
three,
content_generator,
}
}
fn add(&self, new_content: &str) {
println!("Adding to file one:");
self.one.add(new_content);
if let Some(ref file) = self.two {
println!("Adding to file two:");
file.add(new_content);
}
if let Some(ref file) = self.three {
println!("Adding to file three:");
file.add(new_content);
}
}
fn start_polling(self) {
let one = Arc::clone(&self.one);
let two = self.two.clone();
let three = self.three.clone();
let content_generator = self.content_generator;
thread::spawn(move || loop {
let new_content = content_generator.get_new_content();
println!("Polling: Adding to file one:");
one.add(&new_content);
if let Some(ref file) = two {
println!("Polling: Adding to file two:");
file.add(&new_content);
}
if let Some(ref file) = three {
println!("Polling: Adding to file three:");
file.add(&new_content);
}
thread::sleep(Duration::from_secs(2)); // Polling interval
});
}
}
// Now use `FileType` for ReadEngine and AddEngine creation
fn create_engines(
mode: &str,
file_paths: &[&str],
generator: Box<dyn ContentGenerator>,
) -> (ReadEngine, Option<AddEngine>) {
let read_one: FileType = match mode {
"immutable" => FileType::Immutable(Arc::new(
ImmutableFile::new(file_paths[0]).expect("Failed to load file"),
)),
"mutable" => FileType::Mutable(Arc::new(
MutableFile::new(file_paths[0]).expect("Failed to load file"),
)),
_ => panic!("Invalid mode! Use 'immutable' or 'mutable'."),
};
let read_two = if file_paths.len() > 1 {
Some(match mode {
"immutable" => FileType::Immutable(Arc::new(
ImmutableFile::new(file_paths[1]).expect("Failed to load file"),
)),
"mutable" => FileType::Mutable(Arc::new(
MutableFile::new(file_paths[1]).expect("Failed to load file"),
)),
_ => panic!("Invalid mode! Use 'immutable' or 'mutable'."),
})
} else {
None
};
let read_three = if file_paths.len() > 2 {
Some(match mode {
"immutable" => FileType::Immutable(Arc::new(
ImmutableFile::new(file_paths[2]).expect("Failed to load file"),
)),
"mutable" => FileType::Mutable(Arc::new(
MutableFile::new(file_paths[2]).expect("Failed to load file"),
)),
_ => panic!("Invalid mode! Use 'immutable' or 'mutable'."),
})
} else {
None
};
let read_engine = ReadEngine::new(read_one.clone(), read_two.clone(), read_three.clone());
let add_engine = if mode == "mutable" {
Some(AddEngine::new(
match read_one {
FileType::Mutable(file) => file as Arc<dyn Addable>,
_ => panic!("Invalid state"),
},
read_two.and_then(|f| match f {
FileType::Mutable(file) => Some(file as Arc<dyn Addable>),
_ => None,
}),
read_three.and_then(|f| match f {
FileType::Mutable(file) => Some(file as Arc<dyn Addable>),
_ => None,
}),
generator,
))
} else {
None
};
(read_engine, add_engine)
}
fn main() {
let mode = std::env::args()
.nth(1)
.expect("No mode provided! Use 'immutable' or 'mutable'");
let generator_type = std::env::args()
.nth(2)
.expect("No content generator type provided! Use 'random' or 'file'");
// File paths
let file_path_one = "/tmp/example.txt";
let file_path_two = "/tmp/example.txt";
let file_path_three = "/tmp/example.txt";
// Include optional files based on feature flags
let include_file_two = std::env::args().nth(3).as_deref() == Some("file2");
let include_file_three = std::env::args().nth(4).as_deref() == Some("file3");
// Add file paths to the vector based on whether optional files are included
let mut file_paths = vec![file_path_one]; // File one is always required
if include_file_two {
file_paths.push(file_path_two);
}
if include_file_three {
file_paths.push(file_path_three);
}
// Choose the content generator based on user input
let generator: Box<dyn ContentGenerator> = match generator_type.as_str() {
"file" => Box::new(FileContentGenerator::new(file_path_one.to_string())),
"random" => Box::new(RandomContentGenerator),
_ => panic!("Invalid content generator type! Use 'random' or 'file'."),
};
// Create engines based on the mode (immutable or mutable) and file paths
let (read_engine, add_engine) = create_engines(&mode, &file_paths, generator);
// Start reading from files in a separate thread
let read_thread = thread::spawn(move || {
for _ in 0..5 {
read_engine.read();
thread::sleep(Duration::from_secs(1));
}
});
// If we're in mutable mode, start polling for new content and adding it to the files
if let Some(add_engine) = add_engine {
add_engine.start_polling(); // Start polling for new content
}
// Wait for the reading thread to finish
read_thread.join().unwrap();
}
use rand::Rng;
use std::fs::File;
use std::io::{self, Read};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
// Define traits
trait Readable: Send + Sync {
fn read(&self);
}
trait Addable: Send + Sync {
fn add(&self, new_content: &str);
}
// Trait for content generation
trait ContentGenerator: Send {
fn get_new_content(&self) -> String;
}
// Random content generator
struct RandomContentGenerator;
impl ContentGenerator for RandomContentGenerator {
fn get_new_content(&self) -> String {
let random_number: u32 = rand::thread_rng().gen_range(1000..9999);
format!("Generated random content: {}\n", random_number)
}
}
// File content generator
struct FileContentGenerator {
file_path: String,
}
impl FileContentGenerator {
fn new(file_path: String) -> Self {
Self { file_path }
}
}
impl ContentGenerator for FileContentGenerator {
fn get_new_content(&self) -> String {
let mut file = File::open(&self.file_path).expect("Failed to open file");
let mut content = String::new();
file.read_to_string(&mut content)
.expect("Failed to read file");
format!("Content from file: {}\n", content)
}
}
// ------------------- FILE IMPLEMENTATION -------------------
// ImmutableFile for immutable mode
#[cfg(feature = "immutable")]
pub struct ImmutableFile {
content: String,
}
#[cfg(feature = "immutable")]
impl ImmutableFile {
pub fn new(file_path: &str) -> io::Result<Self> {
let mut file = File::open(file_path)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(Self { content })
}
}
#[cfg(feature = "immutable")]
impl Readable for ImmutableFile {
fn read(&self) {
println!("Immutable Read: {}", self.content);
}
}
// MutableFile for mutable mode
#[cfg(feature = "mutable")]
pub struct MutableFile {
content: Arc<Mutex<String>>,
}
#[cfg(feature = "mutable")]
impl MutableFile {
pub fn new(file_path: &str) -> io::Result<Self> {
let mut file = File::open(file_path)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(Self {
content: Arc::new(Mutex::new(content)),
})
}
}
#[cfg(feature = "mutable")]
impl Readable for MutableFile {
fn read(&self) {
let content = self.content.lock().unwrap();
println!("Mutable Read: {}", content);
}
}
#[cfg(feature = "mutable")]
impl Addable for MutableFile {
fn add(&self, new_content: &str) {
let mut content = self.content.lock().unwrap();
content.push_str(new_content);
println!("Added content: {}", new_content);
}
}
// ------------------- ENGINE IMPLEMENTATION -------------------
// ReadEngine handles multiple files: one required and two optional
struct ReadEngine {
one: Arc<dyn Readable>,
two: Option<Arc<dyn Readable>>,
three: Option<Arc<dyn Readable>>,
}
impl ReadEngine {
fn new(
one: Arc<dyn Readable>,
two: Option<Arc<dyn Readable>>,
three: Option<Arc<dyn Readable>>,
) -> Self {
Self { one, two, three }
}
fn read(&self) {
println!("Reading from file one:");
self.one.read();
if let Some(ref file) = self.two {
println!("Reading from file two:");
file.read();
}
if let Some(ref file) = self.three {
println!("Reading from file three:");
file.read();
}
}
}
// AddEngine handles multiple files: one required and two optional
struct AddEngine {
one: Arc<dyn Addable>,
two: Option<Arc<dyn Addable>>,
three: Option<Arc<dyn Addable>>,
content_generator: Box<dyn ContentGenerator>,
}
impl AddEngine {
fn new(
one: Arc<dyn Addable>,
two: Option<Arc<dyn Addable>>,
three: Option<Arc<dyn Addable>>,
content_generator: Box<dyn ContentGenerator>,
) -> Self {
Self {
one,
two,
three,
content_generator,
}
}
fn add(&self, new_content: &str) {
println!("Adding to file one:");
self.one.add(new_content);
if let Some(ref file) = self.two {
println!("Adding to file two:");
file.add(new_content);
}
if let Some(ref file) = self.three {
println!("Adding to file three:");
file.add(new_content);
}
}
fn start_polling(self) {
let one = Arc::clone(&self.one);
let two = self.two.clone();
let three = self.three.clone();
let content_generator = self.content_generator;
thread::spawn(move || loop {
let new_content = content_generator.get_new_content();
println!("Polling: Adding to file one:");
one.add(&new_content);
if let Some(ref file) = two {
println!("Polling: Adding to file two:");
file.add(&new_content);
}
if let Some(ref file) = three {
println!("Polling: Adding to file three:");
file.add(&new_content);
}
thread::sleep(Duration::from_secs(2)); // Polling interval
});
}
}
// Create engines
fn create_engines(
file_paths: &[&str],
generator: Box<dyn ContentGenerator>,
) -> (ReadEngine, Option<AddEngine>) {
#[cfg(feature = "immutable")]
{
let one = Arc::new(ImmutableFile::new(file_paths[0]).expect("Failed to load file"))
as Arc<dyn Readable>;
let two = if file_paths.len() > 1 {
Some(
Arc::new(ImmutableFile::new(file_paths[1]).expect("Failed to load file"))
as Arc<dyn Readable>,
)
} else {
None
};
let three = if file_paths.len() > 2 {
Some(
Arc::new(ImmutableFile::new(file_paths[2]).expect("Failed to load file"))
as Arc<dyn Readable>,
)
} else {
None
};
(ReadEngine::new(one, two, three), None)
}
#[cfg(feature = "mutable")]
{
let one = Arc::new(MutableFile::new(file_paths[0]).expect("Failed to load file"));
let one_add = Arc::clone(&one) as Arc<dyn Addable>;
let two = if file_paths.len() > 1 {
let file = Arc::new(MutableFile::new(file_paths[1]).expect("Failed to load file"));
(
Some(Arc::clone(&file) as Arc<dyn Readable>),
Some(Arc::clone(&file) as Arc<dyn Addable>),
)
} else {
(None, None)
};
let three = if file_paths.len() > 2 {
let file = Arc::new(MutableFile::new(file_paths[2]).expect("Failed to load file"));
(
Some(Arc::clone(&file) as Arc<dyn Readable>),
Some(Arc::clone(&file) as Arc<dyn Addable>),
)
} else {
(None, None)
};
let read_engine = ReadEngine::new(one.clone() as Arc<dyn Readable>, two.0, three.0);
let add_engine = AddEngine::new(one_add, two.1, three.1, generator);
(read_engine, Some(add_engine))
}
}
/*
Run with the feature gating:
```text
cargo run --example switching_seven --features mutable -- random
cargo run --example switching_seven --features immutable --no-default-features -- random
```
Expects `Cargo.toml`:
```text
[features]
default = ["mutable"]
mutable = []
immutable = []
```
*/
fn main() {
let generator_type = std::env::args()
.nth(1)
.expect("No content generator type provided! Use 'random' or 'file'");
// File paths
let file_path_one = "/tmp/example_one.txt";
let file_path_two = "/tmp/example_two.txt";
let file_path_three = "/tmp/example_three.txt";
// Include optional files based on feature flags
let include_file_two = std::env::args().nth(2).as_deref() == Some("file2");
let include_file_three = std::env::args().nth(3).as_deref() == Some("file3");
// Add file paths to the vector based on whether optional files are included
let mut file_paths = vec![file_path_one]; // File one is always required
if include_file_two {
file_paths.push(file_path_two);
}
if include_file_three {
file_paths.push(file_path_three);
}
// Choose the content generator based on user input
// Choose the content generator based on user input
let generator: Box<dyn ContentGenerator> = match generator_type.as_str() {
"file" => Box::new(FileContentGenerator::new(file_path_one.to_string())),
"random" => Box::new(RandomContentGenerator),
_ => panic!("Invalid content generator type! Use 'random' or 'file'."),
};
// Create engines based on the feature enabled (either mutable or immutable)
let (read_engine, add_engine) = create_engines(&file_paths, generator);
// Start reading from files in a separate thread
let read_thread = thread::spawn(move || {
for _ in 0..5 {
read_engine.read();
thread::sleep(Duration::from_secs(1));
}
});
// If we're in mutable mode, start polling for new content and adding it to the files
#[cfg(feature = "mutable")]
if let Some(add_engine) = add_engine {
add_engine.start_polling(); // Start polling for new content
}
// Wait for the reading thread to finish
read_thread.join().unwrap();
}
use rand::Rng;
use std::fs::File;
use std::io::{self, Read};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
// Define traits
trait Readable: Send + Sync {
fn read(&self);
}
trait Addable: Send + Sync {
fn add(&self, new_content: &str);
}
// Trait for content generation
trait ContentGenerator: Send {
fn get_new_content(&self) -> String;
}
// Random content generator
struct RandomContentGenerator;
impl ContentGenerator for RandomContentGenerator {
fn get_new_content(&self) -> String {
let random_number: u32 = rand::thread_rng().gen_range(1000..9999);
format!("Generated random content: {}\n", random_number)
}
}
// File content generator
struct FileContentGenerator {
file_path: String,
}
impl FileContentGenerator {
fn new(file_path: String) -> Self {
Self { file_path }
}
}
impl ContentGenerator for FileContentGenerator {
fn get_new_content(&self) -> String {
let mut file = File::open(&self.file_path).expect("Failed to open file");
let mut content = String::new();
file.read_to_string(&mut content)
.expect("Failed to read file");
format!("Content from file: {}\n", content)
}
}
// ImmutableFile only supports reading
struct ImmutableFile {
content: String,
}
impl ImmutableFile {
fn new(file_path: &str) -> io::Result<Self> {
let mut file = File::open(file_path)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(Self { content })
}
}
impl Readable for ImmutableFile {
fn read(&self) {
println!("Immutable Read: {}", self.content);
}
}
// MutableFile supports reading and adding content using Mutex for locking
struct MutableFile {
content: Arc<Mutex<String>>, // Mutex for thread-safe access
}
impl MutableFile {
fn new(file_path: &str) -> io::Result<Self> {
let mut file = File::open(file_path)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(Self {
content: Arc::new(Mutex::new(content)),
})
}
}
impl Readable for MutableFile {
fn read(&self) {
let content = self.content.lock().unwrap();
println!("Mutable Read: {}", content);
}
}
impl Addable for MutableFile {
fn add(&self, new_content: &str) {
let mut content = self.content.lock().unwrap();
content.push_str(new_content);
println!("Added content: {}", new_content);
}
}
// ReadEngine handles multiple files: one required and two optional
struct ReadEngine {
one: Arc<dyn Readable>,
two: Option<Arc<dyn Readable>>,
three: Option<Arc<dyn Readable>>,
}
impl ReadEngine {
fn new(
one: Arc<dyn Readable>,
two: Option<Arc<dyn Readable>>,
three: Option<Arc<dyn Readable>>,
) -> Self {
Self { one, two, three }
}
fn read(&self) {
println!("Reading from file one:");
self.one.read();
if let Some(ref file) = self.two {
println!("Reading from file two:");
file.read();
}
if let Some(ref file) = self.three {
println!("Reading from file three:");
file.read();
}
}
}
// AddEngine handles multiple files: one required and two optional
struct AddEngine {
one: Arc<dyn Addable>,
two: Option<Arc<dyn Addable>>,
three: Option<Arc<dyn Addable>>,
content_generator: Box<dyn ContentGenerator>,
}
impl AddEngine {
fn new(
one: Arc<dyn Addable>,
two: Option<Arc<dyn Addable>>,
three: Option<Arc<dyn Addable>>,
content_generator: Box<dyn ContentGenerator>,
) -> Self {
Self {
one,
two,
three,
content_generator,
}
}
fn add(&self, new_content: &str) {
println!("Adding to file one:");
self.one.add(new_content);
if let Some(ref file) = self.two {
println!("Adding to file two:");
file.add(new_content);
}
if let Some(ref file) = self.three {
println!("Adding to file three:");
file.add(new_content);
}
}
fn start_polling(self) {
let one = Arc::clone(&self.one);
let two = self.two.clone();
let three = self.three.clone();
let content_generator = self.content_generator;
thread::spawn(move || loop {
let new_content = content_generator.get_new_content();
println!("Polling: Adding to file one:");
one.add(&new_content);
if let Some(ref file) = two {
println!("Polling: Adding to file two:");
file.add(&new_content);
}
if let Some(ref file) = three {
println!("Polling: Adding to file three:");
file.add(&new_content);
}
thread::sleep(Duration::from_secs(2)); // Polling interval
});
}
}
fn create_engines(
mode: &str,
file_paths: &[&str],
generator: Box<dyn ContentGenerator>,
) -> (ReadEngine, Option<AddEngine>) {
// Handle 'one' separately for immutable and mutable cases
let (read_one, add_one) = match mode {
"immutable" => {
let file = Arc::new(ImmutableFile::new(file_paths[0]).expect("Failed to load file"));
(file as Arc<dyn Readable>, None)
}
"mutable" => {
let file = Arc::new(MutableFile::new(file_paths[0]).expect("Failed to load file"));
(
Arc::clone(&file) as Arc<dyn Readable>,
Some(file as Arc<dyn Addable>),
)
}
_ => panic!("Invalid mode! Use 'immutable' or 'mutable'."),
};
// Handle 'two' if present
let (read_two, add_two) = if file_paths.len() > 1 {
match mode {
"immutable" => {
let file =
Arc::new(ImmutableFile::new(file_paths[1]).expect("Failed to load file"));
(Some(file as Arc<dyn Readable>), None)
}
"mutable" => {
let file = Arc::new(MutableFile::new(file_paths[1]).expect("Failed to load file"));
(
Some(Arc::clone(&file) as Arc<dyn Readable>),
Some(file as Arc<dyn Addable>),
)
}
_ => panic!("Invalid mode! Use 'immutable' or 'mutable'."),
}
} else {
(None, None)
};
// Handle 'three' if present
let (read_three, add_three) = if file_paths.len() > 2 {
match mode {
"immutable" => {
let file =
Arc::new(ImmutableFile::new(file_paths[2]).expect("Failed to load file"));
(Some(file as Arc<dyn Readable>), None)
}
"mutable" => {
let file = Arc::new(MutableFile::new(file_paths[2]).expect("Failed to load file"));
(
Some(Arc::clone(&file) as Arc<dyn Readable>),
Some(file as Arc<dyn Addable>),
)
}
_ => panic!("Invalid mode! Use 'immutable' or 'mutable'."),
}
} else {
(None, None)
};
// Create ReadEngine using the read files
let read_engine = ReadEngine::new(read_one, read_two, read_three);
// Create AddEngine only for mutable files
let add_engine = if mode == "mutable" {
Some(AddEngine::new(
add_one.expect("AddEngine requires at least one file"),
add_two,
add_three,
generator,
))
} else {
None
};
(read_engine, add_engine)
}
fn main() {
let mode = std::env::args()
.nth(1)
.expect("No mode provided! Use 'immutable' or 'mutable'");
let generator_type = std::env::args()
.nth(2)
.expect("No content generator type provided! Use 'random' or 'file'");
// File paths
let file_path_one = "/tmp/example.txt";
let file_path_two = "/tmp/example.txt";
let file_path_three = "/tmp/example.txt";
// Include optional files based on feature flags
let include_file_two = std::env::args().nth(3).as_deref() == Some("file2");
let include_file_three = std::env::args().nth(4).as_deref() == Some("file3");
// Add file paths to the vector based on whether optional files are included
let mut file_paths = vec![file_path_one]; // File one is always required
if include_file_two {
file_paths.push(file_path_two);
}
if include_file_three {
file_paths.push(file_path_three);
}
// Choose the content generator based on user input
let generator: Box<dyn ContentGenerator> = match generator_type.as_str() {
"file" => Box::new(FileContentGenerator::new(file_path_one.to_string())),
"random" => Box::new(RandomContentGenerator),
_ => panic!("Invalid content generator type! Use 'random' or 'file'."),
};
// Create engines based on the mode (immutable or mutable) and file paths
let (read_engine, add_engine) = create_engines(&mode, &file_paths, generator);
// Start reading from files in a separate thread
let read_thread = thread::spawn(move || {
for _ in 0..5 {
read_engine.read();
thread::sleep(Duration::from_secs(1));
}
});
// If we're in mutable mode, start polling for new content and adding it to the files
if let Some(add_engine) = add_engine {
add_engine.start_polling(); // Start polling for new content
}
// Wait for the reading thread to finish
read_thread.join().unwrap();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment