use crate::caps::{Capability, CapabilitySet};
use crate::message::{Hello, HelloAck, Refusal, RefusalReason};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Agreement {
pub abi_major: u16,
pub abi_minor: u16,
pub agreed: CapabilitySet,
pub window_bytes: u64,
pub max_batch_rows: u64,
}
pub fn negotiate(hello: &Hello, ack: &HelloAck<'_>) -> Result<Agreement, Refusal<'static>> {
if ack.abi_major > hello.abi_major {
return Err(Refusal::new(
RefusalReason::ABI_TOO_NEW,
"the decoder was built against a later major version of the iris ABI than this host speaks",
));
}
if ack.abi_major < hello.abi_major {
return Err(Refusal::new(
RefusalReason::ABI_TOO_OLD,
"the decoder was built against an earlier major version of the iris ABI than this host speaks",
));
}
if ack.required.has_bits_beyond_this_build() {
return Err(Refusal::new(
RefusalReason::MISSING_CAPABILITY,
"the decoder requires a capability that is past the end of the bitset this host understands",
));
}
let missing = ack.required.difference(hello.offered);
if let Some(cap) = missing.iter().next() {
return Err(Refusal {
reason: RefusalReason::MISSING_CAPABILITY,
capability: cap,
detail: "the decoder requires a capability this host does not offer",
});
}
Ok(Agreement {
abi_major: hello.abi_major,
abi_minor: hello.abi_minor.min(ack.abi_minor),
agreed: hello.offered.intersection(ack.required.union(ack.optional)),
window_bytes: hello.window_bytes,
max_batch_rows: hello.max_batch_rows,
})
}
impl Agreement {
#[must_use]
pub const fn has(&self, cap: Capability) -> bool {
self.agreed.contains(cap)
}
}