#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum RequireIndent {
Unchecked,
Divisible(usize),
Even,
Uniform(Option<usize>),
}
impl RequireIndent {
pub fn is_valid(&mut self, n: usize) -> Result<(), crate::de_error::Error> {
let ok = match self {
RequireIndent::Unchecked => true,
RequireIndent::Divisible(d) => n.is_multiple_of(*d),
RequireIndent::Even => n.is_multiple_of(2),
RequireIndent::Uniform(remembered) => {
if n == 0 {
return Ok(());
}
match *remembered {
None => {
*remembered = Some(n);
true
}
Some(expected) => n.is_multiple_of(expected),
}
}
};
if ok {
Ok(())
} else {
Err(crate::de_error::Error::IndentationError {
required: *self,
actual: n,
location: crate::location::Location::UNKNOWN,
})
}
}
}
impl std::fmt::Display for RequireIndent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RequireIndent::Unchecked => write!(f, "unchecked"),
RequireIndent::Divisible(n) => write!(f, "divisible by {n}"),
RequireIndent::Even => write!(f, "even"),
RequireIndent::Uniform(Some(n)) => write!(f, "uniform ({n} spaces)"),
RequireIndent::Uniform(None) => write!(f, "uniform"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unchecked_always_valid() {
let mut r = RequireIndent::Unchecked;
r.is_valid(0).unwrap();
r.is_valid(1).unwrap();
r.is_valid(7).unwrap();
r.is_valid(100).unwrap();
}
#[test]
fn divisible_by_4() {
let mut r = RequireIndent::Divisible(4);
r.is_valid(0).unwrap();
r.is_valid(4).unwrap();
r.is_valid(8).unwrap();
r.is_valid(1).unwrap_err();
r.is_valid(3).unwrap_err();
r.is_valid(5).unwrap_err();
}
#[test]
fn divisible_by_1() {
let mut r = RequireIndent::Divisible(1);
r.is_valid(0).unwrap();
r.is_valid(1).unwrap();
r.is_valid(999).unwrap();
}
#[test]
fn even_accepts_even_numbers() {
let mut r = RequireIndent::Even;
r.is_valid(0).unwrap();
r.is_valid(2).unwrap();
r.is_valid(4).unwrap();
r.is_valid(100).unwrap();
}
#[test]
fn even_rejects_odd_numbers() {
let mut r = RequireIndent::Even;
r.is_valid(1).unwrap_err();
r.is_valid(3).unwrap_err();
r.is_valid(99).unwrap_err();
}
#[test]
fn uniform_remembers_first_nonzero() {
let mut r = RequireIndent::Uniform(None);
r.is_valid(0).unwrap(); assert_eq!(r, RequireIndent::Uniform(None));
r.is_valid(4).unwrap(); assert_eq!(r, RequireIndent::Uniform(Some(4)));
}
#[test]
fn uniform_accepts_multiples_of_remembered() {
let mut r = RequireIndent::Uniform(Some(2));
r.is_valid(0).unwrap();
r.is_valid(2).unwrap();
r.is_valid(4).unwrap();
r.is_valid(6).unwrap();
}
#[test]
fn uniform_rejects_non_multiples() {
let mut r = RequireIndent::Uniform(Some(4));
r.is_valid(3).unwrap_err();
r.is_valid(5).unwrap_err();
r.is_valid(7).unwrap_err();
}
#[test]
fn uniform_zero_always_valid_even_after_set() {
let mut r = RequireIndent::Uniform(Some(3));
r.is_valid(0).unwrap();
}
#[test]
fn display_unchecked() {
assert_eq!(RequireIndent::Unchecked.to_string(), "unchecked");
}
#[test]
fn display_divisible() {
assert_eq!(RequireIndent::Divisible(4).to_string(), "divisible by 4");
}
#[test]
fn display_even() {
assert_eq!(RequireIndent::Even.to_string(), "even");
}
#[test]
fn display_uniform_none() {
assert_eq!(RequireIndent::Uniform(None).to_string(), "uniform");
}
#[test]
fn display_uniform_some() {
assert_eq!(
RequireIndent::Uniform(Some(2)).to_string(),
"uniform (2 spaces)"
);
}
}