ojcmp 0.4.0

online judge comparer
Documentation
use super::{CompareError, Comparison};

use std::cmp::Ordering;
use std::io::{self, BufRead};

pub fn try_strict_compare(
    std_reader: &mut impl BufRead,
    user_reader: &mut impl BufRead,
) -> Result<Comparison, CompareError> {
    strict_compare(std_reader, user_reader).map_err(CompareError::Io)
}

fn fill_buf(reader: &mut impl BufRead) -> io::Result<Option<&[u8]>> {
    let buf = reader.fill_buf()?;
    if buf.is_empty() {
        Ok(None)
    } else {
        Ok(Some(buf))
    }
}

fn strict_compare(
    std_reader: &mut impl BufRead,
    user_reader: &mut impl BufRead,
) -> io::Result<Comparison> {
    loop {
        let std_buf = fill_buf(std_reader)?;
        let user_buf = fill_buf(user_reader)?;
        let std_len;
        let user_len;

        match (std_buf, user_buf) {
            (None, None) => return Ok(Comparison::AC),
            (Some(_), None) | (None, Some(_)) => return Ok(Comparison::WA),
            (Some(lhs), Some(rhs)) => match lhs.len().cmp(&rhs.len()) {
                Ordering::Equal => {
                    if lhs != rhs {
                        return Ok(Comparison::WA);
                    }
                    std_len = lhs.len();
                    user_len = rhs.len();
                }
                Ordering::Less => {
                    let rhs = &rhs[..lhs.len()];
                    if lhs != rhs {
                        return Ok(Comparison::WA);
                    }
                    std_len = lhs.len();
                    user_len = rhs.len();
                }
                Ordering::Greater => {
                    let lhs = &lhs[..rhs.len()];
                    if lhs != rhs {
                        return Ok(Comparison::WA);
                    }
                    std_len = lhs.len();
                    user_len = rhs.len();
                }
            },
        }
        std_reader.consume(std_len);
        user_reader.consume(user_len);
    }
}

#[test]
fn test_strict_comparer() {
    macro_rules! judge {
        ($ret:expr, $std:expr,$user:expr) => {{
            let mut std: &[u8] = $std.as_ref();
            let mut user: &[u8] = $user.as_ref();

            let ret = strict_compare(&mut std, &mut user).unwrap();
            assert_eq!(ret, $ret);
        }};
    }

    use Comparison::*;

    judge!(AC, b"", b"");
    judge!(AC, b"1", b"1");
    judge!(AC, b"12", b"12");

    judge!(WA, b"", b"a");
    judge!(WA, b"a", b"");
    judge!(WA, b"ab", b"ba");
    judge!(WA, b"cc", b"ccc");
    judge!(WA, b"ccc", b"cc");
}