use ops::{wet_get_ref, wet_put_arc, wet_put_ref, wet_require_ref};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Reference Context Demo ===");
let mut wet = WetContext::new();
println!("\n1. Storing large data structure as reference...");
let large_dataset = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; wet_put_ref!(wet, large_dataset);
let dataset_ref: Option<Arc<Vec<i32>>> = wet_get_ref!(wet, large_dataset);
if let Some(data) = dataset_ref {
println!("Retrieved dataset: {:?}", &data[..5]); println!("Dataset size: {}", data.len());
}
println!("\n2. Sharing expensive computed objects...");
#[derive(Debug, Clone)]
struct ComputationResult {
matrix: Vec<Vec<f64>>,
_computation_time_ms: u64,
}
let expensive_result = ComputationResult {
matrix: vec![vec![1.0, 2.0, 3.0]; 100], _computation_time_ms: 5000, };
wet.insert_ref("computation_result", expensive_result.clone());
for i in 0..3 {
let result_ref: Option<Arc<ComputationResult>> = wet.get_ref("computation_result");
if let Some(result) = result_ref {
println!(
"Operation {} accessed result - matrix size: {}x{}",
i + 1,
result.matrix.len(),
result.matrix[0].len()
);
}
}
println!("\n3. Using require macro for mandatory references...");
let file_paths = vec![
"/tmp/file1.txt".to_string(),
"/tmp/file2.txt".to_string(),
"/tmp/file3.txt".to_string(),
];
wet_put_ref!(wet, file_paths);
let file_paths_result: Result<Arc<Vec<String>>, _> = wet_require_ref!(wet, file_paths);
match file_paths_result {
Ok(paths) => {
println!("Required file paths found: {} files", paths.len());
for path in paths.iter() {
println!(" - {}", path);
}
}
Err(e) => println!("Error: {}", e),
}
let missing_result: Result<Arc<Vec<String>>, _> = wet_require_ref!(wet, missing_paths);
match missing_result {
Ok(_) => println!("This shouldn't happen"),
Err(e) => println!("Expected error: {}", e),
}
println!("\n4. Type safety with references...");
wet.insert_ref("string_data", "Hello, World!".to_string());
let string_ref: Option<Arc<String>> = wet.get_ref("string_data");
if let Some(s) = string_ref {
println!("String data: {}", s);
}
let wrong_type: Option<Arc<i32>> = wet.get_ref("string_data");
println!("Wrong type retrieval result: {:?}", wrong_type);
println!("\n5. Memory sharing demonstration...");
let shared_data = Arc::new(vec![100, 200, 300, 400, 500]);
let original_ptr = Arc::as_ptr(&shared_data);
wet_put_arc!(wet, shared_data);
let retrieved: Option<Arc<Vec<i32>>> = wet_get_ref!(wet, shared_data);
if let Some(retrieved_data) = retrieved {
let retrieved_ptr = Arc::as_ptr(&retrieved_data);
println!("Original ptr: {:p}", original_ptr);
println!("Retrieved ptr: {:p}", retrieved_ptr);
println!("Same memory location: {}", original_ptr == retrieved_ptr);
println!("Reference count: {}", Arc::strong_count(&retrieved_data));
}
println!("\n6. Using wet context in an op...");
use ops::prelude::*;
struct DataProcessorOp;
#[async_trait]
impl Op<String> for DataProcessorOp {
async fn perform(&self, _dry: &mut DryContext, wet: &mut WetContext) -> OpResult<String> {
let data: Arc<Vec<i32>> = wet_require_ref!(wet, large_dataset)?;
let sum: i32 = data.iter().sum();
Ok(format!("Sum of {} elements: {}", data.len(), sum))
}
fn metadata(&self) -> OpMetadata {
OpMetadata::builder("DataProcessorOp")
.description("Processes data from wet context")
.build()
}
}
let mut dry = DryContext::new();
let processor = DataProcessorOp;
tokio::runtime::Runtime::new()?.block_on(async {
match processor.perform(&mut dry, &mut wet).await {
Ok(result) => println!("Op result: {}", result),
Err(e) => println!("Op error: {}", e),
}
});
println!("\n=== Demo Complete ===");
Ok(())
}