<!-- Source: https://medius.k4tech.net/library/advanced/rewrite -->
# Rewrite rules

_Rewrite a matched packet in flight_

The box holds a table of rules that match traffic and rewrite, answer, refuse, or drop it. A rule is addressed in the same `(class, id, direction)` space [catch](/library/catch.md) reads, in the write direction, narrowed by a masked head compare.

Rules are session state: re-asserted on reconnect like a [`lock`](/library/lock.md), and cleared on control-PC silence, [`reset`](/library/admin.md#reset), a re-clone, or the opt-in going off.

```
  native device          the box  (host chip  |  device chip = the clone)         game PC

  HID report  ---IN--->  [ HID_IN ]--> renderer --> [ EMIT ]---interrupt-IN--->  reads report
                          ^ pre-render               ^ post-render, the wire
  relayed     <--OUT---  [ HID_OUT ]<-- relay <---------------- interrupt-OUT <--  writes report
                          ^ VEND_INTR / VEND_BULK
  control     <-- EP0 -> [ CONTROL ]<-- proxy ------------------- EP0 <-------->  GET_DESCRIPTOR, SET_*
                          ^ id = endpoint number

              a rule acts at any [ bracketed ] stage
```

> **Warning**
>
> The advanced control layer is gated on the imperfect-clone opt-in. With [`allow_imperfect_clones`](/library/options.md#allow-imperfect-clones) off, `set_rewrite` returns [`Error::ImperfectRequired`](/library/types/errors.md#errors).

`set_rewrite`, `remove_rewrite`, and `clear_rewrite` are [fire-and-forget](/native/injection.md#fire-and-forget); [`query_rewrite`](/library/advanced/rewrite.md#query-rewrite) reads back what the box actually holds.

## set_rewrite

_Install or overwrite one rule_

```text
fn set_rewrite(&self, rule: &RewriteRule) -> Result<()>
```

_Fire-and-forget_

| Parameter | Type | Description |
| --- | --- | --- |
| `rule` | [`RewriteRule`](/library/types/structs.md#rewrite-rule) | The rule to install: its [address](/library/types/enums.md#rewrite-class), its [`action`](/library/types/enums.md#rewrite-action), and any masked match or payload. Installing one with the whole table already in use is [`Error::RewriteTableFull`](/library/types/errors.md#errors). |

A rule is keyed by `(class, id, direction, match, mask)`; setting one whose key exists overwrites it. The crate validates a rule before sending, so a bad one is a real error rather than a frame the box drops.

#### EXAMPLE

```rust
use medius::{Device, Direction, RewriteRule, RewriteClass, RewriteAction};

let device = Device::find()?;
device.allow_imperfect_clones(true)?;

// Mute the clone's own wire on interrupt-IN endpoint 1.
device.set_rewrite(&RewriteRule::new(RewriteClass::Emit, 1, Direction::IN, RewriteAction::Drop))?;

// Overwrite byte 2 of the device's report on interface 0, when byte 0 is the report id 0x01.
device.set_rewrite(
    &RewriteRule::new(RewriteClass::HidIn, 0, Direction::Both, RewriteAction::Patch)
        .matching([0x01], [0xFF])
        .at_offset(2)
        .with_payload([0x00]),
)?;
```

## remove_rewrite

_Drop one rule_

```text
fn remove_rewrite(&self, rule: &RewriteRule) -> Result<()>
```

_Fire-and-forget_

Drops the rule keyed by this rule's `(class, id, direction, match, mask)`; its `action` and `payload` are ignored. A no-op when no such rule is held.

#### EXAMPLE

```rust
let rule = RewriteRule::new(RewriteClass::Emit, 1, Direction::IN, RewriteAction::Drop);
device.set_rewrite(&rule)?;
device.remove_rewrite(&rule)?; // the same key, dropped
```

## clear_rewrite

_Drop every rule_

```text
fn clear_rewrite(&self) -> Result<()>
```

_Fire-and-forget_

Drops the whole table. It always clears the crate's held rules, whatever the opt-in, so a reconnect never re-asserts a rule you cleared.

#### EXAMPLE

```rust
device.clear_rewrite()?;
```

## query_rewrite

_Read the table's summary_

```text
fn query_rewrite(&self) -> Result<RewriteTable>
```

_Blocks_

Returns a [`RewriteTable`](/library/types/structs.md#rewrite-table): a full flag, a generation counter, and a row per rule without its match, mask, or payload bytes.

#### EXAMPLE

```rust
let table = device.query_rewrite()?;
println!("{} rules, gen {}", table.entries.len(), table.generation);
for e in &table.entries {
    println!("  {:?} id {:#04x} -> {:?}, {} hits", e.class, e.id, e.action, e.hits);
}
```

## query_rewrite_entry

_Read one rule in full_

```text
fn query_rewrite_entry(&self, index: u8) -> Result<RewriteRule>
```

_Blocks_

| Parameter | Type | Description |
| --- | --- | --- |
| `index` | `u8` | The row in the [`query_rewrite`](/library/advanced/rewrite.md#query-rewrite) summary. |

Returns one [`RewriteRule`](/library/types/structs.md#rewrite-rule) in full, in the shape [`set_rewrite`](/library/advanced/rewrite.md#set-rewrite) takes.

#### EXAMPLE

```rust
let table = device.query_rewrite()?;
for i in 0..table.entries.len() as u8 {
    let rule = device.query_rewrite_entry(i)?; // replayable as a set
    let _ = rule;
}
```

## On AsyncDevice

_set_rewrite and the queries await; remove and clear fire_

[`AsyncDevice`](/library/features/async.md) makes `set_rewrite` a future: it awaits the imperfect-clone opt-in check before it sends, as do `query_rewrite` and `query_rewrite_entry`. `remove_rewrite` and `clear_rewrite` carry no opt-in check and stay synchronous.

#### EXAMPLE

```rust
use futures::executor::block_on;
use medius::{AsyncDevice, Direction, RewriteRule, RewriteClass, RewriteAction};

let device = AsyncDevice::open("/dev/ttyACM0")?;
device.allow_imperfect_clones(true)?;
let rule = RewriteRule::new(RewriteClass::Emit, 1, Direction::IN, RewriteAction::Drop);
block_on(device.set_rewrite(&rule))?;            // awaits the opt-in gate
device.remove_rewrite(&rule)?;                   // sync: no gate
let table = block_on(device.query_rewrite())?;   // query awaits
```
