use super::mode::Mode;
use super::tag::LineTag;
use crate::element::ParseAs;
use crate::{Error, ErrorKind};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ModeState {
active_mode: Mode,
default_mode: Mode,
previous_mode: Mode,
}
impl Default for ModeState {
fn default() -> Self {
Self::new()
}
}
impl ModeState {
pub const fn new() -> Self {
Self {
active_mode: Mode::OPEN,
default_mode: Mode::OPEN,
previous_mode: Mode::OPEN,
}
}
#[inline]
pub const fn get(&self) -> Mode {
self.active_mode
}
pub fn line_tag<'a>(&self, state: &'a crate::State) -> Option<LineTag<'a>> {
state.get_line_tag(self.active_mode)
}
const fn lock(&mut self, mode: Mode) {
self.active_mode = mode;
self.default_mode = mode;
}
pub const fn set(&mut self, mode: Mode) -> bool {
let closing = self.is_open() && !mode.is_open();
match mode {
Mode::SECURE_ONCE => {
self.previous_mode = self.active_mode;
self.active_mode = mode;
}
Mode::PERM_OPEN | Mode::RESET => self.lock(Mode::OPEN),
Mode::PERM_SECURE => self.lock(Mode::SECURE),
Mode::PERM_LOCKED => self.lock(Mode::LOCKED),
_ => self.active_mode = mode,
}
closing
}
pub const fn revert(&mut self) {
self.set(self.default_mode);
}
#[inline]
pub const fn use_secure(&mut self) -> bool {
if self.is_secure_once() {
self.active_mode = self.previous_mode;
return true;
}
!self.is_open()
}
#[inline]
pub fn validate_next_character(&mut self, c: u8) -> crate::Result<()> {
#[cold]
#[inline(never)]
fn create_error(c: u8) -> Error {
Error::new(c as char, ErrorKind::TextAfterSecureOnce)
}
if c == b'<' || !self.is_secure_once() {
return Ok(());
}
self.active_mode = self.previous_mode;
Err(create_error(c))
}
#[inline]
pub const fn is_secure_once(&self) -> bool {
self.active_mode.0 == Mode::SECURE_ONCE.0
}
#[inline]
pub const fn is_open(&self) -> bool {
self.active_mode.0 == Mode::OPEN.0 || self.active_mode.0 >= Mode::USER_DEFINED_MIN.0
}
#[inline]
pub const fn is_locked(&self) -> bool {
self.active_mode.0 == Mode::LOCKED.0
}
#[inline]
pub const fn is_automapping(&self) -> bool {
self.active_mode.is_automapping()
}
#[inline]
pub fn parse_as(&self) -> Option<ParseAs> {
self.active_mode.parse_as()
}
#[inline]
pub const fn is_user_defined(&self) -> bool {
self.active_mode.is_user_defined()
}
}