1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use std::error;
use std::fmt;
use std::io;
use std::str;

use byteorder;
use regex_syntax;

use raw;
use RegexError;

pub type Result<T> = ::std::result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Regex(RegexError),
    Version { expected: u64, got: u64 },
    Format,
    Value { got: u64 },
    DuplicateKey { got: Vec<u8> },
    OutOfOrder { previous: Vec<u8>, got: Vec<u8> },
    WrongType { expected: raw::FstType, got: raw::FstType },
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<RegexError> for Error {
    fn from(err: RegexError) -> Error {
        Error::Regex(err)
    }
}

impl From<regex_syntax::Error> for Error {
    fn from(err: regex_syntax::Error) -> Error {
        Error::Regex(RegexError::Syntax(err))
    }
}

impl From<byteorder::Error> for Error {
    fn from(err: byteorder::Error) -> Error {
        Error::Io(From::from(err))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match *self {
            Io(ref err) => err.fmt(f),
            Regex(ref err) => err.fmt(f),
            Version { expected, got } => {
                write!(f, "\
Error opening FST: expected API version {}, got API version {}.
It looks like the FST you're trying to open is either not an FST file or it
was generated with a different version of the 'fst' crate. You'll either need
to change the version of the 'fst' crate you're using, or re-generate the
FST.", expected, got)
            }
            Format => write!(f, "\
Error opening FST: An unknown error occurred. This usually means you're trying
to read data that isn't actually an encoded FST."),
            Value { got } => write!(f, "\
Invalid value for FST map: {}. The maximum value is `2^64 - 2`. Said
differently, the only invalid value is `2^64 - 1`.", got),
            DuplicateKey { ref got } => write!(f, "\
Error inserting duplicate key: {}.", format_bytes(&*got)),
            OutOfOrder { ref previous, ref got } => write!(f, "\
Error inserting out-of-order key: {}. (Previous key was {}.) Keys must be
inserted in lexicographic order.",
format_bytes(&*got), format_bytes(&*previous)),
            WrongType { expected, got } => write!(f, "\
Error opening FST: expected type {}, got type {}.", expected, got),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            Io(ref err) => err.description(),
            Regex(ref err) => err.description(),
            Version { .. } => "incompatible version found when opening FST",
            Format => "unknown invalid format found when opening FST",
            Value { .. } => "invalid value",
            DuplicateKey { .. } => "duplicate key insertion",
            OutOfOrder { .. } => "out-of-order key insertion",
            WrongType { .. } => "incompatible type found when opening FST",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::Regex(ref err) => Some(err),
            _ => None,
        }
    }
}

/// Attempt to convert an arbitrary byte string to a more convenient display
/// form.
///
/// Essentially, try to decode the bytes as UTF-8 and show that. Failing that,
/// just show the sequence of bytes.
fn format_bytes(bytes: &[u8]) -> String {
    match str::from_utf8(bytes) {
        Ok(s) => s.to_owned(),
        Err(_) => format!("{:?}", bytes),
    }
}