<commit_before>const BASE: u128 = 62;

// How much to add to the least-significant five bits of a byte to get the digit's
// value.
//
// Index 1: decimal digits
// Index 2: uppercase letters
// Index 3: lowercase letters
const STANDARD_OFFSETS: u32 = u32::from_le_bytes([0, -16_i8 as u8, 9, 35]);
const ALTERNATIVE_OFFSETS: u32 = u32::from_le_bytes([0, -16_i8 as u8, 35, 9]);

#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum DecodeError {
    InvalidBase62Byte(u8, usize),
    ArithmeticOverflow,
}

impl core::fmt::Display for DecodeError {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        match *self {
            DecodeError::InvalidBase62Byte(ch, idx) => {
                use core::fmt::Write;

                f.write_str("Invalid byte b'")?;
                for char_in_escape in core::ascii::escape_default(ch) {
                    f.write_char(char::from(char_in_escape))?;
                }
                write!(f, "' at position {}", idx)
            }
            DecodeError::ArithmeticOverflow => write!(f, "Decoded number is too large"),
        }
    }
}

// Finds out how many base62 digits a value encodes into.
pub(crate) fn digit_count(mut n: u128) -> usize {
    const BASE_TO_2: u128 = BASE.pow(2);
    const BASE_TO_3: u128 = BASE.pow(3);
    const BASE_TO_6: u128 = BASE.pow(6);
    const BASE_TO_11: u128 = BASE.pow(11);

    let mut result = 1;

    if n >= BASE_TO_11 {
        result += 11;
        n /= BASE_TO_11;
    }
    if n >= BASE_TO_6 {
        result += 6;
        n /= BASE_TO_6;
    }
    if n >= BASE_TO_3 {
        result += 3;
        n /= BASE_TO_3;
    }
    if n >= BASE_TO_2 {
        result += 2;
        n /= BASE_TO_2;
    }
    if n >= BASE {
        result += 1;
    }

    result
}

macro_rules! internal_encoder_fn {
    ($fn_name:ident, $numeric_offset:literal, $first_letters_offset:literal, $last_letters_offset:literal) => {
        // # Safety
        //
        // With this function, `buf` MUST ALREADY have its capacity extended
        // to hold all the new base62 characters that will be added
        unsafe fn $fn_name(mut num: u128, digits: usize, buf: &mut String) {
            let buf_vec = buf.as_mut_vec();
            let new_len = buf_vec.len().wrapping_add(digits);
            let mut ptr = buf_vec.as_mut_ptr().add(new_len.wrapping_sub(1));

            for _ in 0..digits {
                ::core::ptr::write(ptr, {
                    let digit = (num % $crate::BASE) as u8;
                    match digit {
                        0..=9 => digit.wrapping_add($numeric_offset),
                        10..=35 => digit.wrapping_add($first_letters_offset),
                        _ => digit.wrapping_add($last_letters_offset),
                    }
                });
                ptr = ptr.sub(1);

                num /= $crate::BASE;
            }

            buf_vec.set_len(new_len);
        }
    };
}

// # Safety
//
// With these functions, `buf` MUST ALREADY have its capacity extended
// to hold all the new base62 characters that will be added
internal_encoder_fn!(_encode_buf, 48, 55, 61);
internal_encoder_fn!(_encode_alternative_buf, 48, 87, 29);

/// Encodes a uint into base62, using the standard digit ordering
/// (0 to 9, then A to Z, then a to z), and returns the resulting `String`.
///
/// # Example
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let b62 = base62::encode(1337_u32);
///     assert_eq!(b62, "LZ");
/// }
/// ```
#[must_use = "this allocates a new `String`"]
pub fn encode<T: Into<u128>>(num: T) -> String {
    let num = num.into();
    let digits = digit_count(num);
    let mut buf = String::with_capacity(digits);
    unsafe {
        _encode_buf(num, digits, &mut buf);
    }
    buf
}

/// Appends a uint encoded into base62, using the standard digit ordering
/// (0 to 9, then A to Z, then a to z), onto the end of a `String`.
///
/// # Example
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let mut buf = String::new();
///     base62::encode_buf(1337_u32, &mut buf);
///     assert_eq!(buf, "LZ");
/// }
/// ```
pub fn encode_buf<T: Into<u128>>(num: T, buf: &mut String) {
    let num = num.into();
    let digits = digit_count(num);
    buf.reserve(digits);
    unsafe {
        _encode_buf(num, digits, buf);
    }
}

/// Encodes a uint into base62, using the alternative digit ordering
/// (0 to 9, then a to z, then A to Z) with lowercase letters before uppercase letters,
/// and returns the resulting `String`.
///
/// # Example
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let b62 = base62::encode(1337_u32);
///     assert_eq!(b62, "LZ");
/// }
/// ```
#[must_use = "this allocates a new `String`"]
pub fn encode_alternative<T: Into<u128>>(num: T) -> String {
    let num = num.into();
    let digits = digit_count(num);
    let mut buf = String::with_capacity(digits);
    unsafe {
        _encode_alternative_buf(num, digits, &mut buf);
    }
    buf
}

/// Appends a uint encoded into base62, using the alternative digit ordering
/// (0 to 9, then a to z, then A to Z) with lowercase letters before uppercase letters,
/// onto the end of a `String`.
///
/// # Example
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let mut buf = String::new();
///     base62::encode_alternative_buf(1337_u32, &mut buf);
///     assert_eq!(buf, "lz");
/// }
/// ```
pub fn encode_alternative_buf<T: Into<u128>>(num: T, buf: &mut String) {
    let num = num.into();
    let digits = digit_count(num);
    buf.reserve(digits);
    unsafe {
        _encode_alternative_buf(num, digits, buf);
    }
}

macro_rules! internal_decoder_fn {
    ($fn_name:ident, $offsets:ident) => {
        fn $fn_name(input: &[u8]) -> Result<u128, DecodeError> {
            let mut result = 0_u128;
            for (i, &ch) in input.iter().enumerate() {
                if ch.is_ascii_alphanumeric() {
                    result = result
                        .checked_mul(BASE)
                        .and_then(|x| {
                            x.checked_add((ch & 0b0001_1111).wrapping_add(
                                $offsets.wrapping_shr((ch.wrapping_shr(2) & 0b0001_1000) as u32)
                                    as u8,
                            ) as u128)
                        })
                        .ok_or($crate::DecodeError::ArithmeticOverflow)?
                } else {
                    return Err($crate::DecodeError::InvalidBase62Byte(ch, i));
                }
            }

            Ok(result)
        }
    };
}

internal_decoder_fn!(_decode, STANDARD_OFFSETS);
internal_decoder_fn!(_decode_alternative, ALTERNATIVE_OFFSETS);

/// Decodes a base62 byte slice or an equivalent like a `String` using the standard
/// digit ordering (0 to 9, then A to Z, then a to z).
///
/// Returns a Result containing a `u128`, which can be downcasted to any other uint.
///
/// # Examples
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let value = base62::decode("rustlang").unwrap();
///     assert_eq!(value, 189876682536016);
/// }
/// ```
#[must_use = "this returns the decoded result without modifying the original"]
pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<u128, DecodeError> {
    _decode(input.as_ref())
}

/// Decodes a base62 byte slice or an equivalent like a `String` using the alternative
/// digit ordering (0 to 9, then a to z, then A to Z) with lowercase letters before
/// uppercase letters.
///
/// Returns a Result containing a `u128`, which can be downcasted to any other uint.
///
/// # Examples
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let value = base62::decode_alternative("rustlang").unwrap();
///     assert_eq!(value, 96813686712946);
/// }
/// ```
#[must_use = "this returns the decoded result without modifying the original"]
pub fn decode_alternative<T: AsRef<[u8]>>(input: T) -> Result<u128, DecodeError> {
    _decode_alternative(input.as_ref())
}

#[cfg(test)]
mod tests {
    use super::*;
    use quickcheck::{quickcheck, TestResult};

    quickcheck! {
        fn encode_decode(xs: u128) -> bool {
            let encoded = encode(xs);
            xs == decode(&encoded).unwrap()
        }
    }

    quickcheck! {
        fn decode_good(xs: String) -> TestResult {
            if xs.chars().all(|ch| ch.is_ascii_alphanumeric()) && !xs.is_empty() {
                TestResult::from_bool(decode(&xs).is_ok())
            } else {
                TestResult::discard()
            }
        }
    }

    quickcheck! {
        fn decode_bad(xs: String) -> TestResult {
            if xs.chars().all(|ch| ch.is_ascii_alphanumeric()) {
                TestResult::discard()
            } else {
                TestResult::from_bool(decode(&xs).is_err())
            }
        }
    }

    #[test]
    fn test_encode() {
        assert_eq!(encode(u128::MAX), "7n42DGM5Tflk9n8mt7Fhc7");
        assert_eq!(encode(0_u8), "0");
    }

    #[test]
    fn test_encode_buf() {
        let mut buf = String::new();
        encode_buf(u128::MAX, &mut buf);
        assert_eq!(buf, "7n42DGM5Tflk9n8mt7Fhc7");
    }

    #[test]
    fn test_encode_alternative() {
        assert_eq!(encode_alternative(691337691337_u128), "caCOuUN");
        assert_eq!(encode_alternative(0_u8), "0");
    }

    #[test]
    fn test_encode_alternative_buf() {
        let mut buf = String::new();
        encode_alternative_buf(691337691337_u128, &mut buf);
        assert_eq!(buf, "caCOuUN");
    }

    #[test]
    fn test_decode() {
        assert_eq!(decode("7n42DGM5Tflk9n8mt7Fhc7").unwrap(), u128::MAX);
        assert_eq!(decode("").unwrap(), 0);
    }

    #[test]
    fn test_decode_invalid_char() {
        assert_eq!(
            decode("ds{Z455f"),
            Err(DecodeError::InvalidBase62Byte(b'{', 2))
        );
    }

    #[test]
    fn test_decode_long_string() {
        assert_eq!(
            decode("7n42DGM5Tflk9n8mt7Fhc78"),
            Err(DecodeError::ArithmeticOverflow)
        );
    }

    #[test]
    fn test_decode_alternative() {
        assert_eq!(
            decode_alternative("7N42dgm5tFLK9N8MT7fHC7").unwrap(),
            u128::MAX
        );
        assert_eq!(decode_alternative("").unwrap(), 0);
    }

    #[test]
    fn test_decode_alternative_invalid_char() {
        assert_eq!(
            decode_alternative("ds{Z455f"),
            Err(DecodeError::InvalidBase62Byte(b'{', 2))
        );
    }

    #[test]
    fn test_decode_alternative_long_string() {
        assert_eq!(
            decode_alternative("7N42dgm5tFLK9N8MT7fHC8"),
            Err(DecodeError::ArithmeticOverflow)
        );
    }

    #[test]
    fn test_digit_count() {
        // The maximum length of a base62-encoded `u128`.
        let max_encoded_len: usize = core::iter::successors(Some(u128::MAX), |&n| Some(n / BASE))
            .take_while(|&n| n != 0)
            .count();

        // Assume that `digit_count` is a monotonically increasing function and
        // check that the boundaries have the right values.
        assert_eq!(digit_count(0), 1);
        assert_eq!(digit_count(BASE.pow(0)), 1);
        for pow in 1..max_encoded_len {
            let this_power = BASE.pow(pow as u32);

            assert_eq!(digit_count(this_power - 1), pow);
            assert_eq!(digit_count(this_power), pow + 1);
        }
        assert_eq!(digit_count(u128::MAX), 22);
    }
}
<commit_msg>Encoding is now 3 times faster; tests no longer use `unwrap`<commit_after>const BASE: u64 = 62;
const BASE_TO_2: u64 = BASE.pow(2);
const BASE_TO_3: u64 = BASE.pow(3);
const BASE_TO_6: u128 = (BASE as u128).pow(6);
const BASE_TO_10: u64 = BASE.pow(10);
const BASE_TO_11: u128 = (BASE as u128).pow(11);

// How much to add to the least-significant five bits of a byte to get the digit's
// value.
//
// Index 1: decimal digits
// Index 2: uppercase letters
// Index 3: lowercase letters
const STANDARD_OFFSETS: u32 = u32::from_le_bytes([0, -16_i8 as u8, 9, 35]);
const ALTERNATIVE_OFFSETS: u32 = u32::from_le_bytes([0, -16_i8 as u8, 35, 9]);

#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum DecodeError {
    InvalidBase62Byte(u8, usize),
    ArithmeticOverflow,
}

impl core::fmt::Display for DecodeError {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        match *self {
            DecodeError::InvalidBase62Byte(ch, idx) => {
                use core::fmt::Write;

                f.write_str("Invalid byte b'")?;
                for char_in_escape in core::ascii::escape_default(ch) {
                    f.write_char(char::from(char_in_escape))?;
                }
                write!(f, "' at position {}", idx)
            }
            DecodeError::ArithmeticOverflow => write!(f, "Decoded number is too large"),
        }
    }
}

// Finds out how many base62 digits a value encodes into.
pub(crate) fn digit_count(mut n: u128) -> usize {
    let mut result = 1;

    if n >= BASE_TO_11 {
        result += 11;
        n /= BASE_TO_11;
    }
    if n >= BASE_TO_6 {
        result += 6;
        n /= BASE_TO_6;
    }
    let mut n = n as u64;
    if n >= BASE_TO_3 {
        result += 3;
        n /= BASE_TO_3;
    }
    if n >= BASE_TO_2 {
        result += 2;
        n /= BASE_TO_2;
    }
    if n >= BASE {
        result += 1;
    }

    result
}

macro_rules! internal_encoder_fn {
    ($fn_name:ident, $numeric_offset:literal, $first_letters_offset:literal, $last_letters_offset:literal) => {
        // # Safety
        //
        // With this function, `buf` MUST ALREADY have its capacity extended
        // to hold all the new base62 characters that will be added
        unsafe fn $fn_name(mut num: u128, digits: usize, buf: &mut String) {
            let buf_vec = buf.as_mut_vec();
            let new_len = buf_vec.len().wrapping_add(digits);
            let mut ptr = buf_vec.as_mut_ptr().add(new_len.wrapping_sub(1));

            let mut digit_index = 0_usize;
            let mut u64_num = (num % ($crate::BASE_TO_10 as u128)) as u64;
            num /= $crate::BASE_TO_10 as u128;
            loop {
                ::core::ptr::write(ptr, {
                    let digit = (u64_num % $crate::BASE) as u8;
                    match digit {
                        0..=9 => digit.wrapping_add($numeric_offset),
                        10..=35 => digit.wrapping_add($first_letters_offset),
                        _ => digit.wrapping_add($last_letters_offset),
                    }
                });
                ptr = ptr.sub(1);

                digit_index = digit_index.wrapping_add(1);
                match digit_index {
                    _ if digit_index == digits => break,
                    10 => {
                        u64_num = (num % ($crate::BASE_TO_10 as u128)) as u64;
                        num /= $crate::BASE_TO_10 as u128;
                    }
                    20 => u64_num = num as u64,
                    _ => u64_num /= $crate::BASE,
                }
            }

            buf_vec.set_len(new_len);
        }
    };
}

// # Safety
//
// With these functions, `buf` MUST ALREADY have its capacity extended
// to hold all the new base62 characters that will be added
internal_encoder_fn!(_encode_buf, 48, 55, 61);
internal_encoder_fn!(_encode_alternative_buf, 48, 87, 29);

/// Encodes a uint into base62, using the standard digit ordering
/// (0 to 9, then A to Z, then a to z), and returns the resulting `String`.
///
/// # Example
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let b62 = base62::encode(1337_u32);
///     assert_eq!(b62, "LZ");
/// }
/// ```
#[must_use = "this allocates a new `String`"]
pub fn encode<T: Into<u128>>(num: T) -> String {
    let num = num.into();
    let digits = digit_count(num);
    let mut buf = String::with_capacity(digits);
    unsafe {
        _encode_buf(num, digits, &mut buf);
    }
    buf
}

/// Appends a uint encoded into base62, using the standard digit ordering
/// (0 to 9, then A to Z, then a to z), onto the end of a `String`.
///
/// # Example
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let mut buf = String::new();
///     base62::encode_buf(1337_u32, &mut buf);
///     assert_eq!(buf, "LZ");
/// }
/// ```
pub fn encode_buf<T: Into<u128>>(num: T, buf: &mut String) {
    let num = num.into();
    let digits = digit_count(num);
    buf.reserve(digits);
    unsafe {
        _encode_buf(num, digits, buf);
    }
}

/// Encodes a uint into base62, using the alternative digit ordering
/// (0 to 9, then a to z, then A to Z) with lowercase letters before uppercase letters,
/// and returns the resulting `String`.
///
/// # Example
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let b62 = base62::encode(1337_u32);
///     assert_eq!(b62, "LZ");
/// }
/// ```
#[must_use = "this allocates a new `String`"]
pub fn encode_alternative<T: Into<u128>>(num: T) -> String {
    let num = num.into();
    let digits = digit_count(num);
    let mut buf = String::with_capacity(digits);
    unsafe {
        _encode_alternative_buf(num, digits, &mut buf);
    }
    buf
}

/// Appends a uint encoded into base62, using the alternative digit ordering
/// (0 to 9, then a to z, then A to Z) with lowercase letters before uppercase letters,
/// onto the end of a `String`.
///
/// # Example
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let mut buf = String::new();
///     base62::encode_alternative_buf(1337_u32, &mut buf);
///     assert_eq!(buf, "lz");
/// }
/// ```
pub fn encode_alternative_buf<T: Into<u128>>(num: T, buf: &mut String) {
    let num = num.into();
    let digits = digit_count(num);
    buf.reserve(digits);
    unsafe {
        _encode_alternative_buf(num, digits, buf);
    }
}

macro_rules! internal_decoder_fn {
    ($fn_name:ident, $offsets:ident) => {
        fn $fn_name(input: &[u8]) -> Result<u128, DecodeError> {
            let mut result = 0_u128;
            for (i, &ch) in input.iter().enumerate() {
                if ch.is_ascii_alphanumeric() {
                    result = result
                        .checked_mul(BASE as u128)
                        .and_then(|x| {
                            x.checked_add((ch & 0b0001_1111).wrapping_add(
                                $offsets.wrapping_shr((ch.wrapping_shr(2) & 0b0001_1000) as u32)
                                    as u8,
                            ) as u128)
                        })
                        .ok_or($crate::DecodeError::ArithmeticOverflow)?
                } else {
                    return Err($crate::DecodeError::InvalidBase62Byte(ch, i));
                }
            }

            Ok(result)
        }
    };
}

internal_decoder_fn!(_decode, STANDARD_OFFSETS);
internal_decoder_fn!(_decode_alternative, ALTERNATIVE_OFFSETS);

/// Decodes a base62 byte slice or an equivalent like a `String` using the standard
/// digit ordering (0 to 9, then A to Z, then a to z).
///
/// Returns a Result containing a `u128`, which can be downcasted to any other uint.
///
/// # Examples
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let value = base62::decode("rustlang").unwrap();
///     assert_eq!(value, 189876682536016);
/// }
/// ```
#[must_use = "this returns the decoded result without modifying the original"]
pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<u128, DecodeError> {
    _decode(input.as_ref())
}

/// Decodes a base62 byte slice or an equivalent like a `String` using the alternative
/// digit ordering (0 to 9, then a to z, then A to Z) with lowercase letters before
/// uppercase letters.
///
/// Returns a Result containing a `u128`, which can be downcasted to any other uint.
///
/// # Examples
///
/// ```rust
/// extern crate base62;
///
/// fn main() {
///     let value = base62::decode_alternative("rustlang").unwrap();
///     assert_eq!(value, 96813686712946);
/// }
/// ```
#[must_use = "this returns the decoded result without modifying the original"]
pub fn decode_alternative<T: AsRef<[u8]>>(input: T) -> Result<u128, DecodeError> {
    _decode_alternative(input.as_ref())
}

#[cfg(test)]
mod tests {
    use super::*;
    use quickcheck::{quickcheck, TestResult};

    quickcheck! {
        fn encode_decode(xs: u128) -> bool {
            let encoded = encode(xs);
            Ok(xs) == decode(&encoded)
        }
    }

    quickcheck! {
        fn decode_good(xs: String) -> TestResult {
            if xs.chars().all(|ch| ch.is_ascii_alphanumeric()) && !xs.is_empty() {
                TestResult::from_bool(decode(&xs).is_ok())
            } else {
                TestResult::discard()
            }
        }
    }

    quickcheck! {
        fn decode_bad(xs: String) -> TestResult {
            if xs.chars().all(|ch| ch.is_ascii_alphanumeric()) {
                TestResult::discard()
            } else {
                TestResult::from_bool(decode(&xs).is_err())
            }
        }
    }

    #[test]
    fn test_encode() {
        assert_eq!(encode(u128::MAX), "7n42DGM5Tflk9n8mt7Fhc7");
        assert_eq!(
            encode(92202686130861137968548313400401640448_u128),
            "26tF05fvSIgh0000000000"
        );
        assert_eq!(encode(0_u8), "0");
    }

    #[test]
    fn test_encode_buf() {
        let mut buf = String::new();
        encode_buf(u128::MAX, &mut buf);
        assert_eq!(buf, "7n42DGM5Tflk9n8mt7Fhc7");

        buf.clear();
        encode_buf(92202686130861137968548313400401640448_u128, &mut buf);
        assert_eq!(buf, "26tF05fvSIgh0000000000");
    }

    #[test]
    fn test_encode_alternative() {
        assert_eq!(encode_alternative(691337691337_u128), "caCOuUN");
        assert_eq!(
            encode_alternative(92202686130861137968548313400401640448_u128),
            "26Tf05FVsiGH0000000000"
        );
        assert_eq!(encode_alternative(0_u8), "0");
    }

    #[test]
    fn test_encode_alternative_buf() {
        let mut buf = String::new();
        encode_alternative_buf(691337691337_u128, &mut buf);
        assert_eq!(buf, "caCOuUN");

        buf.clear();
        encode_alternative_buf(92202686130861137968548313400401640448_u128, &mut buf);
        assert_eq!(buf, "26Tf05FVsiGH0000000000");
    }

    #[test]
    fn test_decode() {
        assert_eq!(decode("7n42DGM5Tflk9n8mt7Fhc7"), Ok(u128::MAX));
        assert_eq!(
            decode("26tF05fvSIgh0000000000"),
            Ok(92202686130861137968548313400401640448)
        );
        assert_eq!(decode(""), Ok(0));
    }

    #[test]
    fn test_decode_invalid_char() {
        assert_eq!(
            decode("ds{Z455f"),
            Err(DecodeError::InvalidBase62Byte(b'{', 2))
        );
    }

    #[test]
    fn test_decode_long_string() {
        assert_eq!(
            decode("7n42DGM5Tflk9n8mt7Fhc78"),
            Err(DecodeError::ArithmeticOverflow)
        );
    }

    #[test]
    fn test_decode_alternative() {
        assert_eq!(decode_alternative("7N42dgm5tFLK9N8MT7fHC7"), Ok(u128::MAX));
        assert_eq!(
            decode_alternative("26Tf05FVsiGH0000000000"),
            Ok(92202686130861137968548313400401640448)
        );
        assert_eq!(decode_alternative(""), Ok(0));
    }

    #[test]
    fn test_decode_alternative_invalid_char() {
        assert_eq!(
            decode_alternative("ds{Z455f"),
            Err(DecodeError::InvalidBase62Byte(b'{', 2))
        );
    }

    #[test]
    fn test_decode_alternative_long_string() {
        assert_eq!(
            decode_alternative("7N42dgm5tFLK9N8MT7fHC8"),
            Err(DecodeError::ArithmeticOverflow)
        );
    }

    #[test]
    fn test_digit_count() {
        // Assume that `digit_count` is a monotonically increasing function and
        // check that the boundaries have the right values.
        assert_eq!(digit_count(0), 1);
        assert_eq!(digit_count(1), 1);
        for pow in 1..22 {
            let this_power = (BASE as u128).pow(pow as u32);

            assert_eq!(digit_count(this_power - 1), pow);
            assert_eq!(digit_count(this_power), pow + 1);
        }
        assert_eq!(digit_count(u64::MAX as u128), 11);
        assert_eq!(digit_count(u64::MAX as u128 + 1), 11);
        assert_eq!(digit_count(u128::MAX), 22);
    }
}
<|endoftext|>


<commit_before>//! A crate with printing macros.
//!
//! These macros aims to provide a simple and lazy way to print formatted traces.
//!
//! Simple example of usage:
//!
//! ```
//! #[macro_use(TRACE, ENTER)]
//! extern crate trace_macros;
//!
//!fn double_var(var: i32) -> i32 {
//!    ENTER!(var);
//!    var * var
//!}
//!
//!fn main() {
//!    ENTER!();
//!    TRACE!("I'm", "doing", "some", "lazy", "tracing");
//!    TRACE!("Result:", double_var(2));
//!    traceln!("2*2 = {}", double_var(2));
//!}
//! ```

///WARNING macro which uses ```TRACE!```
///
///Prints with the following format: ```file!:line! - WARNING: [Message]```
#[macro_export]
macro_rules! WARNING {
    ($($msg:expr),+) => {{ TRACE!(type => "WARNING", $($msg),+); }};
}

///ERROR macro which uses ```TRACE!```
///
///Prints with the following format: ```file!:line! - ERROR: [Message]```
#[macro_export]
macro_rules! ERROR {
    ($($msg:expr),+) => {{ TRACE!(type => "ERROR", $($msg),+); }};
}

///INFO macro which uses ```TRACE!```
///
///Prints with the following format: ```file!:line! - INFO: [Message]```
#[macro_export]
macro_rules! INFO {
    ($($msg:expr),+) => {{ TRACE!(type => "INFO", $($msg),+); }};
}

///DEBUG macro which uses ```TRACE!```
///
///Prints with the following format: ```file!:line! - DEBUG: [Message]```
#[macro_export]
macro_rules! DEBUG {
    ($($msg:expr),+) => {{ TRACE!(type => "DEBUG", $($msg),+); }};
}

///ENTER macro which uses ```TRACE!```
///
///Prints with the following format: ```file!:line! - ENTER: [arg_name=arg_value]```
///
///It is assumed to be used to wrap function call so all arguments are stringified, if any
#[macro_export]
macro_rules! ENTER {
    () => {{ TRACE!(type => "ENTER"); }};
    ($($msg:expr),+) => {{ TRACE!(type => "ENTER", $(format!("{}={}", stringify!($msg), $msg)),+); }};
}

///Trace macro which concats passed arguments into one string.
///
///Prints with the following format: ```file!:line! - [type:] [Message]```
///
///Usage:
///
///* ```TRACE!(type=>[TYPE], sep=>[String], [arg1, arg2, ..., argN])```
///* ```TRACE!(type=>[TYPE], [arg1, arg2, ..., argN])```
///* ```TRACE!(sep=>[String], [arg1, arg2, ..., argN])```
///* ```TRACE!([arg1, arg2, ..., argN])```
///* ```TRACE!()```
///
///Arguments must have ```fmt::Display``` trait.
#[macro_export]
macro_rules! TRACE {
    (type=>$tp:expr, sep=>$sep:expr, $msg:expr) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, $msg); }};
    (type=>$tp:expr, sep=>$sep:expr, $($arg:expr),+) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, [$(format!("{}", $arg),)+].connect($sep)); }};
    (type=>$tp:expr, $msg:expr) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, $msg); }};
    (type=>$tp:expr, $($arg:expr),+) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, [$(format!("{}", $arg),)+].connect(" ")); }};
    (type=>$tp:expr) => {{ println!("{}:{} - {}", file!(), line!(), $tp); }};
    (sep=>$sep:expr, $($arg:expr),+) => {{ println!("{}:{} - {}", file!(), line!(), [$(format!("{}", $arg),)+].connect($sep)); }};
    ($msg:expr) => {{ println!("{}:{} - {}", file!(), line!(), $msg); }};
    ($($arg:expr),+) => {{ println!("{}:{} - {}", file!(), line!(), [$(format!("{}", $arg),)+].connect(" ")); }};
    () => {{ println!("{}:{}", file!(), line!()); }};
}

///Debug trace macro like ```TRACE!```
///
///Prints with the following format: ```file!:line! - [type:] [Message]```
///
///Usage:
///
///* ```TRACE!(type=>[TYPE], sep=>[String], [arg1, arg2, ..., argN])```
///* ```TRACE!(type=>[TYPE], [arg1, arg2, ..., argN])```
///* ```TRACE!(sep=>[String], [arg1, arg2, ..., argN])```
///* ```TRACE!([arg1, arg2, ..., argN])```
///* ```TRACE!()```
///
///It is the same as ```TRACE!``` except that it prints with ```fmt::Debug``` trait.
#[macro_export]
macro_rules! DEBUG_TRACE {
    (type=>$tp:expr, sep=>$sep:expr, $msg:expr) => {{ println!("{}:{} - {}: {:?}", file!(), line!(), $tp, $msg); }};
    (type=>$tp:expr, sep=>$sep:expr, $($arg:expr),+) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, [$(format!("{:?}", $arg),)+].connect($sep)); }};
    (type=>$tp:expr, $msg:expr) => {{ println!("{}:{} - {}: {:?}", file!(), line!(), $tp, $msg); }};
    (type=>$tp:expr, $($arg:expr),+) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, [$(format!("{:?}", $arg),)+].connect(" ")); }};
    (type=>$tp:expr) => {{ println!("{}:{} - {}", file!(), line!(), $tp); }};
    (sep=>$sep:expr, $($arg:expr),+) => {{ println!("{}:{} - {}", file!(), line!(), [$(format!("{:?}", $arg),)+].connect($sep)); }};
    ($msg:expr) => {{ println!("{}:{} - {:?}", file!(), line!(), $msg); }};
    ($($arg:expr),+) => {{ println!("{}:{} - {}", file!(), line!(), [$(format!("{:?}", $arg),)+].connect(" ")); }};
    () => {{ println!("{}:{}", file!(), line!()); }};
}

///Trace macro like ```println```
///
///It uses ```format_args!``` for creating formatted string from passed arguments.
///
///Prints with the following format: ```file!:line! - [type:] [Message]```
///
#[macro_export]
macro_rules! traceln {
    (type=>$tp:expr, $($arg:tt)+) => {{ traceln!("{}: {}", $tp, format_args!($($arg)+)); }};
    (type=>$tp:expr) => {{ traceln!("{}", $tp); }};
    ($($arg:tt)+) => {{ println!("{}", format_args!("{}:{} - {}", file!(), line!(), format_args!($($arg)+))); }};
}

///Thread trace macro like ```println```
///
///It uses ```format_args!``` for creating formatted string from passed arguments.
///
///Prints with the following format: ```[thread_name] file!:line! - [type:] [Message]```
///
#[macro_export]
macro_rules! th_trace {
    (type=>$tp:expr, $($arg:tt)+) => {{ th_trace!("{}: {}", $tp, format_args!($($arg)+)); }};
    (type=>$tp:expr) => {{ th_trace!("{}", $tp); }};
    ($($arg:tt)+) => {{ println!("{}", format_args!("[{}] {}:{} - {}", std::thread::current().name().unwrap_or("none"), file!(), line!(), format_args!($($arg)+))); }};
}

///WARNING macro which uses ```traceln!```
///
///Prints with the following format: ```file!:line! - WARNING: [Message]```
#[macro_export]
macro_rules! warning {
    ($($msg:tt)+) => {{ traceln!(type=>"WARNING", $($msg)+); }};
}

///ERROR macro which uses ```traceln!```
///
///Prints with the following format: ```file!:line! - ERROR: [Message]```
#[macro_export]
macro_rules! error {
    ($($msg:tt)+) => {{ traceln!(type=>"ERROR", $($msg)+); }};
}

///INFO macro which uses ```traceln!```
///
///Prints with the following format: ```file!:line! - INFO: [Message]```
#[macro_export]
macro_rules! info {
    ($($msg:tt)+) => {{ traceln!(type=>"INFO", $($msg)+); }};
}

///DEBUG macro which uses ```traceln!```
///
///Prints with the following format: ```file!:line! - DEBUG: [Message]```
#[macro_export]
macro_rules! debug {
    ($($msg:tt)+) => {{ traceln!(type=>"DEBUG", $($msg)+); }};
}

///ENTER macro which uses ```traceln!```
///
///Prints with the following format: ```file!:line! - ENTER: [arg_name=arg_value]```
///
///It is assumed to be used to wrap function call so all arguments are stringified, if any
#[macro_export]
macro_rules! enter {
    () => {{ traceln!(type=>"ENTER"); }};
    ($($msg:expr),+) => {{ traceln!(type=>"ENTER", "{}", [$(format!("{}={}", stringify!($msg), $msg)),+].connect(" ")); }};
}

///Simplified trace macro
///
///Prints with the following format: ```file!:line! - [TYPE:] [Message]```
///
///Argument must have ```fmt::Display``` trait.
#[macro_export]
macro_rules! strace {
    (type=>$tp:expr, $msg:expr) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, $msg); }};
    ($msg:expr) => {{ println!("{}:{} - {}", file!(), line!(), $msg); }};
}

///Macro to concat several arguments into one string.
///
///Arguments:
///
///* ```sep``` is a string which is used to separate arguments. Default is white-space.
///* ```formatter``` is a valid string to pass in ```format!``` . Default is ```"{}"```.
///
///Usage:
///
///* ```connect_args!(formatter=>[String], sep=>[String], [arg1, arg2, ..., argN])```
///* ```connect_args!(sep=>[String], [arg1, arg2, ..., argN])```
///* ```connect_args!(formatter=>[String], [arg1, arg2, ..., argN])```
///* ```connect_args!([arg1, arg2, ..., argN])```
#[macro_export]
macro_rules! connect_args {
    (formatter=>$fr:expr, sep=>$sep:expr, $($arg:expr),+) => { [$(format!($fr, $arg),)+].connect($sep) };
    (sep=>$sep:expr, $($arg:expr),+) => { [$(format!("{}", $arg),)+].connect($sep) };
    (formatter=>$fr:expr, $($arg:expr),+) => { [$(format!($fr, $arg),)+].connect(" ") };
    ($msg:expr) => { format!("{}", $msg) };
    ($($arg:expr),+) => { [$(format!("{}", $arg),)+].connect(" ") };
}
<commit_msg>Minor update to docs<commit_after>//! A crate with printing macros.
//!
//! These macros aims to provide a simple and lazy way to print formatted traces.
//!
//!# Example:
//!
//! ```
//! #[macro_use(TRACE, ENTER)]
//! extern crate trace_macros;
//!
//!fn double_var(var: i32) -> i32 {
//!    ENTER!(var);
//!    var * var
//!}
//!
//!fn main() {
//!    ENTER!();
//!    TRACE!("I'm", "doing", "some", "lazy", "tracing");
//!    TRACE!("Result:", double_var(2));
//!    traceln!("2*2 = {}", double_var(2));
//!}
//! ```

///WARNING macro which uses ```TRACE!```
///
///Prints with the following format: ```file!:line! - WARNING: [Message]```
#[macro_export]
macro_rules! WARNING {
    ($($msg:expr),+) => {{ TRACE!(type => "WARNING", $($msg),+); }};
}

///ERROR macro which uses ```TRACE!```
///
///Prints with the following format: ```file!:line! - ERROR: [Message]```
#[macro_export]
macro_rules! ERROR {
    ($($msg:expr),+) => {{ TRACE!(type => "ERROR", $($msg),+); }};
}

///INFO macro which uses ```TRACE!```
///
///Prints with the following format: ```file!:line! - INFO: [Message]```
#[macro_export]
macro_rules! INFO {
    ($($msg:expr),+) => {{ TRACE!(type => "INFO", $($msg),+); }};
}

///DEBUG macro which uses ```TRACE!```
///
///Prints with the following format: ```file!:line! - DEBUG: [Message]```
#[macro_export]
macro_rules! DEBUG {
    ($($msg:expr),+) => {{ TRACE!(type => "DEBUG", $($msg),+); }};
}

///ENTER macro which uses ```TRACE!```
///
///Prints with the following format: ```file!:line! - ENTER: [arg_name=arg_value]```
///
///It is assumed to be used to wrap function call so all arguments are stringified, if any
#[macro_export]
macro_rules! ENTER {
    () => {{ TRACE!(type => "ENTER"); }};
    ($($msg:expr),+) => {{ TRACE!(type => "ENTER", $(format!("{}={}", stringify!($msg), $msg)),+); }};
}

///Trace macro which concats passed arguments into one string.
///
///Prints with the following format: ```file!:line! - [type:] [Message]```
///
///Usage:
///
///* ```TRACE!(type=>[TYPE], sep=>[String], [arg1, arg2, ..., argN])```
///* ```TRACE!(type=>[TYPE], [arg1, arg2, ..., argN])```
///* ```TRACE!(sep=>[String], [arg1, arg2, ..., argN])```
///* ```TRACE!([arg1, arg2, ..., argN])```
///* ```TRACE!()```
///
///Arguments must have ```fmt::Display``` trait.
#[macro_export]
macro_rules! TRACE {
    (type=>$tp:expr, sep=>$sep:expr, $msg:expr) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, $msg); }};
    (type=>$tp:expr, sep=>$sep:expr, $($arg:expr),+) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, [$(format!("{}", $arg),)+].connect($sep)); }};
    (type=>$tp:expr, $msg:expr) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, $msg); }};
    (type=>$tp:expr, $($arg:expr),+) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, [$(format!("{}", $arg),)+].connect(" ")); }};
    (type=>$tp:expr) => {{ println!("{}:{} - {}", file!(), line!(), $tp); }};
    (sep=>$sep:expr, $($arg:expr),+) => {{ println!("{}:{} - {}", file!(), line!(), [$(format!("{}", $arg),)+].connect($sep)); }};
    ($msg:expr) => {{ println!("{}:{} - {}", file!(), line!(), $msg); }};
    ($($arg:expr),+) => {{ println!("{}:{} - {}", file!(), line!(), [$(format!("{}", $arg),)+].connect(" ")); }};
    () => {{ println!("{}:{}", file!(), line!()); }};
}

///Debug trace macro like ```TRACE!```
///
///Prints with the following format: ```file!:line! - [type:] [Message]```
///
///Usage:
///
///* ```TRACE!(type=>[TYPE], sep=>[String], [arg1, arg2, ..., argN])```
///* ```TRACE!(type=>[TYPE], [arg1, arg2, ..., argN])```
///* ```TRACE!(sep=>[String], [arg1, arg2, ..., argN])```
///* ```TRACE!([arg1, arg2, ..., argN])```
///* ```TRACE!()```
///
///It is the same as ```TRACE!``` except that it prints with ```fmt::Debug``` trait.
#[macro_export]
macro_rules! DEBUG_TRACE {
    (type=>$tp:expr, sep=>$sep:expr, $msg:expr) => {{ println!("{}:{} - {}: {:?}", file!(), line!(), $tp, $msg); }};
    (type=>$tp:expr, sep=>$sep:expr, $($arg:expr),+) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, [$(format!("{:?}", $arg),)+].connect($sep)); }};
    (type=>$tp:expr, $msg:expr) => {{ println!("{}:{} - {}: {:?}", file!(), line!(), $tp, $msg); }};
    (type=>$tp:expr, $($arg:expr),+) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, [$(format!("{:?}", $arg),)+].connect(" ")); }};
    (type=>$tp:expr) => {{ println!("{}:{} - {}", file!(), line!(), $tp); }};
    (sep=>$sep:expr, $($arg:expr),+) => {{ println!("{}:{} - {}", file!(), line!(), [$(format!("{:?}", $arg),)+].connect($sep)); }};
    ($msg:expr) => {{ println!("{}:{} - {:?}", file!(), line!(), $msg); }};
    ($($arg:expr),+) => {{ println!("{}:{} - {}", file!(), line!(), [$(format!("{:?}", $arg),)+].connect(" ")); }};
    () => {{ println!("{}:{}", file!(), line!()); }};
}

///Trace macro like ```println```
///
///It uses ```format_args!``` for creating formatted string from passed arguments.
///
///Prints with the following format: ```file!:line! - [type:] [Message]```
///
#[macro_export]
macro_rules! traceln {
    (type=>$tp:expr, $($arg:tt)+) => {{ traceln!("{}: {}", $tp, format_args!($($arg)+)); }};
    (type=>$tp:expr) => {{ traceln!("{}", $tp); }};
    ($($arg:tt)+) => {{ println!("{}", format_args!("{}:{} - {}", file!(), line!(), format_args!($($arg)+))); }};
}

///Thread trace macro like ```println```
///
///It uses ```format_args!``` for creating formatted string from passed arguments.
///
///Prints with the following format: ```[thread_name] file!:line! - [type:] [Message]```
///
#[macro_export]
macro_rules! th_trace {
    (type=>$tp:expr, $($arg:tt)+) => {{ th_trace!("{}: {}", $tp, format_args!($($arg)+)); }};
    (type=>$tp:expr) => {{ th_trace!("{}", $tp); }};
    ($($arg:tt)+) => {{ println!("{}", format_args!("[{}] {}:{} - {}", std::thread::current().name().unwrap_or("none"), file!(), line!(), format_args!($($arg)+))); }};
}

///WARNING macro which uses ```traceln!```
///
///Prints with the following format: ```file!:line! - WARNING: [Message]```
#[macro_export]
macro_rules! warning {
    ($($msg:tt)+) => {{ traceln!(type=>"WARNING", $($msg)+); }};
}

///ERROR macro which uses ```traceln!```
///
///Prints with the following format: ```file!:line! - ERROR: [Message]```
#[macro_export]
macro_rules! error {
    ($($msg:tt)+) => {{ traceln!(type=>"ERROR", $($msg)+); }};
}

///INFO macro which uses ```traceln!```
///
///Prints with the following format: ```file!:line! - INFO: [Message]```
#[macro_export]
macro_rules! info {
    ($($msg:tt)+) => {{ traceln!(type=>"INFO", $($msg)+); }};
}

///DEBUG macro which uses ```traceln!```
///
///Prints with the following format: ```file!:line! - DEBUG: [Message]```
#[macro_export]
macro_rules! debug {
    ($($msg:tt)+) => {{ traceln!(type=>"DEBUG", $($msg)+); }};
}

///ENTER macro which uses ```traceln!```
///
///Prints with the following format: ```file!:line! - ENTER: [arg_name=arg_value]```
///
///It is assumed to be used to wrap function call so all arguments are stringified, if any
#[macro_export]
macro_rules! enter {
    () => {{ traceln!(type=>"ENTER"); }};
    ($($msg:expr),+) => {{ traceln!(type=>"ENTER", "{}", [$(format!("{}={}", stringify!($msg), $msg)),+].connect(" ")); }};
}

///Simplified trace macro
///
///Prints with the following format: ```file!:line! - [TYPE:] [Message]```
///
///Argument must have ```fmt::Display``` trait.
#[macro_export]
macro_rules! strace {
    (type=>$tp:expr, $msg:expr) => {{ println!("{}:{} - {}: {}", file!(), line!(), $tp, $msg); }};
    ($msg:expr) => {{ println!("{}:{} - {}", file!(), line!(), $msg); }};
}

///Macro to concat several arguments into one string.
///
///Arguments:
///
///* ```sep``` is a string which is used to separate arguments. Default is white-space.
///* ```formatter``` is a valid string to pass in ```format!``` . Default is ```"{}"```.
///
///Usage:
///
///* ```connect_args!(formatter=>[String], sep=>[String], [arg1, arg2, ..., argN])```
///* ```connect_args!(sep=>[String], [arg1, arg2, ..., argN])```
///* ```connect_args!(formatter=>[String], [arg1, arg2, ..., argN])```
///* ```connect_args!([arg1, arg2, ..., argN])```
#[macro_export]
macro_rules! connect_args {
    (formatter=>$fr:expr, sep=>$sep:expr, $($arg:expr),+) => { [$(format!($fr, $arg),)+].connect($sep) };
    (sep=>$sep:expr, $($arg:expr),+) => { [$(format!("{}", $arg),)+].connect($sep) };
    (formatter=>$fr:expr, $($arg:expr),+) => { [$(format!($fr, $arg),)+].connect(" ") };
    ($msg:expr) => { format!("{}", $msg) };
    ($($arg:expr),+) => { [$(format!("{}", $arg),)+].connect(" ") };
}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(core)]
#![feature(test)]

//! Txtdist is small crate for calculating the distance between two strings.
//! currently only supports the damerau levenshtein algorithm.
//!

extern crate test;

use std::collections::VecMap;
use std::iter::range_inclusive;
use std::cmp::min;

/// Calculate the distance between two strings using the damerau levenshtein algorithm.
///
///
/// > The Damerau–Levenshtein distance (named after Frederick J. Damerau and Vladimir I. Levenshtein)
/// > is a distance (string metric) between two strings, i.e., finite sequence of symbols,
/// > given by counting the minimum number of operations needed to transform one string into the other,
/// > where an operation is defined as an insertion, deletion, or substitution of a single character,
/// > or a transposition of two adjacent characters.
/// [wikipedia](http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance)
///
/// # Example
///
/// ```rust
/// use txtdist::damerau_levenshtein;
///
/// let distance = damerau_levenshtein("some string", "some other string");
/// assert_eq!(distance, 6)
/// ```
pub fn damerau_levenshtein(source: &str, target: &str) -> u32 {
    let (n, m) = (source.len(), target.len());

    if n == 0 { return m as u32; }
    if m == 0 { return n as u32; }

    if n == m && source == target {
        return 0;
    }

    let inf = n + m;

    let mut matrix = vec![vec![0; m+2]; n+2];

    matrix[0][0] = inf;
    for i in range_inclusive(0, n) {
        matrix[i+1][0] = inf;
        matrix[i+1][1] = i;
    }
    for j in range_inclusive(0, m) {
        matrix[0][j+1] = inf;
        matrix[1][j+1] = j;
    };

    let mut last_row = VecMap::new();

    for row in range_inclusive(1, n) {
        let char_s = source.char_at(row-1);
        let mut last_match_col = 0;

        for col in range_inclusive(1, m) {
            let char_t = target.char_at(col-1);
            let last_match_row = *last_row.get(&(char_t as usize)).unwrap_or(&0);
            let cost = if char_s == char_t { 0 } else { 1 };

            let dist_add = matrix[row][col+1] + 1;
            let dist_del = matrix[row+1][col] + 1;
            let dist_sub = matrix[row][col] + cost;
            let dist_trans = matrix[last_match_row][last_match_col]
                            + (row - last_match_row - 1) + 1
                            + (col - last_match_col - 1);

            let dist = min(min(dist_add, dist_del),
                           min(dist_sub, dist_trans));

            matrix[row+1][col+1] = dist;

            if cost == 0 {
                last_match_col = col;
            }
        }

        last_row.insert(char_s as usize, row);
    }

    matrix[n+1][m+1] as u32
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    #[test]
    fn test_damerau_levenschtein() {
        let distance = damerau_levenshtein("CA", "ABC");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("an act", "a cat");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("", "a cat");
        assert_eq!(distance, 5);

        let distance = damerau_levenshtein("MERCEDES-BENS", "MERCEDES-BENZ");
        assert_eq!(distance, 1);

        let distance = damerau_levenshtein("", "");
        assert_eq!(distance, 0);

        let distance = damerau_levenshtein("some string", "some string");
        assert_eq!(distance, 0);
    }

    #[bench]
    fn bench_damerau_levenschtein(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same_length(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string12", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_empty(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("some string", "some string"));
    }
}
<commit_msg>Some docs<commit_after>#![feature(collections)]
#![feature(core)]
#![feature(test)]

//! Txtdist is small utility crate for calculating the distance between two strings.

extern crate test;

use std::collections::VecMap;
use std::iter::range_inclusive;
use std::cmp::min;

/// Calculate the distance between two strings using the damerau levenshtein algorithm.
///
///
///
/// > The Damerau–Levenshtein distance (named after Frederick J. Damerau and Vladimir I. Levenshtein)
/// > is a distance (string metric) between two strings, i.e., finite sequence of symbols,
/// > given by counting the minimum number of operations needed to transform one string into the other,
/// > where an operation is defined as an insertion, deletion, or substitution of a single character,
/// > or a transposition of two adjacent characters.
/// [wikipedia](http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance)
///
/// # Example
///
/// ```rust
/// use txtdist::damerau_levenshtein;
///
/// let distance = damerau_levenshtein("some string", "some other string");
/// assert_eq!(distance, 6)
/// ```
pub fn damerau_levenshtein(source: &str, target: &str) -> u32 {
    let (n, m) = (source.len(), target.len());

    if n == 0 { return m as u32; }
    if m == 0 { return n as u32; }

    if n == m && source == target {
        return 0;
    }

    let inf = n + m;

    let mut matrix = vec![vec![0; m+2]; n+2];

    matrix[0][0] = inf;
    for i in range_inclusive(0, n) {
        matrix[i+1][0] = inf;
        matrix[i+1][1] = i;
    }
    for j in range_inclusive(0, m) {
        matrix[0][j+1] = inf;
        matrix[1][j+1] = j;
    };

    let mut last_row = VecMap::new();

    for row in range_inclusive(1, n) {
        let char_s = source.char_at(row-1);
        let mut last_match_col = 0;

        for col in range_inclusive(1, m) {
            let char_t = target.char_at(col-1);
            let last_match_row = *last_row.get(&(char_t as usize)).unwrap_or(&0);
            let cost = if char_s == char_t { 0 } else { 1 };

            let dist_add = matrix[row][col+1] + 1;
            let dist_del = matrix[row+1][col] + 1;
            let dist_sub = matrix[row][col] + cost;
            let dist_trans = matrix[last_match_row][last_match_col]
                            + (row - last_match_row - 1) + 1
                            + (col - last_match_col - 1);

            let dist = min(min(dist_add, dist_del),
                           min(dist_sub, dist_trans));

            matrix[row+1][col+1] = dist;

            if cost == 0 {
                last_match_col = col;
            }
        }

        last_row.insert(char_s as usize, row);
    }

    matrix[n+1][m+1] as u32
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    #[test]
    fn test_damerau_levenschtein() {
        let distance = damerau_levenshtein("CA", "ABC");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("an act", "a cat");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("", "a cat");
        assert_eq!(distance, 5);

        let distance = damerau_levenshtein("MERCEDES-BENS", "MERCEDES-BENZ");
        assert_eq!(distance, 1);

        let distance = damerau_levenshtein("", "");
        assert_eq!(distance, 0);

        let distance = damerau_levenshtein("some string", "some string");
        assert_eq!(distance, 0);
    }

    #[bench]
    fn bench_damerau_levenschtein(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same_length(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string12", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_empty(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("some string", "some string"));
    }
}
<|endoftext|>


<commit_before>//! Entity Component System Library (ECS)
//!
//! For info about why an ECS may be beneficial, see some of these articles:
//!
//! - http://gameprogrammingpatterns.com/component.html
//! - http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/
//! - http://www.gamedev.net/page/resources/_/technical/game-programming/understanding-component-entity-systems-r3013
//! - http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/
//!
//! There is a large variety of ways an ECS may work. This particular one is similar to
//! [Artemis](http://gamadu.com/artemis/).
//! Although this isn't a port to Rust, most functionality should be similar, and the
//! tutorials/manual there should be able to make up for the current lack of documentation [FIXME]
//!
//! Here's the basic structure:
//!
//! - An `Entity` is just an identifier. It contains no data or logic whatsoever.
//! - A `Component` is a piece of data (eg: Position, Velocity, Colour). While containing logic can
//! sometimes be useful, it's best practice to avoid it wherever possible.
//! - A `System` runs all the logic. Most of the time, it filters out entities based on their
//! components, and only runs it's logic on the entities it's interested in. These filters are
//! called `Aspect`s. Some systems ignore entities, and just apply logic to the world itself.
//! - An `Aspect` is a simple helper to filter entities based on their components.
//! - A `Manager` is simply an object that observes when an entity is
//! added/activated/deactivated/removed. They are used to help 'manage' the entities, rather than
//! define data or logic.
//! - The `World` organises all the above items together to make sure everything runs as it should.

#![crate_name = "ecs"]
#![crate_type = "lib"]

#![feature(collections)]
#![feature(collections_drain)]

extern crate bincode;
extern crate rustc_serialize;

pub use aspect::Aspect;
pub use component::{Component, ComponentList};
pub use component::{EntityBuilder, EntityModifier};
pub use entity::{Entity, IndexedEntity, EntityIter};
pub use system::{System, Process};
pub use world::{ComponentManager, ServiceManager, SystemManager, DataHelper, World};

use std::ops::Deref;

pub mod aspect;
pub mod component;
pub mod entity;
pub mod system;
pub mod world;

pub struct BuildData<'a, T: ComponentManager>(&'a IndexedEntity<T>);
pub struct ModifyData<'a, T: ComponentManager>(&'a IndexedEntity<T>);
pub struct EntityData<'a, T: ComponentManager>(&'a IndexedEntity<T>);
impl<'a, T: ComponentManager> Deref for EntityData<'a, T>
{
    type Target = IndexedEntity<T>;
    fn deref(&self) -> &IndexedEntity<T>
    {
        &self.0
    }
}

impl<'a, T: ComponentManager> Copy for BuildData<'a, T> {}
impl<'a, T: ComponentManager> Copy for ModifyData<'a, T> {}
impl<'a, T: ComponentManager> Copy for EntityData<'a, T> {}

impl<'a, T: ComponentManager> Clone for BuildData<'a, T> {fn clone(&self) -> BuildData<'a, T> {*self}}
impl<'a, T: ComponentManager> Clone for ModifyData<'a, T> {fn clone(&self) -> ModifyData<'a, T> {*self}}
impl<'a, T: ComponentManager> Clone for EntityData<'a, T> {fn clone(&self) -> EntityData<'a, T> {*self}}

#[doc(hidden)]
pub unsafe trait EditData<T: ComponentManager> { fn entity(&self) -> &IndexedEntity<T>; }
unsafe impl<'a, T: ComponentManager> EditData<T> for ModifyData<'a, T> { fn entity(&self) -> &IndexedEntity<T> { &self.0 } }
unsafe impl<'a, T: ComponentManager> EditData<T> for EntityData<'a, T> { fn entity(&self) -> &IndexedEntity<T> { &self.0 } }

#[macro_use]
mod macros
{
    #[macro_export]
    macro_rules! process {
        {
            $world:expr, $system:ident
        } => {
            $crate::Process::process(&mut $world.systems.$system, &mut $world.data)
        };
    }

    #[macro_export]
    macro_rules! components {
        {
            $Name:ident;
        } => {
            #[derive(RustcEncodable,RustcDecodable)]
            pub struct $Name;

            unsafe impl $crate::ComponentManager for $Name
            {
                unsafe fn new() -> $Name
                {
                    $Name
                }

                unsafe fn remove_all(&mut self, _: &$crate::IndexedEntity<$Name>)
                {

                }
            }
        };
        {
            $Name:ident {
                $(#[$kind:ident] $field_name:ident : $field_ty:ty),+
            }
        } => {
            #[derive(RustcEncodable,RustcDecodable)]
            pub struct $Name {
                $(
                    pub $field_name : $crate::ComponentList<$Name, $field_ty>,
                )+
            }

            unsafe impl $crate::ComponentManager for $Name
            {
                unsafe fn new() -> $Name
                {
                    $Name {
                        $(
                            $field_name : $crate::ComponentList::$kind(),
                        )+
                    }
                }

                unsafe fn remove_all(&mut self, entity: &$crate::IndexedEntity<$Name>)
                {
                    $(
                        self.$field_name.clear(entity);
                    )+
                }
            }
        };
        {
            $Name:ident {
                $(#[$kind:ident] $field_name:ident : $field_ty:ty),+,
            }
        } => {
            components! { $Name { $(#[$kind] $field_name : $field_ty),+ } }
        };
    }

    #[macro_export]
    macro_rules! services {
        {
            $Name:ident {
                $($field_name:ident : $field_ty:ty = $field_init:expr),+
            }
        } => {
            #[derive(RustcEncodable,RustcDecodable)]
            pub struct $Name {
                $(
                    pub $field_name : $field_ty,
                )+
            }

            impl $crate::ServiceManager for $Name
            {
                fn new() -> $Name
                {
                    $Name {
                        $(
                            $field_name : $field_init,
                        )+
                    }
                }
            }
        };
        {
            $Name:ident {
                $($field_name:ident : $field_ty:ty = $field_init:expr),+,
            }
        } => {
            services! { $Name { $($field_name : $field_ty = $field_init),+ } }
        }
    }

    #[macro_export]
    macro_rules! systems {
        {
            $Name:ident<$components:ty, $services:ty>;
        } => {
            pub struct $Name;

            impl Encodable for $Name
            {
                fn encode<S:Encoder>(&self,encoder: &mut S)-> Result<(),S::Error>
                {
                    Ok(())
                }
            }

            impl Decodable for $Name
            {
                fn decode<D: Decoder>(d: &mut D)->Result<$Name,D::Error>
                {
                    Ok(
                    $Name
                    {
                        $(
                            $field_name : $field_init,
                        )+
                    }
                    )
                }
            }

            unsafe impl $crate::SystemManager for $Name
            {
                type Components = $components;
                type Services = $services;
                #[allow(unused_unsafe)] // The aspect macro is probably going to be used here and it also expands to an unsafe block.
                unsafe fn new() -> $Name
                {
                    $Name
                }

                unsafe fn activated(&mut self, _: $crate::EntityData<$components>, _: &$components)
                {

                }

                unsafe fn reactivated(&mut self, _: $crate::EntityData<$components>, _: &$components)
                {

                }

                unsafe fn deactivated(&mut self, _: $crate::EntityData<$components>, _: &$components)
                {

                }

                unsafe fn update(&mut self, _: &mut $crate::DataHelper<$components, $services>)
                {

                }
            }
        };
        {
            $Name:ident<$components:ty, $services:ty> {
                $($field_name:ident : $field_ty:ty = $field_init:expr),+
            }
        } => {
            pub struct $Name {
                $(
                    pub $field_name : $field_ty,
                )+
            }

            impl Encodable for $Name
            {
                fn encode<S:Encoder>(&self,encoder: &mut S)-> Result<(),S::Error>
                {
                    Ok(())
                }
            }

            impl Decodable for $Name
            {
                fn decode<D: Decoder>(d: &mut D)->Result<$Name,D::Error>
                {
                    Ok(
                    $Name
                    {
                        $(
                            $field_name : $field_init,
                        )+
                    }
                    )
                }
            }

            unsafe impl $crate::SystemManager for $Name
            {
                type Components = $components;
                type Services = $services;
                #[allow(unused_unsafe)] // The aspect macro is probably going to be used here and it also expands to an unsafe block.
                unsafe fn new() -> $Name
                {
                    $Name {
                        $(
                            $field_name : $field_init,
                        )+
                    }
                }

                unsafe fn activated(&mut self, en: $crate::EntityData<$components>, co: &$components)
                {
                    $(
                        self.$field_name.activated(&en, co);
                    )+
                }

                unsafe fn reactivated(&mut self, en: $crate::EntityData<$components>, co: &$components)
                {
                    $(
                        self.$field_name.reactivated(&en, co);
                    )+
                }

                unsafe fn deactivated(&mut self, en: $crate::EntityData<$components>, co: &$components)
                {
                    $(
                        self.$field_name.deactivated(&en, co);
                    )+
                }

                unsafe fn update(&mut self, co: &mut $crate::DataHelper<$components, $services>)
                {
                    $(
                        if self.$field_name.is_active() {
                            $crate::Process::process(&mut self.$field_name, co);
                        }
                    )+
                }
            }
        };
        {
            $Name:ident<$components:ty, $services:ty> {
                $($field_name:ident : $field_ty:ty = $field_init:expr),+,
            }
        } => {
            systems! { $Name<$components, $services> { $($field_name : $field_ty = $field_init),+ } }
        }
    }

    #[macro_export]
    macro_rules! aspect {
        {
            <$components:ty>
            all: [$($all_field:ident),*]
            none: [$($none_field:ident),*]
        } => {
            unsafe {
                $crate::Aspect::new(Box::new(|_en: &$crate::EntityData<$components>, _co: &$components| {
                    ($(_co.$all_field.has(_en) &&)* true) &&
                    !($(_co.$none_field.has(_en) ||)* false)
                }))
            }
        };
        {
            <$components:ty>
            all: [$($field:ident),*]
        } => {
            aspect!(
                <$components>
                all: [$($field),*]
                none: []
            )
        };
        {
            <$components:ty>
            none: [$($field:ident),*]
        } => {
            aspect!(
                <$components>
                all: []
                none: [$($field),*]
            )
        };
    }
}
<commit_msg>removed warnings<commit_after>//! Entity Component System Library (ECS)
//!
//! For info about why an ECS may be beneficial, see some of these articles:
//!
//! - http://gameprogrammingpatterns.com/component.html
//! - http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/
//! - http://www.gamedev.net/page/resources/_/technical/game-programming/understanding-component-entity-systems-r3013
//! - http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/
//!
//! There is a large variety of ways an ECS may work. This particular one is similar to
//! [Artemis](http://gamadu.com/artemis/).
//! Although this isn't a port to Rust, most functionality should be similar, and the
//! tutorials/manual there should be able to make up for the current lack of documentation [FIXME]
//!
//! Here's the basic structure:
//!
//! - An `Entity` is just an identifier. It contains no data or logic whatsoever.
//! - A `Component` is a piece of data (eg: Position, Velocity, Colour). While containing logic can
//! sometimes be useful, it's best practice to avoid it wherever possible.
//! - A `System` runs all the logic. Most of the time, it filters out entities based on their
//! components, and only runs it's logic on the entities it's interested in. These filters are
//! called `Aspect`s. Some systems ignore entities, and just apply logic to the world itself.
//! - An `Aspect` is a simple helper to filter entities based on their components.
//! - A `Manager` is simply an object that observes when an entity is
//! added/activated/deactivated/removed. They are used to help 'manage' the entities, rather than
//! define data or logic.
//! - The `World` organises all the above items together to make sure everything runs as it should.

#![crate_name = "ecs"]
#![crate_type = "lib"]

#![feature(collections)]
#![feature(collections_drain)]

extern crate bincode;
extern crate rustc_serialize;

pub use aspect::Aspect;
pub use component::{Component, ComponentList};
pub use component::{EntityBuilder, EntityModifier};
pub use entity::{Entity, IndexedEntity, EntityIter};
pub use system::{System, Process};
pub use world::{ComponentManager, ServiceManager, SystemManager, DataHelper, World};

use std::ops::Deref;

pub mod aspect;
pub mod component;
pub mod entity;
pub mod system;
pub mod world;

pub struct BuildData<'a, T: ComponentManager>(&'a IndexedEntity<T>);
pub struct ModifyData<'a, T: ComponentManager>(&'a IndexedEntity<T>);
pub struct EntityData<'a, T: ComponentManager>(&'a IndexedEntity<T>);
impl<'a, T: ComponentManager> Deref for EntityData<'a, T>
{
    type Target = IndexedEntity<T>;
    fn deref(&self) -> &IndexedEntity<T>
    {
        &self.0
    }
}

impl<'a, T: ComponentManager> Copy for BuildData<'a, T> {}
impl<'a, T: ComponentManager> Copy for ModifyData<'a, T> {}
impl<'a, T: ComponentManager> Copy for EntityData<'a, T> {}

impl<'a, T: ComponentManager> Clone for BuildData<'a, T> {fn clone(&self) -> BuildData<'a, T> {*self}}
impl<'a, T: ComponentManager> Clone for ModifyData<'a, T> {fn clone(&self) -> ModifyData<'a, T> {*self}}
impl<'a, T: ComponentManager> Clone for EntityData<'a, T> {fn clone(&self) -> EntityData<'a, T> {*self}}

#[doc(hidden)]
pub unsafe trait EditData<T: ComponentManager> { fn entity(&self) -> &IndexedEntity<T>; }
unsafe impl<'a, T: ComponentManager> EditData<T> for ModifyData<'a, T> { fn entity(&self) -> &IndexedEntity<T> { &self.0 } }
unsafe impl<'a, T: ComponentManager> EditData<T> for EntityData<'a, T> { fn entity(&self) -> &IndexedEntity<T> { &self.0 } }

#[macro_use]
mod macros
{
    #[macro_export]
    macro_rules! process {
        {
            $world:expr, $system:ident
        } => {
            $crate::Process::process(&mut $world.systems.$system, &mut $world.data)
        };
    }

    #[macro_export]
    macro_rules! components {
        {
            $Name:ident;
        } => {
            #[derive(RustcEncodable,RustcDecodable)]
            pub struct $Name;

            unsafe impl $crate::ComponentManager for $Name
            {
                unsafe fn new() -> $Name
                {
                    $Name
                }

                unsafe fn remove_all(&mut self, _: &$crate::IndexedEntity<$Name>)
                {

                }
            }
        };
        {
            $Name:ident {
                $(#[$kind:ident] $field_name:ident : $field_ty:ty),+
            }
        } => {
            #[derive(RustcEncodable,RustcDecodable)]
            pub struct $Name {
                $(
                    pub $field_name : $crate::ComponentList<$Name, $field_ty>,
                )+
            }

            unsafe impl $crate::ComponentManager for $Name
            {
                unsafe fn new() -> $Name
                {
                    $Name {
                        $(
                            $field_name : $crate::ComponentList::$kind(),
                        )+
                    }
                }

                unsafe fn remove_all(&mut self, entity: &$crate::IndexedEntity<$Name>)
                {
                    $(
                        self.$field_name.clear(entity);
                    )+
                }
            }
        };
        {
            $Name:ident {
                $(#[$kind:ident] $field_name:ident : $field_ty:ty),+,
            }
        } => {
            components! { $Name { $(#[$kind] $field_name : $field_ty),+ } }
        };
    }

    #[macro_export]
    macro_rules! services {
        {
            $Name:ident {
                $($field_name:ident : $field_ty:ty = $field_init:expr),+
            }
        } => {
            #[derive(RustcEncodable,RustcDecodable)]
            pub struct $Name {
                $(
                    pub $field_name : $field_ty,
                )+
            }

            impl $crate::ServiceManager for $Name
            {
                fn new() -> $Name
                {
                    $Name {
                        $(
                            $field_name : $field_init,
                        )+
                    }
                }
            }
        };
        {
            $Name:ident {
                $($field_name:ident : $field_ty:ty = $field_init:expr),+,
            }
        } => {
            services! { $Name { $($field_name : $field_ty = $field_init),+ } }
        }
    }

    #[macro_export]
    macro_rules! systems {
        {
            $Name:ident<$components:ty, $services:ty>;
        } => {
            pub struct $Name;

            impl Encodable for $Name
            {
                fn encode<S:Encoder>(&self,_: &mut S)-> Result<(),S::Error>
                {
                    Ok(())
                }
            }

            impl Decodable for $Name
            {
                fn decode<D: Decoder>(_: &mut D)->Result<$Name,D::Error>
                {
                    Ok(
                    $Name
                    {
                        $(
                            $field_name : $field_init,
                        )+
                    }
                    )
                }
            }

            unsafe impl $crate::SystemManager for $Name
            {
                type Components = $components;
                type Services = $services;
                #[allow(unused_unsafe)] // The aspect macro is probably going to be used here and it also expands to an unsafe block.
                unsafe fn new() -> $Name
                {
                    $Name
                }

                unsafe fn activated(&mut self, _: $crate::EntityData<$components>, _: &$components)
                {

                }

                unsafe fn reactivated(&mut self, _: $crate::EntityData<$components>, _: &$components)
                {

                }

                unsafe fn deactivated(&mut self, _: $crate::EntityData<$components>, _: &$components)
                {

                }

                unsafe fn update(&mut self, _: &mut $crate::DataHelper<$components, $services>)
                {

                }
            }
        };
        {
            $Name:ident<$components:ty, $services:ty> {
                $($field_name:ident : $field_ty:ty = $field_init:expr),+
            }
        } => {
            pub struct $Name {
                $(
                    pub $field_name : $field_ty,
                )+
            }

            impl Encodable for $Name
            {
                fn encode<S:Encoder>(&self,_: &mut S)-> Result<(),S::Error>
                {
                    Ok(())
                }
            }

            impl Decodable for $Name
            {
                fn decode<D: Decoder>(_: &mut D)->Result<$Name,D::Error>
                {
                    Ok(
                    $Name
                    {
                        $(
                            $field_name : $field_init,
                        )+
                    }
                    )
                }
            }

            unsafe impl $crate::SystemManager for $Name
            {
                type Components = $components;
                type Services = $services;
                #[allow(unused_unsafe)] // The aspect macro is probably going to be used here and it also expands to an unsafe block.
                unsafe fn new() -> $Name
                {
                    $Name {
                        $(
                            $field_name : $field_init,
                        )+
                    }
                }

                unsafe fn activated(&mut self, en: $crate::EntityData<$components>, co: &$components)
                {
                    $(
                        self.$field_name.activated(&en, co);
                    )+
                }

                unsafe fn reactivated(&mut self, en: $crate::EntityData<$components>, co: &$components)
                {
                    $(
                        self.$field_name.reactivated(&en, co);
                    )+
                }

                unsafe fn deactivated(&mut self, en: $crate::EntityData<$components>, co: &$components)
                {
                    $(
                        self.$field_name.deactivated(&en, co);
                    )+
                }

                unsafe fn update(&mut self, co: &mut $crate::DataHelper<$components, $services>)
                {
                    $(
                        if self.$field_name.is_active() {
                            $crate::Process::process(&mut self.$field_name, co);
                        }
                    )+
                }
            }
        };
        {
            $Name:ident<$components:ty, $services:ty> {
                $($field_name:ident : $field_ty:ty = $field_init:expr),+,
            }
        } => {
            systems! { $Name<$components, $services> { $($field_name : $field_ty = $field_init),+ } }
        }
    }

    #[macro_export]
    macro_rules! aspect {
        {
            <$components:ty>
            all: [$($all_field:ident),*]
            none: [$($none_field:ident),*]
        } => {
            unsafe {
                $crate::Aspect::new(Box::new(|_en: &$crate::EntityData<$components>, _co: &$components| {
                    ($(_co.$all_field.has(_en) &&)* true) &&
                    !($(_co.$none_field.has(_en) ||)* false)
                }))
            }
        };
        {
            <$components:ty>
            all: [$($field:ident),*]
        } => {
            aspect!(
                <$components>
                all: [$($field),*]
                none: []
            )
        };
        {
            <$components:ty>
            none: [$($field:ident),*]
        } => {
            aspect!(
                <$components>
                all: []
                none: [$($field),*]
            )
        };
    }
}
<|endoftext|>


<commit_before>extern crate bincode;
extern crate rustc_serialize;
#[macro_use]
extern crate log;

use std::collections::HashMap;
use std::fs;
use std::fs::File;
use std::fs::OpenOptions;
use std::path::Path;
use std::io::prelude::*;
use std::hash::Hash;

use bincode::SizeLimit;
use bincode::rustc_serialize::{ encode, decode };

use rustc_serialize::{ Encodable, Decodable };

/// The maximum number of retries the cab will make
const MAX_RETRIES:i32 = 5;

/// A default value type to use with KV
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub enum Value {
    String(String),
    Int(i32),
    Float(f32),
    Map(HashMap<String, Value>),
}

/// Type alias for results from KV
type KVResult = Result<bool, &'static str>;

/// The type that represents the key-value store
pub struct KV<K,V> {
    cab: HashMap<K, V>,
    file: File,
}

impl<K: Clone + Encodable + Decodable + Eq + Hash, V: Clone + Encodable + Decodable> KV<K,V> {
    /// Creates a new instance of the KV store
    pub fn new(p:&'static str) -> KV<K,V> {
        // if the cab doesn't exist create it
        if !Path::new(p).exists() {
            for i in 0..MAX_RETRIES {
                match File::create(p) {
                    Ok(_) => break,
                    Err(e) => {
                        error!("{}", e);
                        if i >= MAX_RETRIES - 1 {
                            panic!("Could not create file after retries");
                        }
                        continue;
                    },
                }
            }
        }

        // Retry to get a reference to the cab file at path p
        fn retry_get_file(p:&'static str) -> File {
            for _ in 0..MAX_RETRIES {
                // make sure it is writeable on open
                let mut perms = match fs::metadata(p) {
                    Ok(f) => f.permissions(),
                    Err(e) => {
                        error!("{}", e);
                        continue;
                    },
                };
                perms.set_readonly(false);
                match fs::set_permissions(p, perms) {
                    Ok(_) => (),
                    Err(e) => {
                        error!("{}", e);
                        continue;
                    }
                }

                match OpenOptions::new().read(true).write(true).open(p) {
                    Ok(f) => { return f; },
                    Err(e) => {
                        error!("{}", e);
                        continue;
                    }
                };
            }
            panic!("retry_get_file: Failed to get file");
        }

        // create the KV instance
        let mut store = KV {
            cab: HashMap::new(),
            file: retry_get_file(p),
        };

        // lock the cab for writes
        store.lock_cab(true);

        match store.load_from_persist() {
            Ok(f) => trace!("{}", f),
            Err(e) => {
                warn!("{}", e);
            },
        };

        store
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // make sure mem version up to date
        let _ = self.load_from_persist();
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: K) -> Option<V> {
        // make sure mem version up to date
        let _ = self.load_from_persist();
        // get the value from the cab
        match self.cab.get(&key) {
            Some(v) => Some((*v).clone()),
            None => None
        }
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: K) -> KVResult {
        // make sure mem version up to date
        let _ = self.load_from_persist();
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Vec<K> {
        // make sure mem version up to date
        let _ = self.load_from_persist();
        // create a vec from the cabs keys
        self.cab.keys().map(|k| k.clone()).collect()
    }

    /// Locks/unlocks cab for writing purposes
    fn lock_cab(&mut self, readonly:bool) {
        for i in 0..MAX_RETRIES {
            // set not readonly while writing
            let mut perms = match self.file.metadata() {
                Ok(f) => f.permissions(),
                Err(e) => {
                    error!("{}", e);
                    if i >= MAX_RETRIES - 1 {
                        panic!("Could not set permissions after retries");
                    }
                    continue;
                },
            };
            perms.set_readonly(readonly);

            match self.file.set_permissions(perms) {
                Ok(_) => {
                    let _ = self.file.sync_all();
                    break;
                },
                Err(e) => {
                    error!("{}", e);
                    if i >= MAX_RETRIES - 1 {
                        panic!("Could not set permissions after retries");
                    }
                    continue;
                },
            }
        }
    }

    /// Waits for the cab to become free
    fn wait_for_free(&mut self, lock:bool) -> KVResult {
        loop {
            // check if the cab is being written to
            let _ = self.file.sync_all();
            let metadata = match self.file.metadata() {
                Ok(m) => m,
                Err(_) => return Err("File doesn't exist or is not readeable"),
            };

            if metadata.permissions().readonly() {
                if lock {
                    self.lock_cab(false);
                }
                break;
            }
        }

        Ok(true)
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // encode the cab as a u8 vec
        let byte_vec: Vec<u8> = match encode(&mut self.cab, SizeLimit::Infinite) {
            Ok(bv) => bv,
            Err(e) => {
                error!("encode: {}", e);
                return Err("Could not encode cab");
            },
        };

        if !self.wait_for_free(true).is_ok() {
            return Err("File doesn't exist or is not readeable");
        }
        // attempt to write to the cab
        for i in 0..MAX_RETRIES {
            // write the bytes to it
            match self.file.write_all(byte_vec.as_slice()) {
                Ok(_) => (),
                Err(e) => {
                    error!("file.write_all/retry: {}", e);
                    if i >= MAX_RETRIES - 1 {
                        panic!("Could not write to file after retries");
                    }
                    continue;
                },
            }

            // flush to disk
            let _ = self.file.flush();
            self.lock_cab(true);
            // leave the retry loop as successful
            break;
        }

        Ok(true)
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self) -> KVResult {
        // byte vec to read into
        let mut byte_vec = Vec::new();

        // wait/lock the cab and read the bytes
        if !self.wait_for_free(false).is_ok() {
            return Err("File doesn't exist or is not readeable");
        }
        let _ = self.file.read_to_end(&mut byte_vec);

        // decode u8 vec back into HashMap
        let decoded: HashMap<K, V> = match decode(byte_vec.as_slice()) {
            Ok(f) => f,
            Err(e) => {
                warn!("{}", e);
                return Err("Couldn't decode cab");
            },
        };
        // assign read HashMap back to self
        self.cab = decoded;

        Ok(true)
    }
}
<commit_msg>Fix import style<commit_after>extern crate bincode;
extern crate rustc_serialize;
#[macro_use]
extern crate log;

use std::collections::HashMap;
use std::fs;
use std::fs::{ File, OpenOptions };
use std::path::Path;
use std::io::prelude::*;
use std::hash::Hash;

use bincode::SizeLimit;
use bincode::rustc_serialize::{ encode, decode };

use rustc_serialize::{ Encodable, Decodable };

/// The maximum number of retries the cab will make
const MAX_RETRIES:i32 = 5;

/// A default value type to use with KV
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub enum Value {
    String(String),
    Int(i32),
    Float(f32),
    Map(HashMap<String, Value>),
}

/// Type alias for results from KV
type KVResult = Result<bool, &'static str>;

/// The type that represents the key-value store
pub struct KV<K,V> {
    cab: HashMap<K, V>,
    file: File,
}

impl<K: Clone + Encodable + Decodable + Eq + Hash, V: Clone + Encodable + Decodable> KV<K,V> {
    /// Creates a new instance of the KV store
    pub fn new(p:&'static str) -> KV<K,V> {
        // if the cab doesn't exist create it
        if !Path::new(p).exists() {
            for i in 0..MAX_RETRIES {
                match File::create(p) {
                    Ok(_) => break,
                    Err(e) => {
                        error!("{}", e);
                        if i >= MAX_RETRIES - 1 {
                            panic!("Could not create file after retries");
                        }
                        continue;
                    },
                }
            }
        }

        // Retry to get a reference to the cab file at path p
        fn retry_get_file(p:&'static str) -> File {
            for _ in 0..MAX_RETRIES {
                // make sure it is writeable on open
                let mut perms = match fs::metadata(p) {
                    Ok(f) => f.permissions(),
                    Err(e) => {
                        error!("{}", e);
                        continue;
                    },
                };
                perms.set_readonly(false);
                match fs::set_permissions(p, perms) {
                    Ok(_) => (),
                    Err(e) => {
                        error!("{}", e);
                        continue;
                    }
                }

                match OpenOptions::new().read(true).write(true).open(p) {
                    Ok(f) => { return f; },
                    Err(e) => {
                        error!("{}", e);
                        continue;
                    }
                };
            }
            panic!("retry_get_file: Failed to get file");
        }

        // create the KV instance
        let mut store = KV {
            cab: HashMap::new(),
            file: retry_get_file(p),
        };

        // lock the cab for writes
        store.lock_cab(true);

        match store.load_from_persist() {
            Ok(f) => trace!("{}", f),
            Err(e) => {
                warn!("{}", e);
            },
        };

        store
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // make sure mem version up to date
        let _ = self.load_from_persist();
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: K) -> Option<V> {
        // make sure mem version up to date
        let _ = self.load_from_persist();
        // get the value from the cab
        match self.cab.get(&key) {
            Some(v) => Some((*v).clone()),
            None => None
        }
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: K) -> KVResult {
        // make sure mem version up to date
        let _ = self.load_from_persist();
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Vec<K> {
        // make sure mem version up to date
        let _ = self.load_from_persist();
        // create a vec from the cabs keys
        self.cab.keys().map(|k| k.clone()).collect()
    }

    /// Locks/unlocks cab for writing purposes
    fn lock_cab(&mut self, readonly:bool) {
        for i in 0..MAX_RETRIES {
            // set not readonly while writing
            let mut perms = match self.file.metadata() {
                Ok(f) => f.permissions(),
                Err(e) => {
                    error!("{}", e);
                    if i >= MAX_RETRIES - 1 {
                        panic!("Could not set permissions after retries");
                    }
                    continue;
                },
            };
            perms.set_readonly(readonly);

            match self.file.set_permissions(perms) {
                Ok(_) => {
                    let _ = self.file.sync_all();
                    break;
                },
                Err(e) => {
                    error!("{}", e);
                    if i >= MAX_RETRIES - 1 {
                        panic!("Could not set permissions after retries");
                    }
                    continue;
                },
            }
        }
    }

    /// Waits for the cab to become free
    fn wait_for_free(&mut self, lock:bool) -> KVResult {
        loop {
            // check if the cab is being written to
            let _ = self.file.sync_all();
            let metadata = match self.file.metadata() {
                Ok(m) => m,
                Err(_) => return Err("File doesn't exist or is not readeable"),
            };

            if metadata.permissions().readonly() {
                if lock {
                    self.lock_cab(false);
                }
                break;
            }
        }

        Ok(true)
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // encode the cab as a u8 vec
        let byte_vec: Vec<u8> = match encode(&mut self.cab, SizeLimit::Infinite) {
            Ok(bv) => bv,
            Err(e) => {
                error!("encode: {}", e);
                return Err("Could not encode cab");
            },
        };

        if !self.wait_for_free(true).is_ok() {
            return Err("File doesn't exist or is not readeable");
        }
        // attempt to write to the cab
        for i in 0..MAX_RETRIES {
            // write the bytes to it
            match self.file.write_all(byte_vec.as_slice()) {
                Ok(_) => (),
                Err(e) => {
                    error!("file.write_all/retry: {}", e);
                    if i >= MAX_RETRIES - 1 {
                        panic!("Could not write to file after retries");
                    }
                    continue;
                },
            }

            // flush to disk
            let _ = self.file.flush();
            self.lock_cab(true);
            // leave the retry loop as successful
            break;
        }

        Ok(true)
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self) -> KVResult {
        // byte vec to read into
        let mut byte_vec = Vec::new();

        // wait/lock the cab and read the bytes
        if !self.wait_for_free(false).is_ok() {
            return Err("File doesn't exist or is not readeable");
        }
        let _ = self.file.read_to_end(&mut byte_vec);

        // decode u8 vec back into HashMap
        let decoded: HashMap<K, V> = match decode(byte_vec.as_slice()) {
            Ok(f) => f,
            Err(e) => {
                warn!("{}", e);
                return Err("Couldn't decode cab");
            },
        };
        // assign read HashMap back to self
        self.cab = decoded;

        Ok(true)
    }
}
<|endoftext|>


<commit_before>#![allow(unstable)]
use std::io;
use OverwriteBehavior::{AllowOverwrite, DisallowOverwrite};

pub struct AtomicFile {
    pub path: Path,
    pub overwrite: OverwriteBehavior,
    pub tmpdir: Path
}

impl AtomicFile {
    /// Open the given file in write-only mode, if not `allow_overwrite`, errors will be returned
    /// from `do(...)` if the file exists.
    ///
    /// The temporary directory defaults to `path`, and will be used for temporary files. It must
    /// reside on the same filesystem.
    pub fn new(path: &Path, overwrite: OverwriteBehavior, tmpdir: Option<&Path>) -> AtomicFile {
        AtomicFile {
            path: path.clone(),
            overwrite: overwrite,
            tmpdir: match tmpdir {
                Some(x) => x.clone(),
                None => path.dir_path()
            }
        }
    }

    fn get_tmpfile(&self) -> io::IoResult<io::File> {
        let tmpdir = try!(io::TempDir::new_in(&self.tmpdir, "atomicwrite"));
        io::File::create(&tmpdir.path().join(Path::new("tmpfile.tmp")))
    }

    pub fn write(&self, f: &fn(&io::File) -> io::IoResult<()>) -> io::IoResult<()> {
        let mut tmpfile = try!(self.get_tmpfile());
        try!(f(&tmpfile));
        try!(tmpfile.fsync());
        try!(self.commit(tmpfile.path()));
        Ok(())
    }

    fn commit(&self, tmppath: &Path) -> io::IoResult<()> {
        match self.overwrite {
            AllowOverwrite => {
                try!(io::fs::rename(tmppath, &self.path));  // atomic
            },
            DisallowOverwrite => {
                try!(io::fs::link(tmppath, &self.path)); // atomic
                try!(io::fs::unlink(&self.path)); // doesn't matter if atomic
            }
        };
        Ok(())
    }
}

#[derive(Copy)]
pub enum OverwriteBehavior {
    AllowOverwrite,
    DisallowOverwrite
}
<commit_msg>Fixes<commit_after>#![allow(unstable)]
use std::io;
pub use OverwriteBehavior::{AllowOverwrite, DisallowOverwrite};

pub struct AtomicFile {
    pub path: Path,
    pub overwrite: OverwriteBehavior,
    pub tmpdir: Path
}

impl AtomicFile {
    /// Open the given file in write-only mode, if not `allow_overwrite`, errors will be returned
    /// from `do(...)` if the file exists.
    ///
    /// The temporary directory defaults to `path`, and will be used for temporary files. It must
    /// reside on the same filesystem.
    pub fn new(path: &Path, overwrite: OverwriteBehavior, tmpdir: Option<&Path>) -> AtomicFile {
        AtomicFile {
            path: path.clone(),
            overwrite: overwrite,
            tmpdir: match tmpdir {
                Some(x) => x.clone(),
                None => path.dir_path()
            }
        }
    }

    fn get_tmpfile(&self) -> io::IoResult<io::File> {
        let tmpdir = try!(io::TempDir::new_in(&self.tmpdir, ".atomicwrite"));
        io::File::create(&tmpdir.path().join(Path::new("tmpfile.tmp")))
    }

    pub fn write<F: FnMut(&mut io::File) -> io::IoResult<()>>(&self, mut f: F) -> io::IoResult<()> {
        let mut tmpfile = try!(self.get_tmpfile());
        try!(f(&mut tmpfile));
        try!(tmpfile.fsync());
        try!(self.commit(tmpfile.path()));
        Ok(())
    }

    fn commit(&self, tmppath: &Path) -> io::IoResult<()> {
        match self.overwrite {
            AllowOverwrite => {
                try!(io::fs::rename(tmppath, &self.path));  // atomic
            },
            DisallowOverwrite => {
                try!(io::fs::link(tmppath, &self.path)); // atomic
                try!(io::fs::unlink(&self.path)); // doesn't matter if atomic
            }
        };
        Ok(())
    }
}

#[derive(Copy)]
pub enum OverwriteBehavior {
    AllowOverwrite,
    DisallowOverwrite
}
<|endoftext|>