use crate::{
bits::{
BitIdx,
Bits,
},
pointer::BitPtr,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum BitDomainKind {
Empty,
Minor,
Major,
PartialHead,
PartialTail,
Spanning,
}
impl BitDomainKind {
pub fn is_empty(self) -> bool { self == BitDomainKind::Empty }
pub fn is_minor(self) -> bool { self == BitDomainKind::Minor }
pub fn is_major(self) -> bool { self == BitDomainKind::Major }
pub fn is_partial_head(self) -> bool { self == BitDomainKind::PartialHead }
pub fn is_partial_tail(self) -> bool { self == BitDomainKind::PartialTail }
pub fn is_spanning(self) -> bool { self == BitDomainKind::Spanning }
}
impl<T> From<&BitPtr<T>> for BitDomainKind
where T: Bits {
fn from(bitptr: &BitPtr<T>) -> Self {
let (e, h, t) = bitptr.region_data();
let w = T::BITS;
match (e, *h, *t) {
(0, _, _) => BitDomainKind::Empty,
(_, 0, t) if t == w => BitDomainKind::Spanning,
(_, _, t) if t == w => BitDomainKind::PartialHead,
(_, 0, _) => BitDomainKind::PartialTail,
(1, _, _) => BitDomainKind::Minor,
(_, _, _ ) => BitDomainKind::Major,
}
}
}
#[derive(Clone, Debug)]
pub enum BitDomain<'a, T>
where T: 'a + Bits {
Empty,
Minor(BitIdx, &'a T, BitIdx),
Major(BitIdx, &'a T, &'a [T], &'a T, BitIdx),
PartialHead(BitIdx, &'a T, &'a [T]),
PartialTail(&'a [T], &'a T, BitIdx),
Spanning(&'a [T]),
}
impl<'a, T> From<BitPtr<T>> for BitDomain<'a, T>
where T: 'a + Bits {
fn from(bitptr: BitPtr<T>) -> Self {
use BitDomainKind as Bdk;
let (e, h, t) = bitptr.region_data();
let data = bitptr.as_slice();
match bitptr.domain_kind() {
Bdk::Empty => BitDomain::Empty,
Bdk::Minor => BitDomain::Minor(h, &data[0], t),
Bdk::Major => BitDomain::Major(
h, &data[0], &data[1 .. e - 1], &data[e - 1], t
),
Bdk::PartialHead => BitDomain::PartialHead(
h, &data[0], &data[1 ..]
),
Bdk::PartialTail => BitDomain::PartialTail(
&data[.. e - 1], &data[e - 1], t
),
Bdk::Spanning => BitDomain::Spanning(data),
}
}
}
#[derive(Debug)]
pub enum BitDomainMut<'a, T>
where T: 'a + Bits {
Empty,
Minor(BitIdx, &'a mut T, BitIdx),
Major(BitIdx, &'a mut T, &'a mut [T], &'a mut T, BitIdx),
PartialHead(BitIdx, &'a mut T, &'a mut [T]),
PartialTail(&'a mut [T], &'a mut T, BitIdx),
Spanning(&'a mut [T]),
}
impl<'a, T> From<BitPtr<T>> for BitDomainMut<'a, T>
where T: 'a + Bits {
fn from(bitptr: BitPtr<T>) -> Self {
use BitDomainKind as Bdk;
let (h, t) = bitptr.cursors();
let data = bitptr.as_mut_slice();
match bitptr.domain_kind() {
Bdk::Empty => BitDomainMut::Empty,
Bdk::Minor => BitDomainMut::Minor(h, &mut data[0], t),
Bdk::Major => {
let (head, body) = data
.split_first_mut()
.expect("Major cannot fail to split head");
let (tail, body) = body
.split_last_mut()
.expect("Major cannot fail to split tail");
BitDomainMut::Major(h, head, body, tail, t)
},
Bdk::PartialHead => {
let (head, tail) = data
.split_first_mut()
.expect("PartialHead cannot fail to split");
BitDomainMut::PartialHead(h, head, tail)
},
Bdk::PartialTail => {
let (tail, head) = data
.split_last_mut()
.expect("PartialTail cannot fail to split");
BitDomainMut::PartialTail(head, tail, t)
},
Bdk::Spanning => BitDomainMut::Spanning(data),
}
}
}
#[cfg(all(test, feature = "testing"))]
mod tests {
use super::*;
#[test]
fn minor() {
let data: u8 = 0u8;
let bp = BitPtr::new(&data, 1, 1, 6);
assert!(bp.domain_kind().is_minor());
}
#[test]
fn major() {
let data: &[u16] = &[0u16, !0u16];
let bp = BitPtr::new(&data[0], 2, 1, 12);
assert!(bp.domain_kind().is_major());
}
#[test]
fn partial_head() {
let data: u32 = 0u32;
let bp = BitPtr::new(&data, 1, 4, 32);
assert!(bp.domain_kind().is_partial_head());
let data: &[u32] = &[0u32, !0u32];
let bp = BitPtr::new(&data[0], 2, 4, 32);
assert!(bp.domain_kind().is_partial_head());
}
#[test]
fn partial_tail() {
let data: u64 = 0u64;
let bp = BitPtr::new(&data, 1, 0, 60);
assert!(bp.domain_kind().is_partial_tail());
let data: &[u64] = &[0u64, !0u64];
let bp = BitPtr::new(&data[0], 2, 0, 60);
assert!(bp.domain_kind().is_partial_tail());
}
#[test]
fn spanning() {
let data: u8 = 0u8;
let bp = BitPtr::new(&data, 1, 0, 8);
assert!(bp.domain_kind().is_spanning());
let data: &[u16] = &[0u16, !0u16];
let bp = BitPtr::new(&data[0], 2, 0, 16);
assert!(bp.domain_kind().is_spanning());
}
}