#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(not(test), no_std)]
#![warn(missing_docs)]
use core::{cmp, fmt, hash, iter::FromIterator, mem, ops, slice};
#[cfg(feature = "rand")]
use rand as rand_core;
#[macro_use]
mod macros;
#[cfg(test)]
#[macro_use]
mod tests_macros;
#[cfg(test)]
mod tests;
pub(crate) mod chunk;
pub(crate) use chunk::Chunk;
mod iter;
pub use iter::Iter;
const SLOT_SIZE: usize = mem::size_of::<Chunk>();
const NUM_SLOTS: usize = 256 / 8 / SLOT_SIZE;
const LAST_SLOT_INDEX: usize = NUM_SLOTS - 1;
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct ByteSet([Chunk; NUM_SLOTS]);
#[inline]
const fn chunk_index_and_shift(byte: u8) -> (usize, usize) {
let byte = byte as usize;
#[cfg(target_pointer_width = "64")]
let index = byte >> 6;
#[cfg(target_pointer_width = "64")]
let shift = byte & 0b0011_1111;
#[cfg(not(target_pointer_width = "64"))]
let index = byte >> 5;
#[cfg(not(target_pointer_width = "64"))]
let shift = byte & 0b0001_1111;
(index, shift)
}
#[cfg(test)]
impl ByteSet {
pub(crate) fn fmt_binary<'a>(&'a self) -> impl fmt::Display + 'a {
struct Formatted<'a>(&'a ByteSet);
impl fmt::Display for Formatted<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for chunk in &(self.0).0 {
#[cfg(target_pointer_width = "64")]
write!(f, "{:064b}", chunk)?;
#[cfg(not(target_pointer_width = "64"))]
write!(f, "{:032b}", chunk)?;
}
Ok(())
}
}
Formatted(self)
}
}
impl ByteSet {
#[inline]
#[must_use]
pub const fn new() -> Self {
Self([0; NUM_SLOTS])
}
#[inline]
#[must_use]
pub const fn full() -> Self {
Self([Chunk::max_value(); NUM_SLOTS])
}
#[inline]
#[must_use]
pub const fn from_byte(byte: u8) -> Self {
byte_set![byte]
}
#[inline]
#[must_use]
pub const fn from_range_to(range: ops::RangeTo<u8>) -> Self {
const fn chunk_for(
this_chunk: usize,
byte_chunk: usize,
shift: usize,
) -> Chunk {
let value: Chunk = (1 << shift) - 1;
let is_equal = (this_chunk == byte_chunk) as usize;
let is_less_than = (this_chunk < byte_chunk) as usize;
let if_unequal = [0, Chunk::max_value()][is_less_than];
[if_unequal, value][is_equal]
}
let (index, shift) = chunk_index_and_shift(range.end);
#[cfg(target_pointer_width = "64")]
let array = [
chunk_for(0, index, shift),
chunk_for(1, index, shift),
chunk_for(2, index, shift),
chunk_for(3, index, shift),
];
#[cfg(not(target_pointer_width = "64"))]
let array = [
chunk_for(0, index, shift),
chunk_for(1, index, shift),
chunk_for(2, index, shift),
chunk_for(3, index, shift),
chunk_for(4, index, shift),
chunk_for(5, index, shift),
chunk_for(6, index, shift),
chunk_for(7, index, shift),
];
ByteSet(array)
}
#[inline]
#[must_use]
pub const fn from_range_to_inclusive(
range: ops::RangeToInclusive<u8>,
) -> Self {
[
Self::full(),
Self::from_range_to(..(range.end.wrapping_add(1))),
][(range.end != 255) as usize]
}
#[inline]
#[must_use]
pub const fn from_range_from(range: ops::RangeFrom<u8>) -> Self {
Self::from_range_to(..range.start).not()
}
#[inline]
#[must_use]
pub const fn from_range(range: ops::Range<u8>) -> Self {
Self::from_range_from(range.start..)
.intersection(Self::from_range_to(..range.end))
}
#[inline]
#[must_use]
pub const fn from_range_inclusive(range: ops::RangeInclusive<u8>) -> Self {
Self::from_range_from(*range.start()..)
.intersection(Self::from_range_to_inclusive(..=*range.end()))
}
#[cfg(any(feature = "rand", feature = "rand_core"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "rand", feature = "rand_core"))))]
#[inline]
pub fn rand<R: rand_core::RngCore>(mut rng: R) -> Self {
let mut set = Self::new();
rng.fill_bytes(set.as_bytes_mut());
set
}
#[cfg(any(feature = "rand", feature = "rand_core"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "rand", feature = "rand_core"))))]
#[inline]
pub fn try_rand<R: rand_core::RngCore>(
mut rng: R,
) -> Result<Self, rand_core::Error> {
let mut set = Self::new();
rng.try_fill_bytes(set.as_bytes_mut())?;
Ok(set)
}
#[inline]
#[must_use]
#[allow(clippy::let_and_return)]
pub const fn is_empty(&self) -> bool {
let is_empty = (self.0[0] == 0)
& (self.0[1] == 0)
& (self.0[2] == 0)
& (self.0[3] == 0);
#[cfg(not(target_pointer_width = "64"))]
{
is_empty
& (self.0[4] == 0)
& (self.0[5] == 0)
& (self.0[6] == 0)
& (self.0[7] == 0)
}
#[cfg(target_pointer_width = "64")]
is_empty
}
#[inline]
#[must_use]
#[allow(clippy::let_and_return)]
pub const fn is_full(&self) -> bool {
let is_full = (self.0[0] == !0)
& (self.0[1] == !0)
& (self.0[2] == !0)
& (self.0[3] == !0);
#[cfg(not(target_pointer_width = "64"))]
{
is_full
& (self.0[4] == !0)
& (self.0[5] == !0)
& (self.0[6] == !0)
& (self.0[7] == !0)
}
#[cfg(target_pointer_width = "64")]
is_full
}
#[cfg_attr(target_feature = "popcnt", inline)]
#[must_use]
#[allow(clippy::let_and_return)]
pub const fn len(&self) -> usize {
let len = (self.0[0].count_ones() as usize)
+ (self.0[1].count_ones() as usize)
+ (self.0[2].count_ones() as usize)
+ (self.0[3].count_ones() as usize);
#[cfg(not(target_pointer_width = "64"))]
{
len + (self.0[4].count_ones() as usize)
+ (self.0[5].count_ones() as usize)
+ (self.0[6].count_ones() as usize)
+ (self.0[7].count_ones() as usize)
}
#[cfg(target_pointer_width = "64")]
len
}
#[inline]
pub fn clear(&mut self) {
*self = ByteSet::new();
}
pub fn first(&self) -> Option<u8> {
for (i, &chunk) in self.0.iter().enumerate() {
if let Some(lsb) = chunk::lsb(chunk) {
return Some(lsb + (i * chunk::INDEX_OFFSET) as u8);
}
}
None
}
pub fn pop_first(&mut self) -> Option<u8> {
for (i, chunk) in self.0.iter_mut().enumerate() {
if let Some(lsb) = chunk::pop_lsb(chunk) {
return Some(lsb + (i * chunk::INDEX_OFFSET) as u8);
}
}
None
}
pub fn last(&self) -> Option<u8> {
for (i, &chunk) in self.0.iter().rev().enumerate() {
if let Some(msb) = chunk::msb(chunk) {
let i = LAST_SLOT_INDEX - i;
return Some(msb + (i * chunk::INDEX_OFFSET) as u8);
}
}
None
}
pub fn pop_last(&mut self) -> Option<u8> {
for (i, chunk) in self.0.iter_mut().rev().enumerate() {
if let Some(msb) = chunk::pop_msb(chunk) {
let i = LAST_SLOT_INDEX - i;
return Some(msb + (i * chunk::INDEX_OFFSET) as u8);
}
}
None
}
#[inline]
pub fn insert(&mut self, byte: u8) {
let (index, shift) = chunk_index_and_shift(byte);
self.0[index] |= 1 << shift;
}
#[inline]
pub fn insert_all(&mut self, other: Self) {
self.0[0] |= other.0[0];
self.0[1] |= other.0[1];
self.0[2] |= other.0[2];
self.0[3] |= other.0[3];
#[cfg(not(target_pointer_width = "64"))]
{
self.0[4] |= other.0[4];
self.0[5] |= other.0[5];
self.0[6] |= other.0[6];
self.0[7] |= other.0[7];
}
}
#[inline]
#[must_use]
pub const fn inserting(mut self, byte: u8) -> Self {
let (index, shift) = chunk_index_and_shift(byte);
self.0[index] |= 1 << shift;
self
}
#[inline]
#[must_use]
pub const fn inserting_all(self, other: Self) -> Self {
self.union(other)
}
#[inline]
pub fn remove(&mut self, byte: u8) {
let (index, shift) = chunk_index_and_shift(byte);
self.0[index] &= !(1 << shift);
}
#[inline]
pub fn remove_all(&mut self, other: Self) {
*self &= !other;
}
#[inline]
#[must_use]
pub const fn removing(mut self, byte: u8) -> Self {
let (index, shift) = chunk_index_and_shift(byte);
self.0[index] &= !(1 << shift);
self
}
#[inline]
#[must_use]
pub const fn removing_all(self, other: Self) -> Self {
self.difference(other)
}
#[inline]
pub fn set(&mut self, byte: u8, enabled: bool) {
let (index, shift) = chunk_index_and_shift(byte);
let chunk = self.0[index];
self.0[index] = (chunk & !(1 << shift)) | ((enabled as Chunk) << shift);
}
#[inline]
#[must_use]
pub const fn setting(mut self, byte: u8, enabled: bool) -> Self {
let (index, shift) = chunk_index_and_shift(byte);
let chunk = self.0[index];
self.0[index] = (chunk & !(1 << shift)) | ((enabled as Chunk) << shift);
self
}
#[inline]
#[must_use]
pub const fn contains(&self, byte: u8) -> bool {
let (index, shift) = chunk_index_and_shift(byte);
self.0[index] & (1 << shift) != 0
}
#[inline]
#[must_use]
const fn chunk_and_or(&self, other: &Self) -> Chunk {
map_reduce_chunks!(self, other, &, |)
}
#[inline]
#[must_use]
pub fn contains_any(&self, other: &Self) -> bool {
self.chunk_and_or(other) != 0
}
#[inline]
const fn _is_subset(&self, other: &Self) -> bool {
self.intersection(*other).eq(self)
}
#[inline]
#[must_use]
pub fn is_subset(&self, other: &Self) -> bool {
self._is_subset(other)
}
#[must_use]
pub fn is_strict_subset(&self, other: &Self) -> bool {
self.ne(other) && self.is_subset(other)
}
#[inline]
#[must_use]
pub fn is_superset(&self, other: &Self) -> bool {
other.is_subset(self)
}
#[inline]
#[must_use]
pub fn is_strict_superset(&self, other: &Self) -> bool {
other.is_strict_subset(self)
}
#[inline]
#[must_use]
pub fn is_disjoint(&self, other: &Self) -> bool {
self.intersection(*other).is_empty()
}
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
self.intersection(other.not())
}
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
map_chunks!(self, ^, other)
}
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
map_chunks!(self, &, other)
}
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
map_chunks!(self, |, other)
}
#[inline]
#[must_use]
#[allow(clippy::should_implement_trait)]
pub const fn not(self) -> Self {
map_chunks!(self, !)
}
#[must_use]
#[cfg_attr(target_arch = "aarch64", inline)]
pub const fn reverse_bits(self) -> Self {
Self([
#[cfg(not(target_pointer_width = "64"))]
self.0[7].reverse_bits(),
#[cfg(not(target_pointer_width = "64"))]
self.0[6].reverse_bits(),
#[cfg(not(target_pointer_width = "64"))]
self.0[5].reverse_bits(),
#[cfg(not(target_pointer_width = "64"))]
self.0[4].reverse_bits(),
self.0[3].reverse_bits(),
self.0[2].reverse_bits(),
self.0[1].reverse_bits(),
self.0[0].reverse_bits(),
])
}
#[inline]
#[must_use]
#[allow(clippy::should_implement_trait)]
#[allow(clippy::let_and_return)]
pub const fn eq(&self, other: &Self) -> bool {
let eq = (self.0[0] == other.0[0])
& (self.0[1] == other.0[1])
& (self.0[2] == other.0[2])
& (self.0[3] == other.0[3]);
#[cfg(not(target_pointer_width = "64"))]
{
eq & (self.0[4] == other.0[4])
& (self.0[5] == other.0[5])
& (self.0[6] == other.0[6])
& (self.0[7] == other.0[7])
}
#[cfg(target_pointer_width = "64")]
eq
}
#[inline]
#[must_use]
#[allow(clippy::should_implement_trait)]
pub const fn ne(&self, other: &Self) -> bool {
!self.eq(other)
}
}
impl ByteSet {
pub const ASCII: Self = {
#[cfg(target_pointer_width = "64")]
{
Self([!0, !0, 0, 0])
}
#[cfg(not(target_pointer_width = "64"))]
{
Self([!0, !0, !0, !0, 0, 0, 0, 0])
}
};
pub const ASCII_ALPHABETIC: Self =
Self::ASCII_LOWERCASE.inserting_all(Self::ASCII_UPPERCASE);
pub const ASCII_UPPERCASE: Self = Self::from_range_inclusive(b'A'..=b'Z');
pub const ASCII_LOWERCASE: Self = Self::from_range_inclusive(b'a'..=b'z');
pub const ASCII_ALPHANUMERIC: Self =
Self::ASCII_ALPHABETIC.inserting_all(Self::ASCII_DIGIT);
pub const ASCII_DIGIT: Self = Self::from_range_inclusive(b'0'..=b'9');
pub const ASCII_HEXDIGIT: Self = Self::ASCII_DIGIT
.inserting_all(Self::from_range_inclusive(b'A'..=b'F'))
.inserting_all(Self::from_range_inclusive(b'a'..=b'f'));
pub const ASCII_PUNCTUATION: Self = byte_set![
b'!', b'"', b'#', b'$', b'%', b'&', b'\'', b'(', b')', b'*', b'+',
b',', b'-', b'.', b'/', b':', b';', b'<', b'=', b'>', b'?', b'@', b'[',
b'\\', b']', b'^', b'_', b'`', b'{', b'|', b'}', b'~',
];
pub const ASCII_GRAPHIC: Self =
Self::ASCII_ALPHANUMERIC.inserting_all(Self::ASCII_PUNCTUATION);
pub const ASCII_WHITESPACE: Self =
byte_set![b'\t', b'\n', 0x0C, b'\r', b' '];
pub const ASCII_CONTROL: Self =
Self::from_range_inclusive(0..=0x1F).inserting(0x7F);
#[inline]
#[must_use]
pub const fn is_ascii(&self) -> bool {
self._is_subset(&Self::ASCII)
}
#[inline]
#[must_use]
pub const fn is_ascii_alphabetic(&self) -> bool {
self._is_subset(&Self::ASCII_ALPHABETIC)
}
#[inline]
#[must_use]
pub const fn is_ascii_uppercase(&self) -> bool {
self._is_subset(&Self::ASCII_UPPERCASE)
}
#[inline]
#[must_use]
pub const fn is_ascii_lowercase(&self) -> bool {
self._is_subset(&Self::ASCII_LOWERCASE)
}
#[inline]
#[must_use]
pub const fn is_ascii_alphanumeric(&self) -> bool {
self._is_subset(&Self::ASCII_ALPHANUMERIC)
}
#[inline]
#[must_use]
pub const fn is_ascii_digit(&self) -> bool {
self._is_subset(&Self::ASCII_DIGIT)
}
#[inline]
#[must_use]
pub const fn is_ascii_hexdigit(&self) -> bool {
self._is_subset(&Self::ASCII_HEXDIGIT)
}
#[inline]
#[must_use]
pub const fn is_ascii_punctuation(&self) -> bool {
self._is_subset(&Self::ASCII_PUNCTUATION)
}
#[inline]
#[must_use]
pub const fn is_ascii_graphic(&self) -> bool {
self._is_subset(&Self::ASCII_GRAPHIC)
}
#[inline]
#[must_use]
pub const fn is_ascii_whitespace(&self) -> bool {
self._is_subset(&Self::ASCII_WHITESPACE)
}
#[inline]
#[must_use]
pub const fn is_ascii_control(&self) -> bool {
self._is_subset(&Self::ASCII_CONTROL)
}
}
impl ByteSet {
const SIZE: usize = mem::size_of::<Self>();
#[inline]
pub fn as_bytes(&self) -> &[u8; Self::SIZE] {
unsafe { &*self.0.as_ptr().cast() }
}
#[inline]
pub fn as_bytes_mut(&mut self) -> &mut [u8; Self::SIZE] {
unsafe { &mut *self.0.as_mut_ptr().cast() }
}
#[inline]
pub fn slice_as_bytes(slice: &[Self]) -> &[u8] {
let ptr = slice.as_ptr().cast::<u8>();
let len = slice.len() * Self::SIZE;
unsafe { slice::from_raw_parts(ptr, len) }
}
#[inline]
pub fn slice_as_bytes_mut(slice: &mut [Self]) -> &mut [u8] {
let ptr = slice.as_mut_ptr().cast::<u8>();
let len = slice.len() * Self::SIZE;
unsafe { slice::from_raw_parts_mut(ptr, len) }
}
}
impl Default for ByteSet {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl From<u8> for ByteSet {
#[inline]
fn from(byte: u8) -> ByteSet {
ByteSet::from_byte(byte)
}
}
impl From<&[u8]> for ByteSet {
#[inline]
fn from(bytes: &[u8]) -> Self {
let mut set = ByteSet::new();
set.extend(bytes);
set
}
}
impl From<&str> for ByteSet {
#[inline]
fn from(s: &str) -> Self {
s.as_bytes().into()
}
}
impl From<ops::Range<u8>> for ByteSet {
#[inline]
fn from(range: ops::Range<u8>) -> Self {
Self::from_range(range)
}
}
impl From<ops::RangeTo<u8>> for ByteSet {
#[inline]
fn from(range: ops::RangeTo<u8>) -> Self {
Self::from_range_to(range)
}
}
impl From<ops::RangeFrom<u8>> for ByteSet {
#[inline]
fn from(range: ops::RangeFrom<u8>) -> Self {
Self::from_range_from(range)
}
}
impl From<ops::RangeInclusive<u8>> for ByteSet {
#[inline]
fn from(range: ops::RangeInclusive<u8>) -> Self {
Self::from_range_inclusive(range)
}
}
impl From<ops::RangeToInclusive<u8>> for ByteSet {
#[inline]
fn from(range: ops::RangeToInclusive<u8>) -> Self {
Self::from_range_to_inclusive(range)
}
}
impl From<ops::RangeFull> for ByteSet {
#[inline]
fn from(_: ops::RangeFull) -> Self {
Self::full()
}
}
impl Extend<u8> for ByteSet {
fn extend<T: IntoIterator<Item = u8>>(&mut self, iter: T) {
iter.into_iter().for_each(|byte| self.insert(byte));
}
}
impl<'a> Extend<&'a u8> for ByteSet {
fn extend<T: IntoIterator<Item = &'a u8>>(&mut self, iter: T) {
self.extend(iter.into_iter().cloned());
}
}
impl FromIterator<u8> for ByteSet {
fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
let mut set = ByteSet::new();
set.extend(iter);
set
}
}
impl<'a> FromIterator<&'a u8> for ByteSet {
fn from_iter<T: IntoIterator<Item = &'a u8>>(iter: T) -> Self {
iter.into_iter().cloned().collect()
}
}
impl IntoIterator for ByteSet {
type Item = u8;
type IntoIter = Iter;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.into()
}
}
impl fmt::Debug for ByteSet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_set().entries(*self).finish()
}
}
impl PartialOrd for ByteSet {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
#[inline]
fn lt(&self, other: &Self) -> bool {
self.as_bytes().lt(other.as_bytes())
}
#[inline]
fn le(&self, other: &Self) -> bool {
self.as_bytes().le(other.as_bytes())
}
#[inline]
fn gt(&self, other: &Self) -> bool {
self.as_bytes().gt(other.as_bytes())
}
#[inline]
fn ge(&self, other: &Self) -> bool {
self.as_bytes().ge(other.as_bytes())
}
}
impl Ord for ByteSet {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_bytes().cmp(other.as_bytes())
}
}
#[allow(clippy::derive_hash_xor_eq)]
impl hash::Hash for ByteSet {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_bytes().hash(state)
}
#[inline]
fn hash_slice<H: hash::Hasher>(data: &[Self], state: &mut H) {
Self::slice_as_bytes(data).hash(state)
}
}
impl ops::Sub for ByteSet {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self::Output {
self.removing_all(rhs)
}
}
impl ops::SubAssign for ByteSet {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
self.remove_all(rhs);
}
}
impl ops::BitAnd for ByteSet {
type Output = Self;
#[inline]
fn bitand(self, rhs: Self) -> Self::Output {
self.intersection(rhs)
}
}
impl ops::BitAndAssign for ByteSet {
#[inline]
fn bitand_assign(&mut self, rhs: Self) {
*self = *self & rhs;
}
}
impl ops::BitOr for ByteSet {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self::Output {
self.inserting_all(rhs)
}
}
impl ops::BitOrAssign for ByteSet {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
self.insert_all(rhs);
}
}
impl ops::BitXor for ByteSet {
type Output = Self;
#[inline]
fn bitxor(self, rhs: Self) -> Self::Output {
self.symmetric_difference(rhs)
}
}
impl ops::BitXorAssign for ByteSet {
#[inline]
fn bitxor_assign(&mut self, rhs: Self) {
*self = *self ^ rhs;
}
}
impl ops::Not for ByteSet {
type Output = Self;
#[inline]
fn not(self) -> Self::Output {
ByteSet::not(self)
}
}
#[cfg(feature = "rand")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
impl rand::distributions::Distribution<ByteSet>
for rand::distributions::Standard
{
#[inline]
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> ByteSet {
ByteSet::rand(rng)
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl serde::Serialize for ByteSet {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeSeq;
let mut seq = serializer.serialize_seq(Some(self.len()))?;
for byte in *self {
seq.serialize_element(&byte)?;
}
seq.end()
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'de> serde::Deserialize<'de> for ByteSet {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct ByteSetVisitor;
impl<'de> serde::de::Visitor<'de> for ByteSetVisitor {
type Value = ByteSet;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a set of bytes")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(v.into())
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut set = ByteSet::new();
while let Some(byte) = seq.next_element::<u8>()? {
set.insert(byte);
}
Ok(set)
}
}
deserializer.deserialize_seq(ByteSetVisitor)
}
}