# Optional Features

Wasot uses Cargo feature flags to allow you to customize the build and exclude functionality you don't need. This reduces binary size and compilation time. For release build instructions, see [build release](./build_release.md). For [CLI](./cli.md) usage, see the CLI documentation.

## Available Features

| Feature | Description | Default | Impact |
|---------|-------------|---------|--------|
| `sqlite` | SQLite database support (`to-sqlite`, `from-sqlite` commands) | Yes | ~2.3 MB |
| `python` | [Python bindings](./python_bindings.md) via PyO3 | No | Significant |
| `grpc` | gRPC support | No | Moderate |
| `optimized-alloc` | Use mimalloc allocator (faster heap allocation) | No | None (runtime perf) |

## Building Without Optional Features

### Minimal Build (No SQLite)

To build the smallest possible binary without SQLite support:

```bash
cargo build --release --no-default-features
```

**Size comparison:**
- With SQLite: ~5.5 MB
- Without SQLite: ~3.2 MB (~41% smaller)

### Selective Features

Enable only the features you need:

```bash
# Just core functionality (no SQLite)
cargo build --release --no-default-features

# Core + SQLite
cargo build --release --no-default-features --features sqlite

# Core + Python bindings
cargo build --release --no-default-features --features python

# Everything
cargo build --release --features "sqlite,python,grpc"
```

## How to Add New Optional Features

When adding new optional functionality to Wasot, follow this pattern to make it conditionally compilable.

### Step 1: Add the Dependency as Optional

In `Cargo.toml`:

```toml
[dependencies]
your-dep = { version = "1.0", optional = true }

[features]
default = ["your-feature"]  # Include in default if commonly needed
your-feature = ["your-dep"]
```

### Step 2: Wrap the Module Declaration

In `src/consumers/mod.rs` or `src/emitters/mod.rs`:

```rust
#[cfg(feature = "your-feature")]
pub mod your_consumer;

// Re-exports
#[cfg(feature = "your-feature")]
pub use your_consumer::YourConsumer;
```

### Step 3: Wrap the Module Contents

At the top of your module file (e.g., `src/consumers/your_consumer.rs`):

```rust
#![cfg(feature = "your-feature")]

use your_dep::SomeType;
// ... rest of module
```

### Step 4: Update lib.rs Re-exports

In `src/lib.rs`:

```rust
// Main re-exports (unconditional)
pub use consumers::{ActionConsumer, /* other consumers */};

// Conditional re-exports
#[cfg(feature = "your-feature")]
pub use consumers::YourConsumer;
```

### Step 5: Update main.rs CLI

For CLI commands, wrap the command enum variant and its handler:

```rust
#[derive(Subcommand)]
enum Commands {
    // ... other commands ...

    /// Your new command description
    #[cfg(feature = "your-feature")]
    YourCommand {
        #[arg(short, long)]
        some_arg: String,
    },
}

// In the match handler:
#[cfg(feature = "your-feature")]
Commands::YourCommand { some_arg } => {
    process_your_command(&some_arg)?;
}
```

### Step 6: Update Tests

Wrap feature-specific tests:

```rust
#[test]
#[cfg(feature = "your-feature")]
fn test_your_feature() {
    // Test code
}

// For conditional test data:
#[cfg(feature = "your-feature")]
let data = vec!["with-feature"];
#[cfg(not(feature = "your-feature"))]
let data = vec!["without-feature"];
```

## Testing Feature Combinations

Always test that your code compiles with different feature combinations:

```bash
# Without any default features
cargo check --no-default-features

# With all features
cargo check --all-features

# With specific feature combinations
cargo check --no-default-features --features "sqlite"
cargo check --no-default-features --features "python"
```

## CI Configuration

For CI, test multiple feature combinations:

```yaml
jobs:
  test:
    strategy:
      matrix:
        features:
          - ""  # no features
          - "sqlite"
          - "sqlite,python"
    steps:
      - run: cargo test --no-default-features --features "${{ matrix.features }}"
```

## Best Practices

1. **Default to including common features** - Features most users need should be in the default set
2. **Keep feature flags granular** - One feature per major dependency when possible
3. **Document size/compile-time impact** - Help users make informed decisions
4. **Test all combinations** - Ensure the build works with any feature combination
5. **Use `#![cfg(feature = "...")]`** at module level - Cleaner than wrapping every item
6. **Keep conditional code minimal** - Prefer wrapping entire modules over scattered `#[cfg]` attributes
