use std::sync::Arc;
use std::time::Instant;
use eryx::{
InProcessSession, PythonExecutor, PythonStateSnapshot, Sandbox, Session, SessionExecutor,
};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
println!("=== Session Reuse Examples ===\n");
let sandbox = Sandbox::embedded().build()?;
let executor = Arc::new(PythonExecutor::from_embedded_runtime()?);
demo_session_executor(&executor).await?;
println!();
demo_in_process_session(&sandbox).await?;
println!();
demo_state_snapshots(&executor).await?;
println!();
benchmark_comparison(&sandbox, &executor).await?;
Ok(())
}
async fn demo_session_executor(executor: &Arc<PythonExecutor>) -> anyhow::Result<()> {
println!("--- SessionExecutor (Core) ---");
println!("Keeps WASM Store and Instance alive between executions.");
println!("This is the foundation for all session types.\n");
let mut session = SessionExecutor::new(executor.clone(), &[]).await?;
let start = Instant::now();
let output = session
.execute("x = 1")
.run()
.await
.map_err(|e| anyhow::anyhow!(e))?;
println!(
"Execute 'x = 1': '{}' (execution #{})",
output.stdout,
session.execution_count()
);
let output = session
.execute("y = 2")
.run()
.await
.map_err(|e| anyhow::anyhow!(e))?;
println!(
"Execute 'y = 2': '{}' (execution #{})",
output.stdout,
session.execution_count()
);
let output = session
.execute("print(x + y)")
.run()
.await
.map_err(|e| anyhow::anyhow!(e))?;
println!(
"Execute 'print(x + y)': '{}' (execution #{})",
output.stdout,
session.execution_count()
);
let total = start.elapsed();
println!("\nTotal time for 3 executions: {:?}", total);
println!("Average per execution: {:?}", total / 3);
session.reset(&[]).await?;
println!(
"\nAfter reset, execution count: {}",
session.execution_count()
);
Ok(())
}
async fn demo_in_process_session(sandbox: &Sandbox) -> anyhow::Result<()> {
println!("--- InProcessSession (High-Level API) ---");
println!("Wraps SessionExecutor for easy state persistence.\n");
let mut session = InProcessSession::new(sandbox).await?;
let start = Instant::now();
let result = session.execute("x = 1").await?;
println!(
"Execute 'x = 1': '{}' ({:?})",
result.stdout, result.stats.duration
);
let result = session.execute("y = 2").await?;
println!(
"Execute 'y = 2': '{}' ({:?})",
result.stdout, result.stats.duration
);
let result = session.execute("print(x + y)").await?;
println!(
"Execute 'print(x + y)': '{}' ({:?})",
result.stdout, result.stats.duration
);
let total = start.elapsed();
println!("\nTotal time for 3 executions: {:?}", total);
println!("Execution count: {}", session.execution_count());
session.reset().await?;
println!("\nAfter reset, session state is cleared.");
Ok(())
}
async fn demo_state_snapshots(executor: &Arc<PythonExecutor>) -> anyhow::Result<()> {
println!("--- State Snapshots ---");
println!("Capture and restore Python state using pickle serialization.");
println!("Enables state persistence across process restarts.\n");
let mut session = SessionExecutor::new(executor.clone(), &[]).await?;
session
.execute("x = 10")
.run()
.await
.map_err(|e| anyhow::anyhow!(e))?;
session
.execute("y = 20")
.run()
.await
.map_err(|e| anyhow::anyhow!(e))?;
session
.execute("data = [1, 2, 3, 4, 5]")
.run()
.await
.map_err(|e| anyhow::anyhow!(e))?;
println!("Created state: x=10, y=20, data=[1,2,3,4,5]");
let snapshot_start = Instant::now();
let snapshot = session.snapshot_state().await?;
let snapshot_duration = snapshot_start.elapsed();
println!("\nSnapshot captured:");
println!(" - Size: {} bytes", snapshot.size());
println!(" - Capture time: {:?}", snapshot_duration);
println!(" - Timestamp: {}", snapshot.metadata().timestamp_ms);
let bytes = snapshot.to_bytes();
println!(" - Serialized size: {} bytes", bytes.len());
session
.execute("x = 999")
.run()
.await
.map_err(|e| anyhow::anyhow!(e))?;
let output = session
.execute("print(f'x after modification: {x}')")
.run()
.await
.map_err(|e| anyhow::anyhow!(e))?;
println!("\n{}", output.stdout);
let restore_start = Instant::now();
session.restore_state(&snapshot).await?;
let restore_duration = restore_start.elapsed();
let output = session
.execute("print(f'x after restore: {x}')")
.run()
.await
.map_err(|e| anyhow::anyhow!(e))?;
println!("{}", output.stdout);
println!("Restore time: {:?}", restore_duration);
println!("\nSimulating load from storage...");
let restored_snapshot = PythonStateSnapshot::from_bytes(&bytes)?;
println!(
"Deserialized snapshot: {} bytes, timestamp {}",
restored_snapshot.size(),
restored_snapshot.metadata().timestamp_ms
);
session.clear_state().await?;
println!("State cleared");
session.restore_state(&restored_snapshot).await?;
let output = session
.execute("print(f'After clear+restore: x={x}, y={y}, data={data}')")
.run()
.await
.map_err(|e| anyhow::anyhow!(e))?;
println!("{}", output.stdout);
Ok(())
}
async fn benchmark_comparison(
sandbox: &Sandbox,
executor: &Arc<PythonExecutor>,
) -> anyhow::Result<()> {
println!("--- Performance Comparison ---\n");
const ITERATIONS: usize = 5;
let start = Instant::now();
for _ in 0..ITERATIONS {
sandbox.execute("x = 1").await?;
}
let regular_time = start.elapsed();
let mut session_executor = SessionExecutor::new(executor.clone(), &[]).await?;
let start = Instant::now();
for _ in 0..ITERATIONS {
session_executor
.execute("x = 1")
.run()
.await
.map_err(|e| anyhow::anyhow!(e))?;
}
let executor_time = start.elapsed();
let mut session = InProcessSession::new(sandbox).await?;
let start = Instant::now();
for _ in 0..ITERATIONS {
session.execute("x = 1").await?;
}
let session_time = start.elapsed();
println!(
"Regular sandbox ({} executions): {:?}",
ITERATIONS, regular_time
);
println!(
"SessionExecutor ({} executions): {:?}",
ITERATIONS, executor_time
);
println!(
"InProcessSession ({} executions): {:?}",
ITERATIONS, session_time
);
if executor_time.as_nanos() > 0 {
println!(
"\nSessionExecutor speedup vs regular: {:.2}x",
regular_time.as_secs_f64() / executor_time.as_secs_f64()
);
}
println!("\nNote: SessionExecutor persists state between executions.");
println!("Use snapshot_state()/restore_state() for serialization.");
println!("See plans/SANDBOX_REUSE.md for implementation details.");
Ok(())
}