<!-- Source: https://medius.k4tech.net/library/advanced/patch -->
# Descriptor patches

_Overwrite the bytes the clone presents_

A descriptor patch overwrites bytes in what the clone presents at enumeration, keyed by `(section, cfg, index, offset)` and persisted per device (VID:PID) in the box's NVS.

Unlike a [rewrite rule](/library/advanced/rewrite.md), a patch is configuration, not session state: it survives a reconnect and clears only on [`clear_patch`](/library/advanced/patch.md#clear-patch). The box stores a patch whatever the opt-in, and applies the stored set only under it.

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

  descriptors  ------------------->  [ descriptor patches ]  ---enumerate--->  device descriptor
                                       overwrite what the                      configuration
                                       clone presents                          report / string / BOS

  HID report   ---IN--->  [ HID_IN ]--> renderer --> [ EMIT ]---interrupt-IN--->  reads report
  control      <-- EP0 -> [ CONTROL ]<-- proxy ------------------- EP0 <-------->  GET_DESCRIPTOR, SET_*
```

> **Warning**
>
> A patch never changes a descriptor's byte count; the box refuses (and logs) an apply that would. Applying is gated on the imperfect-clone opt-in; with [`allow_imperfect_clones`](/library/options.md#allow-imperfect-clones) off, `apply_patch` returns [`Error::ImperfectRequired`](/library/types/errors.md#errors).

The setters are [fire-and-forget](/native/injection.md#fire-and-forget); [`query_patches`](/library/advanced/patch.md#query-patches) reads back the stored set and its apply state.

## set_patch

_Store or overwrite one patch_

```text
fn set_patch(&self, patch: &Patch) -> Result<()>
```

_Fire-and-forget_

| Parameter | Type | Description |
| --- | --- | --- |
| `patch` | [`Patch`](/library/types/structs.md#patch) | The overwrite: its [section](/library/types/enums.md#patch-section), address, offset, and bytes. |

A patch is keyed by `(section, cfg, index, offset)`; setting one whose key exists overwrites it, and empty `bytes` removes it. Storing is not gated and does not re-present the clone; [`apply_patch`](/library/advanced/patch.md#apply-patch) does.

#### EXAMPLE

```rust
use medius::{Device, Patch, PatchSection};

let device = Device::find()?;

// Overwrite idVendor in the device descriptor (offset 8, little-endian), then re-present.
device.set_patch(&Patch::new(PatchSection::Device, 8, [0x34, 0x12]))?;
device.allow_imperfect_clones(true)?;
device.apply_patch()?;
```

## apply_patch

_Re-present the clone with the stored set_

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

_Fire-and-forget_

Re-presents the clone with the stored patch set: one unplug/replug to the game PC. Gated on [`allow_imperfect_clones`](/library/options.md#allow-imperfect-clones); with the opt-in off it returns [`Error::ImperfectRequired`](/library/types/errors.md#errors). A refused apply shows in [`query_patches`](/library/advanced/patch.md#query-patches)'s `refused` flag.

#### EXAMPLE

```rust
device.allow_imperfect_clones(true)?;
device.apply_patch()?; // the clone replugs and re-presents patched
```

## clear_patch

_Drop every patch for this device_

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

_Fire-and-forget_

Drops every patch stored for this device (VID:PID) and re-presents the clone unpatched. This is the only thing that clears the stored set; a reconnect does not.

#### EXAMPLE

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

## query_patches

_Read the stored set and its apply state_

```text
fn query_patches(&self) -> Result<PatchSet>
```

_Blocks_

Returns a [`PatchSet`](/library/types/structs.md#patch-set): the four apply-state flags and a row per stored patch, without its bytes.

#### EXAMPLE

```rust
let set = device.query_patches()?;
println!("{} patches, applied={} pending={}", set.entries.len(), set.applied, set.pending);
if set.refused {
    eprintln!("the last apply was refused: a patched length no longer matched what it serves");
}
```

## query_patch_entry

_Read one patch in full_

```text
fn query_patch_entry(&self, index: u8) -> Result<Patch>
```

_Blocks_

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

Returns one [`Patch`](/library/types/structs.md#patch) in full, in the shape [`set_patch`](/library/advanced/patch.md#set-patch) takes.

#### EXAMPLE

```rust
let set = device.query_patches()?;
for i in 0..set.entries.len() as u8 {
    let patch = device.query_patch_entry(i)?; // replayable as a set
    let _ = patch;
}
```

## On AsyncDevice

_apply_patch and the queries await; set and clear fire_

[`AsyncDevice`](/library/features/async.md) makes `apply_patch` a future (it awaits the opt-in check), as are `query_patches` and `query_patch_entry`. `set_patch` and `clear_patch` stay synchronous.

#### EXAMPLE

```rust
use futures::executor::block_on;
use medius::{AsyncDevice, Patch, PatchSection};

let device = AsyncDevice::open("/dev/ttyACM0")?;
device.set_patch(&Patch::new(PatchSection::Device, 8, [0x34, 0x12]))?;  // sync
device.allow_imperfect_clones(true)?;
block_on(device.apply_patch())?;                                        // awaits the opt-in gate
let set = block_on(device.query_patches())?;                            // query awaits
```
