use crate::wire::Reader;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Capability(pub u16);
impl Capability {
pub const REQUIRE_RANGE: Self = Self(0);
pub const SLIDING_WINDOW: Self = Self(1);
pub const PROJECTION: Self = Self(2);
pub const FILTER_PUSHDOWN: Self = Self(3);
pub const RANDOM_ACCESS: Self = Self(4);
pub const STATELESS: Self = Self(5);
pub const RESUMABLE: Self = Self(6);
#[must_use]
pub const fn name(self) -> Option<&'static str> {
match self {
Self::REQUIRE_RANGE => Some("require-range"),
Self::SLIDING_WINDOW => Some("sliding-window"),
Self::PROJECTION => Some("projection"),
Self::FILTER_PUSHDOWN => Some("filter-pushdown"),
Self::RANDOM_ACCESS => Some("random-access"),
Self::STATELESS => Some("stateless"),
Self::RESUMABLE => Some("resumable"),
_ => None,
}
}
}
impl core::fmt::Display for Capability {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.name() {
Some(name) => f.write_str(name),
None => write!(f, "capability bit {}", self.0),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub struct CapabilitySet {
bits: [u8; Self::BYTES],
beyond: bool,
}
impl CapabilitySet {
pub const BYTES: usize = 32;
pub const MAX_BIT: u16 = 255;
#[must_use]
pub const fn new() -> Self {
Self {
bits: [0; Self::BYTES],
beyond: false,
}
}
#[must_use]
pub const fn with(mut self, cap: Capability) -> Self {
if cap.0 <= Self::MAX_BIT {
let byte = (cap.0 / 8) as usize;
self.bits[byte] |= 1 << (cap.0 % 8);
}
self
}
#[must_use]
pub const fn contains(self, cap: Capability) -> bool {
if cap.0 > Self::MAX_BIT {
return false;
}
let byte = (cap.0 / 8) as usize;
self.bits[byte] & (1 << (cap.0 % 8)) != 0
}
#[must_use]
pub fn is_empty(self) -> bool {
!self.beyond && self.bits.iter().all(|b| *b == 0)
}
#[must_use]
pub const fn has_bits_beyond_this_build(self) -> bool {
self.beyond
}
#[must_use]
pub fn from_bytes(bytes: &[u8]) -> Self {
let mut out = Self::new();
let take = bytes.len().min(Self::BYTES);
out.bits[..take].copy_from_slice(&bytes[..take]);
out.beyond = bytes[take..].iter().any(|b| *b != 0);
out
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
let end = self
.bits
.iter()
.rposition(|b| *b != 0)
.map_or(0, |i| i.saturating_add(1));
&self.bits[..end]
}
#[must_use]
pub fn difference(self, other: Self) -> Self {
let mut out = Self::new();
for i in 0..Self::BYTES {
out.bits[i] = self.bits[i] & !other.bits[i];
}
out.beyond = self.beyond;
out
}
#[must_use]
pub fn intersection(self, other: Self) -> Self {
let mut out = Self::new();
for i in 0..Self::BYTES {
out.bits[i] = self.bits[i] & other.bits[i];
}
out
}
#[must_use]
pub fn union(self, other: Self) -> Self {
let mut out = Self::new();
for i in 0..Self::BYTES {
out.bits[i] = self.bits[i] | other.bits[i];
}
out.beyond = self.beyond || other.beyond;
out
}
pub fn iter(&self) -> impl Iterator<Item = Capability> + '_ {
(0..=Self::MAX_BIT)
.map(Capability)
.filter(move |c| self.contains(*c))
}
}
const _: () = assert!(CapabilitySet::BYTES * 8 == CapabilitySet::MAX_BIT as usize + 1);
impl Reader<'_> {
pub fn capability_set(&mut self) -> crate::error::Result<CapabilitySet> {
Ok(CapabilitySet::from_bytes(self.var_bytes()?))
}
}