<!-- Source: https://medius.k4tech.net/library/transform -->
# Transform

_Swap or remap a field on the wire_

A transform moves a field the clone's descriptor declares into another one. It needs no [imperfect-clone opt-in](/library/options.md#allow-imperfect-clones), unlike the [advanced control layer](/library/advanced/raw.md).

Transforms run before rendering, so [injection](/library/inject.md), riding and rendering see the transformed field. They are session state on the same lifecycle as a [`lock`](/library/lock.md).

```
  native report        the box's semantic path                          the wire

  X Y wheel pan  --> parse --> lock --> [ field transform ] --> render --> emit
  buttons/keys                 weigh     swap
                                         remap (X->Y, btn->btn, same report)
                                                   |
                                                   +-- btn->key / btn->media --> that interface's report
```

| Transform a... | Exchange it with another | Move it into another field | Weigh or invert it |
| --- | --- | --- | --- |
| relative axis (X / Y / wheel / pan) | [`transform_swap`](/library/transform.md#helpers) | [`transform_remap`](/library/transform.md#helpers) | [`scale`](/library/lock.md#scale), at a signed percent |
| button | axes only | [`transform_remap`](/library/transform.md#helpers), into a button, key, or media | one bit: [`lock`](/library/lock.md#lock) or [`unlock`](/library/lock.md#unlock) |
| key or media usage | not a source | destination only, from a button | one bit, as a button |

All are [fire-and-forget](/native/injection.md#fire-and-forget): one frame, no reply. [`transform`](/library/transform.md#transform) takes any [`Transform`](/library/types/structs.md#transform) built from parts, and [`query_transforms`](/library/transform.md#query-transforms) reads the active table.

## transform

_Install or overwrite one field transform_

```text
fn transform(&self, t: &Transform) -> Result<()>
```

_Fire-and-forget_

| Parameter | Type | Description |
| --- | --- | --- |
| `t` | [`Transform`](/library/types/structs.md#transform) | The [operation](/library/types/enums.md#transform-op) and the source and destination [fields](/library/types/enums.md#lock-target). A pair the op cannot address, or one field named as both ends, is [`Error::TransformOpFields`](/library/types/errors.md#errors); installing one past `Transforms::CAPACITY` is `Error::TransformTableFull`; one the box refuses is absent from [`query_transforms`](/library/transform.md#query-transforms). |

An entry is keyed by its [`(source, dest)`](/library/types/structs.md#transform-key); setting one whose key exists overwrites it in place, keeping its position. Entries apply in installation order, so two that write the same field do not commute.

#### EXAMPLE

```rust
use medius::{Device, Axis, Transform};

let device = Device::find()?;
device.transform(&Transform::swap(Axis::X, Axis::Y))?;      // the mouse's two axes, exchanged
device.transform(&Transform::remap(Axis::Wheel, Axis::Y))?; // the wheel drives vertical motion
```

## transform_swap / transform_remap

_The two transforms, one call each_

```text
fn transform_swap(&self, a: Axis, b: Axis) -> Result<()>
```

```text
fn transform_remap(&self, source: impl Into<LockTarget>, dest: impl Into<LockTarget>) -> Result<()>
```

_Fire-and-forget_

Each installs the [`Transform`](/library/types/structs.md#transform) its matching constructor builds, and refuses on the same terms as [`transform`](/library/transform.md#transform).

#### EXAMPLE

```rust
use medius::{Device, Axis, Button, Direction, Key};

let device = Device::find()?;
device.transform_swap(Axis::X, Axis::Y)?;        // exchange the two axes
device.transform_remap(Axis::Wheel, Axis::Y)?;   // the wheel drives vertical motion
device.transform_remap(Button::new(4), Key::A)?; // the fifth button emits 'A' on the keyboard interface
device.scale(Axis::Y, Direction::Both, -100)?;   // and Y arrives inverted
```

## untransform / clear_transforms

_Drop one entry or the whole table_

```text
fn untransform(&self, t: &Transform) -> Result<()>
```

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

_Fire-and-forget_

`untransform` drops the entry keyed by this transform's [`(source, dest)`](/library/types/structs.md#transform-key); its op is ignored. `clear_transforms` drops the whole table.

#### EXAMPLE

```rust
let swap = Transform::swap(Axis::X, Axis::Y);
device.transform(&swap)?;
device.untransform(&swap)?;   // the same key, dropped
device.clear_transforms()?;   // or drop everything
```

## query_transforms

_Read the active table_

```text
fn query_transforms(&self) -> Result<Transforms>
```

_Blocks_

Returns a [`Transforms`](/library/types/structs.md#transforms): the held entries in the order the box applies them, and a full flag. [`query_health`](/library/requests.md#health) reports a non-empty table in its [`transform_on`](/library/types/structs.md#health) flag.

#### EXAMPLE

```rust
let table = device.query_transforms()?;
println!("{} transforms{}", table.entries.len(), if table.table_full { " (full)" } else { "" });
for t in &table.entries {
    println!("  {:?} {:?} -> {:?}", t.op, t.source, t.dest);
}
```

## On AsyncDevice

_the transforms fire, query_transforms awaits_

Transforms carry no opt-in check, so [`AsyncDevice`](/library/features/async.md) keeps every setter synchronous. Only `query_transforms` is a future.

#### EXAMPLE

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

let device = AsyncDevice::open("/dev/ttyACM0")?;
device.transform_swap(Axis::X, Axis::Y)?;            // sync
let table = block_on(device.query_transforms())?;    // query awaits
```
