Skip to content

Commit 2d767a6

Browse files
Frostyclaude
andcommitted
Epic 8: Stories 8.1 & 8.2 - Prelude module and Quick-start API
Story 8.1: Add prelude module for convenient imports - Created src/prelude.rs with commonly used types - Updated hello_braille example to demonstrate prelude usage Story 8.2: Implement quick-start API for rapid prototyping - Added src/quick.rs with simplified high-level API - Created examples/quick_demo.rs demonstrating usage - Added benches/quick.rs for performance testing Published dotmax v0.1.0 to crates.io 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent f9a9186 commit 2d767a6

7 files changed

Lines changed: 1017 additions & 3 deletions

File tree

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ name = "image_processing"
9999
harness = false
100100
required-features = ["image"]
101101

102+
[[bench]]
103+
name = "quick"
104+
harness = false
105+
102106
# Examples requiring the 'image' feature
103107
[[example]]
104108
name = "compare_resize_filters"

benches/quick.rs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//! Benchmarks for the quick module (Story 8.2, AC9)
2+
//!
3+
//! Validates that quick functions add < 5ms overhead vs manual approach.
4+
//!
5+
//! These benchmarks compare:
6+
//! - quick::grid() vs BrailleGrid::new()
7+
//! - quick::load_image() vs manual ImageRenderer pipeline
8+
//!
9+
//! Performance target: < 5ms overhead for convenience functions
10+
11+
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
12+
use std::hint::black_box;
13+
14+
// ============================================================================
15+
// Grid Creation Overhead (AC9)
16+
// ============================================================================
17+
18+
/// Compare quick::grid() vs BrailleGrid::new() overhead
19+
///
20+
/// Measures the overhead of terminal size detection in quick::grid()
21+
fn bench_grid_overhead(c: &mut Criterion) {
22+
use dotmax::{quick, BrailleGrid};
23+
24+
let mut group = c.benchmark_group("quick_overhead");
25+
26+
// Benchmark direct BrailleGrid::new (baseline)
27+
group.bench_function("BrailleGrid::new_80x24", |b| {
28+
b.iter(|| black_box(BrailleGrid::new(80, 24).unwrap()));
29+
});
30+
31+
// Benchmark quick::grid() (includes terminal size detection)
32+
group.bench_function("quick::grid", |b| {
33+
b.iter(|| black_box(quick::grid().unwrap()));
34+
});
35+
36+
// Benchmark quick::grid_sized() (no terminal detection)
37+
group.bench_function("quick::grid_sized_80x24", |b| {
38+
b.iter(|| black_box(quick::grid_sized(80, 24).unwrap()));
39+
});
40+
41+
group.finish();
42+
}
43+
44+
// ============================================================================
45+
// Image Loading Overhead (AC9) - requires image feature
46+
// ============================================================================
47+
48+
#[cfg(feature = "image")]
49+
mod image_benchmarks {
50+
use super::*;
51+
use dotmax::image::ImageRenderer;
52+
use dotmax::quick;
53+
use std::path::Path;
54+
55+
/// Compare quick::load_image() vs manual ImageRenderer pipeline
56+
///
57+
/// This measures the overhead of the convenience function vs manual setup.
58+
/// Both should produce identical results, but quick::load_image() does
59+
/// terminal size detection automatically.
60+
pub fn bench_load_image_overhead(c: &mut Criterion) {
61+
let mut group = c.benchmark_group("quick_image_overhead");
62+
63+
// Use test fixture if available, skip otherwise
64+
let test_image = Path::new("tests/fixtures/images/sample.png");
65+
if !test_image.exists() {
66+
println!("Skipping image benchmarks: test image not found");
67+
return;
68+
}
69+
70+
// Benchmark manual ImageRenderer pipeline (baseline)
71+
group.bench_function("manual_ImageRenderer_80x24", |b| {
72+
b.iter(|| {
73+
black_box(
74+
ImageRenderer::new()
75+
.load_from_path(test_image)
76+
.unwrap()
77+
.resize(80, 24, true)
78+
.unwrap()
79+
.render()
80+
.unwrap(),
81+
)
82+
});
83+
});
84+
85+
// Benchmark quick::load_image_sized() (convenience function)
86+
group.bench_function("quick::load_image_sized_80x24", |b| {
87+
b.iter(|| black_box(quick::load_image_sized(test_image, 80, 24).unwrap()));
88+
});
89+
90+
// Benchmark quick::load_image() (includes terminal detection)
91+
// Note: Terminal detection adds minimal overhead (~microseconds)
92+
group.bench_function("quick::load_image_auto", |b| {
93+
b.iter(|| black_box(quick::load_image(test_image).unwrap()));
94+
});
95+
96+
group.finish();
97+
}
98+
}
99+
100+
// ============================================================================
101+
// Criterion Groups
102+
// ============================================================================
103+
104+
criterion_group!(quick_benches, bench_grid_overhead);
105+
106+
#[cfg(feature = "image")]
107+
criterion_group!(quick_image_benches, image_benchmarks::bench_load_image_overhead);
108+
109+
#[cfg(feature = "image")]
110+
criterion_main!(quick_benches, quick_image_benches);
111+
112+
#[cfg(not(feature = "image"))]
113+
criterion_main!(quick_benches);

examples/hello_braille.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
//! Hello Braille - Simple viewport test
22
//!
3-
//! Run with: `RUST_LOG=dotmax=debug` cargo run --example `hello_braille`
3+
//! This example demonstrates using the prelude for convenient imports.
4+
//! Instead of importing individual types, we use `dotmax::prelude::*`.
5+
//!
6+
//! Run with: `RUST_LOG=dotmax=debug cargo run --example hello_braille`
47
5-
use dotmax::{BrailleGrid, TerminalRenderer};
8+
// The prelude provides all commonly used types with a single import!
9+
use dotmax::prelude::*;
610
use std::thread;
711
use std::time::Duration;
812

9-
fn main() -> Result<(), Box<dyn std::error::Error>> {
13+
fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
1014
// Initialize logging to see debug output
1115
tracing_subscriber::fmt()
1216
.with_max_level(tracing::Level::DEBUG)

examples/quick_demo.rs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//! Quick module demonstration (Story 8.2)
2+
//!
3+
//! This example demonstrates the one-liner convenience functions in the `quick` module.
4+
//! The quick module provides the simplest possible API for common dotmax tasks.
5+
//!
6+
//! # Running this example
7+
//!
8+
//! Without image support (demonstrates grid/show):
9+
//! ```bash
10+
//! cargo run --example quick_demo
11+
//! ```
12+
//!
13+
//! With image support (demonstrates all functions):
14+
//! ```bash
15+
//! cargo run --example quick_demo --features image
16+
//! ```
17+
//!
18+
//! # What this example shows
19+
//!
20+
//! 1. `quick::grid()` - Create a terminal-sized grid
21+
//! 2. `quick::grid_sized()` - Create a grid with specific dimensions
22+
//! 3. `quick::show()` - Display a grid and wait for keypress
23+
//! 4. `quick::load_image()` - Load an image into a grid (image feature)
24+
//! 5. `quick::show_image()` - One-line image display (image feature)
25+
26+
use dotmax::primitives::{draw_circle, draw_line, draw_rectangle};
27+
use dotmax::quick;
28+
29+
fn main() -> Result<(), dotmax::DotmaxError> {
30+
println!("=== dotmax quick module demo ===\n");
31+
32+
// Example 1: Create a terminal-sized grid and draw on it
33+
println!("1. Creating terminal-sized grid with quick::grid()");
34+
let grid = quick::grid()?;
35+
println!(
36+
" Grid created: {}x{} cells ({}x{} dots)",
37+
grid.width(),
38+
grid.height(),
39+
grid.dot_width(),
40+
grid.dot_height()
41+
);
42+
43+
// Example 2: Create a grid with specific dimensions
44+
println!("\n2. Creating 40x20 grid with quick::grid_sized(40, 20)");
45+
let mut grid = quick::grid_sized(40, 20)?;
46+
println!(" Grid created: {}x{} cells", grid.width(), grid.height());
47+
48+
// Draw some shapes on the grid
49+
println!(" Drawing shapes...");
50+
51+
// Get dimensions for drawing
52+
let dot_w = grid.dot_width() as u32;
53+
let dot_h = grid.dot_height() as u32;
54+
55+
// Draw a border (draw_rectangle takes i32 for position, u32 for size)
56+
draw_rectangle(&mut grid, 0, 0, dot_w, dot_h)?;
57+
58+
// Draw diagonal lines (draw_line takes i32 for all coordinates)
59+
let w = dot_w as i32 - 1;
60+
let h = dot_h as i32 - 1;
61+
draw_line(&mut grid, 0, 0, w, h)?;
62+
draw_line(&mut grid, w, 0, 0, h)?;
63+
64+
// Draw a circle in the center (draw_circle takes i32 for position)
65+
let center_x = w / 2;
66+
let center_y = h / 2;
67+
draw_circle(&mut grid, center_x, center_y, 15)?;
68+
69+
// Display the grid
70+
println!("\n3. Displaying grid with quick::show()");
71+
println!(" Press any key to continue after viewing...\n");
72+
quick::show(&grid)?;
73+
println!(" Grid displayed and dismissed.");
74+
75+
// Image examples (only with image feature)
76+
#[cfg(feature = "image")]
77+
{
78+
use std::path::Path;
79+
80+
// Try to find a sample image
81+
let sample_paths = [
82+
"tests/fixtures/images/sample.png",
83+
"examples/sample.png",
84+
"sample.png",
85+
];
86+
87+
let sample_image = sample_paths.iter().find(|p| Path::new(p).exists());
88+
89+
if let Some(image_path) = sample_image {
90+
println!("\n4. Loading image with quick::load_image()");
91+
let image_grid = quick::load_image(image_path)?;
92+
println!(
93+
" Loaded {} into {}x{} grid",
94+
image_path,
95+
image_grid.width(),
96+
image_grid.height()
97+
);
98+
99+
println!("\n5. Displaying image with quick::show_image() - one line!");
100+
println!(" Press any key after viewing...\n");
101+
quick::show_image(image_path)?;
102+
println!(" Image displayed and dismissed.");
103+
} else {
104+
println!("\n4-5. Skipping image demos (no sample image found)");
105+
println!(" Try placing a sample.png in the examples/ directory");
106+
}
107+
}
108+
109+
#[cfg(not(feature = "image"))]
110+
{
111+
println!("\n4-5. Image demos require --features image");
112+
println!(" Run: cargo run --example quick_demo --features image");
113+
}
114+
115+
println!("\n=== Demo complete ===");
116+
Ok(())
117+
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@
7979
// Core modules (Epic 2)
8080
pub mod error;
8181
pub mod grid;
82+
pub mod prelude;
83+
pub mod quick;
8284
pub mod render;
8385

8486
// Utility modules (Epic 5)

0 commit comments

Comments
 (0)