frozen-duckdb 0.1.0

Pre-compiled DuckDB binary for fast Rust builds - Drop-in replacement for duckdb-rs
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# Library API Reference

## Overview

The Frozen DuckDB library provides three core modules for **architecture detection**, **performance benchmarking**, and **environment setup**. All modules are designed for **production use** with comprehensive error handling and performance optimization.

## Architecture Module

The `architecture` module handles **automatic architecture detection** and **binary selection** for optimal performance.

### Functions

#### `detect() -> String`

Detects the current system architecture with manual override support.

```rust
use frozen_duckdb::architecture;

// Detect current architecture
let arch = architecture::detect();
println!("Current architecture: {}", arch);
// Output: "arm64" or "x86_64"

// With environment override
std::env::set_var("ARCH", "x86_64");
assert_eq!(architecture::detect(), "x86_64");
std::env::remove_var("ARCH");
```

**Environment Override:**
```bash
# Force x86_64 binary selection
ARCH=x86_64 cargo build

# Force arm64 binary selection
ARCH=arm64 cargo build
```

#### `is_supported(arch: &str) -> bool`

Checks if the given architecture has optimized binaries available.

```rust
use frozen_duckdb::architecture;

assert!(architecture::is_supported("x86_64"));
assert!(architecture::is_supported("arm64"));
assert!(architecture::is_supported("aarch64"));
assert!(!architecture::is_supported("unknown"));
```

**Supported Architectures:**
- `x86_64`: Intel/AMD 64-bit processors (55MB optimized binary)
- `arm64`: Apple Silicon processors (50MB optimized binary)
- `aarch64`: ARM 64-bit processors (same as arm64, 50MB optimized binary)

#### `get_binary_name() -> String`

Gets the appropriate binary filename for the current architecture.

```rust
use frozen_duckdb::architecture;

let binary = architecture::get_binary_name();
assert!(binary.starts_with("libduckdb"));
assert!(binary.ends_with(".dylib"));

// With architecture override
std::env::set_var("ARCH", "x86_64");
assert_eq!(architecture::get_binary_name(), "libduckdb_x86_64.dylib");
std::env::remove_var("ARCH");
```

**Binary Mapping:**
| Architecture | Binary Name | Size | Optimization |
|--------------|-------------|------|--------------|
| x86_64 | libduckdb_x86_64.dylib | 55MB | Intel/AMD optimized |
| arm64/aarch64 | libduckdb_arm64.dylib | 50MB | ARM optimized |
| Other | libduckdb.dylib | ~50MB | Generic fallback |

### Performance Characteristics

- **Detection time**: <1μs (cached at OS level)
- **Binary selection**: <1μs
- **Memory usage**: Negligible
- **Thread safety**: Safe for concurrent use

## Environment Setup Module

The `env_setup` module provides utilities for **validating** and **configuring** the frozen DuckDB environment.

### Functions

#### `is_configured() -> bool`

Checks if the frozen DuckDB environment is properly configured.

```rust
use frozen_duckdb::env_setup;

// Check configuration status
if env_setup::is_configured() {
    println!("✅ Environment is properly configured");
} else {
    println!("❌ Please run: source prebuilt/setup_env.sh");
}
```

**Environment Variables Checked:**
- `DUCKDB_LIB_DIR`: Directory containing DuckDB libraries
- `DUCKDB_INCLUDE_DIR`: Directory containing DuckDB headers

#### `get_lib_dir() -> Option<String>`

Gets the configured DuckDB library directory path.

```rust
use frozen_duckdb::env_setup;

// Get library directory
if let Some(lib_dir) = env_setup::get_lib_dir() {
    println!("Library directory: {}", lib_dir);
} else {
    println!("DUCKDB_LIB_DIR not set");
}
```

**Expected Directory Contents:**
- `libduckdb_x86_64.dylib` (55MB) - Intel/AMD 64-bit binary
- `libduckdb_arm64.dylib` (50MB) - Apple Silicon/ARM 64-bit binary
- `libduckdb.dylib` - Generic fallback binary

#### `get_include_dir() -> Option<String>`

Gets the configured DuckDB include directory path.

```rust
use frozen_duckdb::env_setup;

// Get include directory
if let Some(include_dir) = env_setup::get_include_dir() {
    println!("Include directory: {}", include_dir);
} else {
    println!("DUCKDB_INCLUDE_DIR not set");
}
```

**Expected Directory Contents:**
- `duckdb.h` (186KB) - C header file
- `duckdb.hpp` (1.8MB) - C++ header file

#### `validate_binary() -> Result<()>`

Validates that the frozen DuckDB binary exists and is accessible.

```rust
use frozen_duckdb::env_setup;

// Validate binary existence
match env_setup::validate_binary() {
    Ok(()) => println!("✅ DuckDB binaries are available"),
    Err(e) => println!("❌ Binary validation failed: {}", e),
}
```

**Validation Process:**
1. Check `DUCKDB_LIB_DIR` environment variable
2. Verify library directory exists and is accessible
3. Confirm at least one DuckDB binary is present
4. Validate binary permissions and integrity

**Error Conditions:**
- `DUCKDB_LIB_DIR` not set
- Library directory doesn't exist
- No DuckDB binaries found
- Directory not accessible

### Performance Characteristics

- **Configuration check**: <1μs (cached environment variables)
- **Path retrieval**: <1μs
- **Binary validation**: <10ms (file system operations)
- **Memory usage**: Negligible

## Benchmark Module

The `benchmark` module provides utilities for **measuring** and **comparing** build performance.

### Functions

#### `measure_build_time<F>(operation: F) -> std::time::Duration`

Measures the execution time of a build operation with high precision.

```rust
use frozen_duckdb::benchmark;
use std::time::Duration;

// Measure a simple operation
let duration = benchmark::measure_build_time(|| {
    std::thread::sleep(Duration::from_millis(100));
    Ok(())
});

assert!(duration >= Duration::from_millis(100));
assert!(duration < Duration::from_millis(200));
```

**Features:**
- **High precision**: Microsecond-level accuracy
- **Error handling**: Measures time even when operations fail
- **Zero overhead**: Minimal performance impact
- **Thread safety**: Safe for concurrent use

#### `compare_build_times<F1, F2>(operation1: F1, operation2: F2) -> Result<(std::time::Duration, std::time::Duration)>`

Compares the execution times of two different build operations.

```rust
use frozen_duckdb::benchmark;
use std::time::Duration;

let (time1, time2) = benchmark::compare_build_times(
    || {
        // Fast operation (e.g., using pre-built binaries)
        std::thread::sleep(Duration::from_millis(50));
        Ok(())
    },
    || {
        // Slow operation (e.g., compiling from source)
        std::thread::sleep(Duration::from_millis(200));
        Ok(())
    },
).unwrap();

assert!(time2 > time1);
// Calculate improvement percentage
let improvement = ((time2.as_millis() - time1.as_millis()) as f64 / time2.as_millis() as f64) * 100.0;
println!("Improvement: {:.1}%", improvement);
```

**Use Cases:**
- **Build optimization**: Compare different build configurations
- **Binary vs source**: Measure impact of pre-built vs compiled binaries
- **Architecture comparison**: Test performance across different architectures
- **Dependency analysis**: Understand impact of different dependencies

### Performance Characteristics

- **Timing precision**: Microsecond-level accuracy on most platforms
- **Overhead**: <1μs per measurement
- **Memory usage**: No allocations during timing
- **Thread safety**: Safe for concurrent use

## Error Handling

All library functions follow consistent error handling patterns:

### Error Types

```rust
use anyhow::Result;

// All public functions return Result<T, anyhow::Error>
pub fn detect() -> String;                    // Never fails
pub fn is_configured() -> bool;              // Never fails
pub fn get_lib_dir() -> Option<String>;       // Never fails
pub fn get_include_dir() -> Option<String>;   // Never fails
pub fn validate_binary() -> Result<()>;      // Can fail
pub fn measure_build_time<F>(...) -> Duration; // Never fails
pub fn compare_build_times<F1, F2>(...) -> Result<...>; // Can fail
```

### Error Messages

The library provides **clear, actionable error messages**:

```rust
// Environment errors
"DUCKDB_LIB_DIR not set"
"No frozen DuckDB binary found in /path/to/lib"

// Binary validation errors
"No frozen DuckDB binary found in /path/to/lib"
"Library directory does not exist"

// Performance measurement errors
"Operation failed during timing measurement"
"Comparison operations returned different error types"
```

## Integration Examples

### Basic Environment Check

```rust
use frozen_duckdb::{architecture, env_setup};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Check if environment is properly configured
    if env_setup::is_configured() {
        println!("✅ Frozen DuckDB is ready!");
        println!("Architecture: {}", architecture::detect());

        // Validate binaries exist
        env_setup::validate_binary()?;
        println!("✅ Binaries validated");
    } else {
        println!("❌ Please run: source prebuilt/setup_env.sh");
        std::process::exit(1);
    }

    Ok(())
}
```

### Performance Benchmarking

```rust
use frozen_duckdb::benchmark;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Measure build time for an operation
    let duration = benchmark::measure_build_time(|| {
        // Your build operation here
        std::thread::sleep(std::time::Duration::from_millis(100));
        Ok(())
    });

    println!("Build completed in: {:?}", duration);

    // Compare two approaches
    let (fast_time, slow_time) = benchmark::compare_build_times(
        || {
            // Fast approach (pre-built binary)
            std::thread::sleep(std::time::Duration::from_millis(50));
            Ok(())
        },
        || {
            // Slow approach (source compilation)
            std::thread::sleep(std::time::Duration::from_millis(200));
            Ok(())
        },
    )?;

    println!("Fast approach: {:?}", fast_time);
    println!("Slow approach: {:?}", slow_time);

    Ok(())
}
```

## Testing

The library includes comprehensive tests covering:

### Unit Tests

```bash
# Run all library tests
cargo test --lib

# Run specific module tests
cargo test architecture
cargo test env_setup
cargo test benchmark
```

### Test Coverage

- **Architecture detection**: Multiple architectures and overrides
- **Environment validation**: Various configuration scenarios
- **Binary validation**: Missing files, permission issues
- **Performance measurement**: Timing accuracy and error handling
- **Error conditions**: Invalid inputs and edge cases

### Property Tests

```rust
#[cfg(test)]
mod tests {
    use super::*;
    use proptest::prelude::*;

    proptest! {
        #[test]
        fn test_architecture_detection_consistency(arch in "x86_64|arm64|aarch64") {
            std::env::set_var("ARCH", arch);
            let detected = detect();
            assert_eq!(detected, arch);
            std::env::remove_var("ARCH");
        }
    }
}
```

## Performance Considerations

### Optimization Guidelines

1. **Architecture detection**: Perform once at startup, cache results
2. **Environment validation**: Call sparingly, cache results when possible
3. **Binary validation**: Perform during initialization, not on every operation
4. **Performance measurement**: Use for optimization, not in production hot paths

### Memory Usage

- **Module size**: <50KB compiled
- **Runtime memory**: Negligible for typical usage
- **Allocation patterns**: No heap allocations in performance-critical paths

## Migration Guide

### From Manual Architecture Detection

```rust
// Before
let arch = std::env::consts::ARCH;

// After
use frozen_duckdb::architecture;
let arch = architecture::detect(); // Includes override support
```

### From Manual Environment Setup

```rust
// Before
let lib_dir = std::env::var("DUCKDB_LIB_DIR").unwrap();

// After
use frozen_duckdb::env_setup;
let lib_dir = env_setup::get_lib_dir().unwrap(); // Includes validation
```

## Summary

The library API provides a **simple, reliable interface** for architecture detection, environment setup, and performance benchmarking. All functions are designed for **production use** with comprehensive error handling, performance optimization, and extensive testing.

**Key Benefits:**
- **Zero configuration**: Automatic architecture detection with manual override
- **Fast validation**: Quick environment and binary verification
- **Accurate benchmarking**: High-precision performance measurement
- **Production ready**: Comprehensive error handling and testing
- **Minimal overhead**: Optimized for frequent use