Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Wire Format

molex::ops::wire holds two binary formats: the assembly format (a full Assembly snapshot) and the delta format (an incremental edit list). Both start with a fixed 8-byte magic followed by a u8 version byte that selects the payload layout; the magic never changes when the payload does. Only version 1 exists today, and any other version is a clean decode rejection.

Assembly format

The format is entity-aware: it preserves per-entity molecule-type metadata so the decoder reconstructs MoleculeEntity variants without re-running residue classification. It also carries each entity’s EntityId and a trailing per-residue variants section.

Public surface

assembly_bytes is the only public free function; it serializes a raw entity slice. serialize_assembly / deserialize_assembly are crate-internal. To round-trip an Assembly use its to_bytes / from_bytes methods.

use molex::ops::wire::{assembly_bytes, ASSEMBLY_MAGIC};
use molex::Assembly;

// Serialize a raw entity slice.
let bytes: Vec<u8> = assembly_bytes(&entities)?;

// Round-trip an Assembly.
let bytes: Vec<u8> = assembly.to_bytes()?;
let decoded: Assembly = Assembly::from_bytes(&bytes)?; // ss_types empty

assert_eq!(&bytes[0..8], ASSEMBLY_MAGIC);

Decoding returns a secondary-structure-free assembly: ss_types is empty until a caller invokes recompute_ss(). The decode path does not recompute derived data.

Byte layout

The chain id lives in the per-entity header as a length-prefixed string, so chain ids are not capped to a single printable byte. Each atom row is 25 bytes.

8 bytes:   magic "ASSEMBLY"
1 byte:    version (currently 1)
4 bytes:   entity_count (u32 BE)
Per entity header (variable):
  1 byte:  molecule_type wire byte
  4 bytes: atom_count (u32 BE), the body-row count for this entity
  4 bytes: entity_id (u32 BE), the originator's EntityId.raw()
  2 bytes: chain_len (u16 BE)
  chain_len bytes: chain id (UTF-8 label_asym_id; empty for non-polymers)
Per atom (25 bytes):
  12 bytes: x, y, z (f32 BE x 3)
  3 bytes:  res_name
  4 bytes:  res_num (i32 BE)
  4 bytes:  atom_name
  2 bytes:  element symbol (byte 0, byte 1 or 0)
Per-entity variants section (after all atoms, in entity-header order):
  per entity {
    4 bytes: variant_residue_count (u32 BE)
    per variant-bearing residue {
      4 bytes: label_seq_id (i32 BE)
      4 bytes: variant_count (u32 BE)
      per variant {
        1 byte:  tag
        tag-specific payload
      }
    }
  }

Each entity contributes a variant block even when it carries no variants: a non-polymer entity or one with no variant-bearing residues emits a variant_residue_count of 0 (4 bytes).

Variant tags

0x01  NTerminus    0 payload bytes
0x02  CTerminus    0 payload bytes
0x03  Disulfide    0 payload bytes
0x04  Protonation  1 sub-tag byte:
        0x01  HisDelta
        0x02  HisEpsilon
        0x03  HisDoubly
        0xFF  Custom (u16 BE length + UTF-8 bytes)
0xFE  Other        u16 BE length + UTF-8 bytes

Occupancy, b_factor, formal_charge, and the observed flag are not preserved on the wire; deserialize resets occupancy / b_factor to 1.0 / 0.0.

Delta format

molex::ops::wire::delta carries an incremental edit list (Vec<AssemblyEdit>) rather than a full snapshot; it is the steady-state path between the host and its plugins. Topology edits (AddEntity / RemoveEntity) are not representable on the wire; callers broadcast a full assembly snapshot for that class of change.

use molex::ops::wire::delta::{serialize_edits, deserialize_edits, DELTA_MAGIC};

let bytes = serialize_edits(&edits)?;
let edits = deserialize_edits(&bytes)?;

Byte layout

8 bytes:  magic b"DELTA\0\0\0"
1 byte:   version (currently 1)
4 bytes:  edit_count (u32 BE)
per edit:
  1 byte: tag
  tag-specific payload

Edit tags:

0x01  SetEntityCoords   u32 entity_id, u32 coord_count, 12 bytes per coord (xyz f32 BE)
0x02  SetResidueCoords  u32 entity_id, u32 residue_idx, u32 coord_count, 12 bytes per coord
0x03  MutateResidue     u32 entity_id, u32 residue_idx, 3 bytes new_name, u32 atom_count,
                        25 bytes per atom (same row layout as the assembly format),
                        u32 variant_count, per-variant payload (same as the variants block)
0x04  SetVariants       u32 entity_id, u32 residue_idx, u32 variant_count, per-variant payload

See the Edits page for the AssemblyEdit types these tags encode.