Medius - Rust LibraryTransform

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, unlike the advanced control layer.

Transforms run before rendering, so injection, riding and rendering see the transformed field. They are session state on the same lifecycle as a lock.

  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 anotherMove it into another fieldWeigh or invert it
relative axis (X / Y / wheel / pan)transform_swaptransform_remapscale, at a signed percent
buttonaxes onlytransform_remap, into a button, key, or mediaone bit: lock or unlock
key or media usagenot a sourcedestination only, from a buttonone bit, as a button

All are fire-and-forget: one frame, no reply. transform takes any Transform built from parts, and query_transforms reads the active table.

transform

Install or overwrite one field transform
fn transform(&self, t: &Transform) -> Result<()>

Fire-and-forget

ParameterTypeDescription
tTransformThe operation and the source and destination fields. A pair the op cannot address, or one field named as both ends, is Error::TransformOpFields; installing one past Transforms::CAPACITY is Error::TransformTableFull; one the box refuses is absent from query_transforms.

An entry is keyed by its (source, dest); 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
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
fn transform_swap(&self, a: Axis, b: Axis) -> Result<()>
fn transform_remap(&self, source: impl Into<LockTarget>, dest: impl Into<LockTarget>) -> Result<()>

Fire-and-forget

Each installs the Transform its matching constructor builds, and refuses on the same terms as transform.

EXAMPLE
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
fn untransform(&self, t: &Transform) -> Result<()>
fn clear_transforms(&self) -> Result<()>

Fire-and-forget

untransform drops the entry keyed by this transform's (source, dest); its op is ignored. clear_transforms drops the whole table.

EXAMPLE
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
fn query_transforms(&self) -> Result<Transforms>

Blocks

Returns a Transforms: the held entries in the order the box applies them, and a full flag. query_health reports a non-empty table in its transform_on flag.

EXAMPLE
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 keeps every setter synchronous. Only query_transforms is a future.

EXAMPLE
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