1 use std::fmt;
2 use std::str;
3 use std::string::FromUtf8Error;
4 
5 use crate::raw::FstType;
6 
7 /// An error that occurred while using a finite state transducer.
8 ///
9 /// This enum is non-exhaustive. New variants may be added to it in
10 /// compatible releases.
11 pub enum Error {
12     /// A version mismatch occurred while reading a finite state transducer.
13     ///
14     /// This occurs when the API version (of the crate) does not match the
15     /// version encoded in the finite state transducer.
16     ///
17     /// When this error is encountered, there are only two ways to fix it:
18     ///
19     /// 1. Change the version of the library to one that is compatible with
20     ///    the given finite state transducer.
21     /// 2. Rebuild the finite state transducer.
22     Version {
23         /// The expected version, which is hard-coded into the current version
24         /// of this crate.
25         expected: u64,
26         /// The version read from the finite state transducer.
27         got: u64,
28     },
29     /// An unexpected error occurred while reading a finite state transducer.
30     /// Usually this occurs because the data is corrupted or is not actually
31     /// a finite state transducer serialized by this library.
32     Format {
33         /// The number of bytes given to the FST constructor.
34         size: usize,
35     },
36     /// An error that is returned if verification of an FST fails because of a
37     /// checksum mismatch.
38     ChecksumMismatch {
39         /// The checksum that was expected.
40         expected: u32,
41         /// The checksum that was actually computed.
42         got: u32,
43     },
44     /// An error that is returned if the caller attempts to verify an FST
45     /// that does not have a checksum, as is the case for all FSTs generated
46     /// by this crate before version `0.4`.
47     ChecksumMissing,
48     /// A duplicate key was inserted into a finite state transducer, which is
49     /// not allowed.
50     DuplicateKey {
51         /// The duplicate key.
52         got: Vec<u8>,
53     },
54     /// A key was inserted out of order into a finite state transducer.
55     ///
56     /// Keys must always be inserted in lexicographic order.
57     OutOfOrder {
58         /// The last key successfully inserted.
59         previous: Vec<u8>,
60         /// The key that caused this error to occur.
61         got: Vec<u8>,
62     },
63     /// A finite state transducer with an unexpected type was found.
64     ///
65     /// This is not currently used in this crate, but callers may wish to
66     /// employ its use for alternative data structures implemented on top of
67     /// finite state transducers.
68     WrongType {
69         /// The expected finite state transducer type.
70         expected: FstType,
71         /// The type read from a finite state transducer.
72         got: FstType,
73     },
74     /// An error that occurred when trying to decode a UTF-8 byte key.
75     FromUtf8(FromUtf8Error),
76     /// Hints that destructuring should not be exhaustive.
77     ///
78     /// This enum may grow additional variants, so this makes sure clients
79     /// don't count on exhaustive matching. (Otherwise, adding a new variant
80     /// could break existing code.)
81     #[doc(hidden)]
82     __Nonexhaustive,
83 }
84 
85 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result86     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87         match *self {
88             Error::FromUtf8(ref err) => err.fmt(f),
89             Error::Version { expected, got } => write!(
90                 f,
91                 "\
92 Error opening FST: expected API version {}, got API version {}. \
93 It looks like the FST you're trying to open is either not an FST file or it \
94 was generated with a different version of the 'fst' crate. You'll either need \
95 to change the version of the 'fst' crate you're using, or re-generate the
96 FST.",
97                 expected, got
98             ),
99             Error::Format { size } => write!(
100                 f,
101                 "\
102 Error opening FST with size {} bytes: An unknown error occurred. This \
103 usually means you're trying to read data that isn't actually an encoded FST.",
104                 size
105             ),
106             Error::ChecksumMismatch { expected, got } => write!(
107                 f,
108                 "FST verification failed: expected checksum of {} but got {}",
109                 expected, got,
110             ),
111             Error::ChecksumMissing => write!(
112                 f,
113                 "FST verification failed: FST does not contain a checksum",
114             ),
115             Error::DuplicateKey { ref got } => write!(
116                 f,
117                 "Error inserting duplicate key: '{}'.",
118                 format_bytes(&*got)
119             ),
120             Error::OutOfOrder { ref previous, ref got } => write!(
121                 f,
122                 "\
123 Error inserting out-of-order key: '{}'. (Previous key was '{}'.) Keys must be \
124 inserted in lexicographic order.",
125                 format_bytes(&*got),
126                 format_bytes(&*previous)
127             ),
128             Error::WrongType { expected, got } => write!(
129                 f,
130                 "\
131 Error opening FST: expected type '{}', got type '{}'.",
132                 expected, got
133             ),
134             Error::__Nonexhaustive => unreachable!(),
135         }
136     }
137 }
138 
139 impl fmt::Debug for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result140     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141         fmt::Display::fmt(self, f)
142     }
143 }
144 
145 impl std::error::Error for Error {
source(&self) -> Option<&(dyn std::error::Error + 'static)>146     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
147         match *self {
148             Error::FromUtf8(ref err) => Some(err),
149             _ => None,
150         }
151     }
152 }
153 
154 impl From<FromUtf8Error> for Error {
155     #[inline]
from(err: FromUtf8Error) -> Error156     fn from(err: FromUtf8Error) -> Error {
157         Error::FromUtf8(err)
158     }
159 }
160 
161 /// Attempt to convert an arbitrary byte string to a more convenient display
162 /// form.
163 ///
164 /// Essentially, try to decode the bytes as UTF-8 and show that. Failing that,
165 /// just show the sequence of bytes.
format_bytes(bytes: &[u8]) -> String166 fn format_bytes(bytes: &[u8]) -> String {
167     match str::from_utf8(bytes) {
168         Ok(s) => s.to_owned(),
169         Err(_) => format!("{:?}", bytes),
170     }
171 }
172