Skip to main content

Crate iris_abi

Crate iris_abi 

Source
Expand description

The guest and host ABI for iris self-decoding datasets.

The ABI is the only surface in iris that can ossify, so it is shaped like a wire protocol: length prefixed records, negotiated capabilities, and a defined way for either side to refuse politely.

This crate is no_std and has no dependencies at all, and both of those are checked by CI. It ends up inside every decoder anyone writes, so anything it pulls in, everyone pays for.

§How a conversation goes

The host sends a Hello saying which ABI version it speaks and what it can do. The decoder answers with a HelloAck saying what it needs. negotiate compares the two and either produces an Agreement or a Refusal that names the capability that was missing. After that the host sends ScanRequest records, the decoder sends RangeRequest records back when it needs bytes it has not been given, and the rows come back as Batch records.

use iris_abi::{Capability, CapabilitySet, Hello, HelloAck, negotiate};

let host = Hello {
    abi_major: iris_abi::ABI_MAJOR,
    abi_minor: iris_abi::ABI_MINOR,
    window_bytes: 64 << 20,
    max_batch_rows: 8192,
    offered: CapabilitySet::new()
        .with(Capability::REQUIRE_RANGE)
        .with(Capability::SLIDING_WINDOW),
    source_bytes: 4 << 30,
};
let decoder = HelloAck {
    abi_major: iris_abi::ABI_MAJOR,
    abi_minor: iris_abi::ABI_MINOR,
    required: CapabilitySet::new().with(Capability::REQUIRE_RANGE),
    optional: CapabilitySet::new().with(Capability::PROJECTION),
    decoder_id: "example",
};

let agreed = negotiate(&host, &decoder).expect("the host offers what the decoder needs");
assert!(agreed.has(Capability::REQUIRE_RANGE));
// The host offers sliding windows but this decoder never asked for them, so it is not on.
assert!(!agreed.has(Capability::SLIDING_WINDOW));
// The decoder would like projection pushdown but this host does not do it, and that is fine
// because it was optional.
assert!(!agreed.has(Capability::PROJECTION));

§What is allowed to change

Adding a field to the end of a record is allowed and does not bump that record’s version, because a reader that does not know about the field steps over it. Adding a record is allowed, because a reader that does not know a tag steps over the whole record. Adding a capability is allowed, because a side that does not offer it says so and the other side decides what to do.

Removing a field, reordering fields, changing what a field means, or changing what a capability bit means are all breaking, and all of them are supposed to be loud rather than silent. The tests in tests/forward_compat.rs hold the compatible half of that line.

Re-exports§

pub use caps::Capability;
pub use caps::CapabilitySet;
pub use error::Error;
pub use error::Result;
pub use handshake::Agreement;
pub use handshake::negotiate;
pub use message::Batch;
pub use message::BufferRef;
pub use message::Buffers;
pub use message::Hello;
pub use message::HelloAck;
pub use message::Message;
pub use message::Node;
pub use message::Nodes;
pub use message::Projection;
pub use message::RangeRequest;
pub use message::Refusal;
pub use message::RefusalReason;
pub use message::ScanRequest;
pub use record::Header;
pub use record::Tag;
pub use wire::Reader;
pub use wire::Writer;

Modules§

caps
Capabilities, and the set of them each side carries.
error
Errors from reading and writing ABI records.
handshake
Working out whether the host and the decoder can work together, and saying so plainly when they cannot.
message
The records themselves.
record
Record framing.
wire
Reading and writing the primitive values that ABI records are built out of.

Constants§

ABI_MAJOR
The major ABI version this build speaks.
ABI_MINOR
The minor ABI version this build speaks.