use std::{fmt, num::NonZeroU16};
use serde::{Deserialize, Serialize};
#[derive(Default, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub struct Place(Option<NonZeroU16>);
impl fmt::Debug for Place {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn u8_to_str(f: &mut fmt::Formatter<'_>, num: u8, len: u8) -> fmt::Result {
for i in (0..len).rev() {
match num & (1 << i) != 0 {
true => write!(f, "+", )?,
false => write!(f, "-", )?,
}
}
Ok(())
}
match self.get_labial() {
Some(lab) => u8_to_str(f, lab, 2)?,
None => write!(f, "00")?
}
write!(f, "|")?;
match self.get_coronal() {
Some(cor) => u8_to_str(f, cor, 2)?,
None => write!(f, "00")?
}
write!(f, "|")?;
match self.get_dorsal() {
Some(dor) => u8_to_str(f, dor, 6)?,
None => write!(f, "000000")?
}
write!(f, "|")?;
match self.get_pharyngeal() {
Some(phr) => u8_to_str(f, phr, 2),
None => write!(f, "00"),
}
}
}
impl std::ops::Deref for Place {
type Target = Option<NonZeroU16>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for Place {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Place {
const LAB_BIT: u16 = 0x8000;
const COR_BIT: u16 = 0x4000;
const DOR_BIT: u16 = 0x2000;
const PHR_BIT: u16 = 0x1000;
const LAB_LOW: u16 = 0xc00;
const COR_LOW: u16 = 0x300;
const DOR_LOW: u16 = 0x0FC;
const PHR_LOW: u16 = 0x003;
const LAB_OFF: u8 = 10;
const COR_OFF: u8 = 8;
const DOR_OFF: u8 = 2;
const LAB_MSK: u16 = 0x03;
const COR_MSK: u16 = 0x03;
const DOR_MSK: u16 = 0x3F;
const PHR_MSK: u16 = 0x03;
pub fn is_some(&self) -> bool {
self.0.is_some()
}
pub fn is_none(&self) -> bool {
self.0.is_none()
}
pub fn labial_is_some(&self) -> bool {
match self.0 {
Some(x) => Self::LAB_BIT & x.get() == Self::LAB_BIT,
None => false,
}
}
pub fn labial_is_none(&self) -> bool {
!self.labial_is_some()
}
pub fn coronal_is_some(&self) -> bool {
match self.0 {
Some(x) => Self::COR_BIT & x.get() == Self::COR_BIT,
None => false,
}
}
pub fn coronal_is_none(&self) -> bool {
!self.coronal_is_some()
}
pub fn dorsal_is_some(&self) -> bool {
match self.0 {
Some(x) => Self::DOR_BIT & x.get() == Self::DOR_BIT,
None => false,
}
}
pub fn dorsal_is_none(&self) -> bool {
!self.dorsal_is_some()
}
pub fn pharyngeal_is_some(&self) -> bool {
match self.0 {
Some(x) => Self::PHR_BIT & x.get() == Self::PHR_BIT,
None => false,
}
}
pub fn pharyngeal_is_none(&self) -> bool {
!self.pharyngeal_is_some()
}
pub fn get_labial(&self) -> Option<u8> {
if self.labial_is_some() {
Some(((unsafe { self.0.unwrap_unchecked().get() } >> Self::LAB_OFF) & Self::LAB_MSK) as u8)
} else {
None
}
}
pub fn get_coronal(&self) -> Option<u8> {
if self.coronal_is_some() {
Some(((unsafe { self.0.unwrap_unchecked().get() } >> Self::COR_OFF) & Self::COR_MSK) as u8)
} else {
None
}
}
pub fn get_dorsal(&self) -> Option<u8> {
if self.dorsal_is_some() {
Some(((unsafe { self.0.unwrap_unchecked().get() } >> Self::DOR_OFF) & Self::DOR_MSK) as u8)
} else {
None
}
}
pub fn get_pharyngeal(&self) -> Option<u8> {
if self.pharyngeal_is_some() {
Some((unsafe { self.0.unwrap_unchecked().get() } & Self::PHR_MSK) as u8)
} else {
None
}
}
pub fn set_labial(&mut self, bits: Option<u8>) {
debug_assert!(bits <= Some(Self::LAB_MSK as u8), "Only lower two bits are used");
self.0 = NonZeroU16::new(match bits {
Some(bts) => match &self.0 {
Some(num) => ((num.get() | Self::LAB_BIT) & !Self::LAB_LOW) | ((bts as u16) << Self::LAB_OFF),
None => Self::LAB_BIT | ((Self::LAB_MSK & bts as u16) << Self::LAB_OFF),
},
None => match &self.0 {
Some(num) => num.get() & !(Self::LAB_BIT | Self::LAB_LOW),
None => 0,
},
});
}
pub fn set_coronal(&mut self, bits: Option<u8>) {
debug_assert!(bits <= Some(Self::COR_MSK as u8), "Only lower two bits are used");
self.0 = NonZeroU16::new(match bits {
Some(bts) => match &self.0 {
Some(num) => ((num.get() | Self::COR_BIT) & !Self::COR_LOW) | ((bts as u16) << Self::COR_OFF),
None => Self::COR_BIT | ((Self::COR_MSK & bts as u16) << Self::COR_OFF),
},
None => match &self.0 {
Some(num) => num.get() & !(Self::COR_BIT | Self::COR_LOW),
None => 0,
},
});
}
pub fn set_dorsal(&mut self, bits: Option<u8>) {
debug_assert!(bits <= Some(Self::DOR_MSK as u8), "Only lower six bits are used");
self.0 = NonZeroU16::new(match bits {
Some(bts) => match &self.0 {
Some(num) => ((num.get() | Self::DOR_BIT) & !Self::DOR_LOW) | ((bts as u16) << Self::DOR_OFF),
None => Self::DOR_BIT | ((Self::DOR_MSK & bts as u16) << Self::DOR_OFF),
},
None => match &self.0 {
Some(num) => num.get() & !(Self::DOR_BIT | Self::DOR_LOW),
None => 0,
},
});
}
pub fn set_pharyngeal(&mut self, bits: Option<u8>) {
debug_assert!(bits <= Some(Self::PHR_MSK as u8), "Only lower two bits are used");
self.0 = NonZeroU16::new(match bits {
Some(bts) => match &self.0 {
Some(num) => ((num.get() | Self::PHR_BIT) & !Self::PHR_LOW) | bts as u16,
None => Self::PHR_BIT | (Self::PHR_MSK & bts as u16),
},
None => match &self.0 {
Some(num) => num.get() & !(Self::PHR_BIT | Self::PHR_LOW),
None => 0,
},
});
}
}