Skip to main content

kdb_plus_fixed/ipc/
error.rs

1//! This module provides error implementation.
2
3//++++++++++++++++++++++++++++++++++++++++++++++++++//
4// >> Load Libraries
5//++++++++++++++++++++++++++++++++++++++++++++++++++//
6
7use super::K;
8use crate::qtype;
9use std::error::Error as StdError;
10use std::fmt;
11use std::io::Error as IOError;
12
13//++++++++++++++++++++++++++++++++++++++++++++++++++//
14// >>  Structs
15//++++++++++++++++++++++++++++++++++++++++++++++++++//
16
17/// Error from network IO or invalid operation.
18pub enum Error {
19    /// Invalid time was used to build `Date` or `DateTime`.
20    InvalidDateTime,
21    /// Network error.
22    IO(IOError),
23    /// Tried to cast to wrong type.
24    InvalidCast {
25        from: &'static str,
26        to: &'static str,
27    },
28    /// Tried to cast a list to wrong type.
29    InvalidCastList(&'static str),
30    /// Tried to access an index which is out of range.
31    IndexOutOfBounds { length: usize, index: usize },
32    /// Invalid operation to a wrong type.
33    InvalidOperation {
34        operator: &'static str,
35        operand_type: &'static str,
36        expected: Option<&'static str>,
37    },
38    /// Length of dictionary key and value do not match.
39    LengthMismatch {
40        key_length: usize,
41        value_length: usize,
42    },
43    /// Tried to get non-existing column.
44    NoSuchColumn(String),
45    /// Tried to insert or push wrong element.
46    InsertWrongElement {
47        is_insert: bool,
48        destination: &'static str,
49        expected: &'static str,
50    },
51    /// Tried to pop from empty list.
52    PopFromEmptyList,
53    /// Tried to convert but coluld not.
54    Object(K),
55}
56
57//++++++++++++++++++++++++++++++++++++++++++++++++++//
58// >> Implementation
59//++++++++++++++++++++++++++++++++++++++++++++++++++//
60
61impl Error {
62    /// Construct `InvalidCast` error.
63    pub(crate) fn invalid_cast(from: i8, to: i8) -> Self {
64        Self::InvalidCast {
65            from: type_to_string(from),
66            to: type_to_string(to),
67        }
68    }
69
70    /// Construct `InvalidCastList` error.
71    pub(crate) fn invalid_cast_list(from: i8) -> Self {
72        Self::InvalidCastList(type_to_string(from))
73    }
74
75    /// Construct `IndexOutOfBounds` error.
76    pub(crate) fn index_out_of_bounds(length: usize, index: usize) -> Self {
77        Self::IndexOutOfBounds { length, index }
78    }
79
80    /// Construct `InvalidOperation` error.
81    pub(crate) fn invalid_operation(
82        operator: &'static str,
83        operand_type: i8,
84        expected: Option<i8>,
85    ) -> Self {
86        Self::InvalidOperation {
87            operator,
88            operand_type: type_to_string(operand_type),
89            expected: expected.map(type_to_string),
90        }
91    }
92
93    /// Construct `LengthMismatch` error.
94    pub(crate) fn length_mismatch(key_length: usize, value_length: usize) -> Self {
95        Self::LengthMismatch {
96            key_length,
97            value_length,
98        }
99    }
100
101    /// Construct `NoSuchColumn` error.
102    pub(crate) fn no_such_column(column: String) -> Self {
103        Self::NoSuchColumn(column)
104    }
105
106    /// Construct `InsertWrongElement` error.
107    pub(crate) fn insert_wrong_element(
108        is_insert: bool,
109        destination: i8,
110        expected: &'static str,
111    ) -> Self {
112        Self::InsertWrongElement {
113            is_insert,
114            destination: type_to_string(destination),
115            expected,
116        }
117    }
118
119    /// Construct `PopFromEmptyList` error.
120    pub(crate) fn pop_from_empty_list() -> Self {
121        Self::PopFromEmptyList
122    }
123
124    /// Construct returned object as a result of an error.
125    pub(crate) fn object(returned: K) -> Self {
126        Self::Object(returned)
127    }
128
129    /// Comsume error and retrieve original object returned from some operation.
130    /// `None` is returned if the error does not contain `K` object.
131    /// ```
132    /// use kdbplus::ipc::*;
133    ///
134    /// let int = K::new_int(777);
135    /// match int.flip(){
136    ///   Ok(_) => eprintln!("miracle!!"),
137    ///   Err(original_) => {
138    ///     let original = original_.into_inner().unwrap();
139    ///     assert_eq!(original.get_int().unwrap(), 777);
140    ///   }
141    /// }
142    /// ```
143    pub fn into_inner(self) -> Option<K> {
144        match self {
145            Self::Object(object) => Some(object),
146            _ => None,
147        }
148    }
149}
150
151impl From<IOError> for Error {
152    fn from(error: IOError) -> Self {
153        Self::IO(error)
154    }
155}
156
157impl PartialEq<Self> for Error {
158    fn eq(&self, other: &Error) -> bool {
159        match (self, other) {
160            (Self::IO(left), Self::IO(right)) => left.to_string() == right.to_string(),
161            (Self::IO(_), _) => false,
162            (Self::InvalidCast { from: f, to: t }, Self::InvalidCast { from: f2, to: t2 }) => {
163                f == f2 && t == t2
164            }
165            (Self::InvalidCastList(left), Self::InvalidCastList(right)) => left == right,
166            (
167                Self::IndexOutOfBounds {
168                    length: l,
169                    index: i,
170                },
171                Self::IndexOutOfBounds {
172                    length: l2,
173                    index: i2,
174                },
175            ) => l == l2 && i == i2,
176            (
177                Self::InvalidOperation {
178                    operator: o,
179                    operand_type: ot,
180                    expected: e,
181                },
182                Self::InvalidOperation {
183                    operator: o2,
184                    operand_type: ot2,
185                    expected: e2,
186                },
187            ) => o == o2 && ot == ot2 && e == e2,
188            (
189                Self::LengthMismatch {
190                    key_length: k,
191                    value_length: l,
192                },
193                Self::LengthMismatch {
194                    key_length: k2,
195                    value_length: l2,
196                },
197            ) => k == k2 && l == l2,
198            (Self::NoSuchColumn(left), Self::NoSuchColumn(right)) => left == right,
199            (
200                Self::InsertWrongElement {
201                    is_insert: i,
202                    destination: d,
203                    expected: e,
204                },
205                Self::InsertWrongElement {
206                    is_insert: i2,
207                    destination: d2,
208                    expected: e2,
209                },
210            ) => i == i2 && d == d2 && e == e2,
211            (Self::Object(left), Self::Object(right)) => {
212                left.0.qtype == right.0.qtype && left.0.attribute == right.0.attribute
213            }
214            (Self::PopFromEmptyList, Self::PopFromEmptyList) => true,
215            _ => false,
216        }
217    }
218}
219
220impl fmt::Display for Error {
221    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
222        match self {
223            Self::InvalidDateTime => write!(f, "invalid datetime"),
224            Self::IO(error) => write!(f, "IO error: {}", error),
225            Self::InvalidCast { from, to } => write!(f, "invalid cast from {} to {}", from, to),
226            Self::InvalidCastList(from) => {
227                write!(f, "invalid cast from {} to list of generics T", from)
228            }
229            Self::IndexOutOfBounds { length, index } => write!(
230                f,
231                "index out of bounds: specified {} but length is {}",
232                index, length
233            ),
234            Self::InvalidOperation {
235                operator,
236                operand_type,
237                expected,
238            } => match expected {
239                Some(expected_type) => write!(
240                    f,
241                    "invalid operation {} on {}. expected: {}",
242                    operator, operand_type, expected_type
243                ),
244                None => write!(f, "invalid operation {} on {}", operator, operand_type),
245            },
246            Self::LengthMismatch {
247                key_length,
248                value_length,
249            } => write!(
250                f,
251                "key-value length mismatch: {} and {}",
252                key_length, value_length
253            ),
254            Self::NoSuchColumn(column) => write!(f, "no such column: {}", column),
255            Self::InsertWrongElement {
256                is_insert,
257                destination,
258                expected,
259            } => {
260                let operation = match is_insert {
261                    true => "insert",
262                    false => "push",
263                };
264                write!(
265                    f,
266                    "{} wrong element to {}: expected {}",
267                    operation, destination, expected
268                )
269            }
270            Self::Object(object) => write!(f, "{}", object),
271            Self::PopFromEmptyList => write!(f, "pop from empty list"),
272        }
273    }
274}
275
276impl fmt::Debug for Error {
277    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
278        match self {
279            Self::InvalidDateTime => write!(f, "invalid datetime"),
280            Self::IO(error) => write!(f, "IO error: {:?}", error),
281            Self::InvalidCast { from, to } => write!(f, "invalid cast from {} to {}", from, to),
282            Self::InvalidCastList(from) => {
283                write!(f, "invalid cast from {} to list of generics T", from)
284            }
285            Self::IndexOutOfBounds { length, index } => write!(
286                f,
287                "index out of bounds: specified {} but length is {}",
288                index, length
289            ),
290            Self::InvalidOperation {
291                operator,
292                operand_type,
293                expected,
294            } => match expected {
295                Some(expected_type) => write!(
296                    f,
297                    "invalid operation {} on {}. expected: {}",
298                    operator, operand_type, expected_type
299                ),
300                None => write!(f, "invalid operation {} on {}", operator, operand_type),
301            },
302            Self::LengthMismatch {
303                key_length,
304                value_length,
305            } => write!(
306                f,
307                "key-value length mismatch: {} and {}",
308                key_length, value_length
309            ),
310            Self::NoSuchColumn(column) => write!(f, "no such column: {}", column),
311            Self::InsertWrongElement {
312                is_insert,
313                destination,
314                expected,
315            } => {
316                let operation = match is_insert {
317                    true => "insert",
318                    false => "push",
319                };
320                write!(
321                    f,
322                    "{} wrong element to {}: expected {}",
323                    operation, destination, expected
324                )
325            }
326            Self::Object(object) => write!(f, "{}", object),
327            Self::PopFromEmptyList => write!(f, "pop from empty list"),
328        }
329    }
330}
331
332impl StdError for Error {}
333
334//++++++++++++++++++++++++++++++++++++++++++++++++++//
335// >> Private Function
336//++++++++++++++++++++++++++++++++++++++++++++++++++//
337
338/// Return a corresponding type name of a given type indicator.
339fn type_to_string(qtype: i8) -> &'static str {
340    match qtype {
341        qtype::BOOL_ATOM => "bool",
342        qtype::GUID_ATOM => "guid",
343        qtype::BYTE_ATOM => "byte",
344        qtype::SHORT_ATOM => "short",
345        qtype::INT_ATOM => "int",
346        qtype::LONG_ATOM => "long",
347        qtype::REAL_ATOM => "real",
348        qtype::FLOAT_ATOM => "float",
349        qtype::CHAR => "char",
350        qtype::SYMBOL_ATOM => "symbol",
351        qtype::TIMESTAMP_ATOM => "timestamp",
352        qtype::MONTH_ATOM => "month",
353        qtype::DATE_ATOM => "date",
354        qtype::DATETIME_ATOM => "datetime",
355        qtype::TIMESPAN_ATOM => "timespan",
356        qtype::MINUTE_ATOM => "minute",
357        qtype::SECOND_ATOM => "second",
358        qtype::TIME_ATOM => "time",
359        qtype::COMPOUND_LIST => "compound list",
360        qtype::BOOL_LIST => "bool list",
361        qtype::GUID_LIST => "guid list",
362        qtype::BYTE_LIST => "byte list",
363        qtype::SHORT_LIST => "short list",
364        qtype::INT_LIST => "int list",
365        qtype::LONG_LIST => "long list",
366        qtype::REAL_LIST => "real list",
367        qtype::FLOAT_LIST => "float list",
368        qtype::STRING => "string",
369        qtype::SYMBOL_LIST => "symbol list",
370        qtype::TIMESTAMP_LIST => "timestamp list",
371        qtype::MONTH_LIST => "month list",
372        qtype::DATE_LIST => "date list",
373        qtype::DATETIME_LIST => "datetime list",
374        qtype::TIMESPAN_LIST => "timespan list",
375        qtype::MINUTE_LIST => "minute list",
376        qtype::SECOND_LIST => "second list",
377        qtype::TIME_LIST => "time list",
378        qtype::TABLE => "table",
379        qtype::DICTIONARY => "dictionary",
380        qtype::NULL => "null",
381        qtype::SORTED_DICTIONARY => "sorted dictionary",
382        qtype::ERROR => "error",
383        _ => "not supported",
384    }
385}