serde_pickle/
error.rs

1// Copyright (c) 2015-2024 Georg Brandl.  Licensed under the Apache License,
2// Version 2.0 <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
3// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at
4// your option. This file may not be copied, modified, or distributed except
5// according to those terms.
6
7//! Error objects and codes
8
9use serde::{de, ser};
10use std::error;
11use std::fmt;
12use std::io;
13use std::result;
14
15#[derive(Clone, PartialEq, Eq, Debug)]
16pub enum ErrorCode {
17    /// Unsupported opcode
18    Unsupported(char),
19    /// EOF while parsing op argument
20    EOFWhileParsing,
21    /// Stack underflowed
22    StackUnderflow,
23    /// Length prefix found negative
24    NegativeLength,
25    /// String decoding as UTF-8 failed
26    StringNotUTF8,
27    /// Wrong stack top type for opcode
28    InvalidStackTop(&'static str, String),
29    /// Value not hashable, but used as dict key or set item
30    ValueNotHashable,
31    /// Recursive structure found, which we don't support
32    Recursive,
33    /// A "module global" reference wasn't resolved by REDUCE
34    UnresolvedGlobal,
35    /// A "module global" isn't supported
36    UnsupportedGlobal(Vec<u8>, Vec<u8>),
37    /// A value was missing from the memo
38    MissingMemo(u32),
39    /// Invalid literal found
40    InvalidLiteral(Vec<u8>),
41    /// Found trailing bytes after STOP opcode
42    TrailingBytes,
43    /// Invalid value in pickle stream
44    InvalidValue(String),
45    /// Structure deserialization error (e.g., unknown variant)
46    Structure(String),
47}
48
49impl fmt::Display for ErrorCode {
50    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
51        match *self {
52            ErrorCode::Unsupported(ch) => write!(fmt, "unsupported opcode {:?}", ch),
53            ErrorCode::EOFWhileParsing => write!(fmt, "EOF while parsing"),
54            ErrorCode::StackUnderflow => write!(fmt, "pickle stack underflow"),
55            ErrorCode::NegativeLength => write!(fmt, "negative length prefix"),
56            ErrorCode::StringNotUTF8 => write!(fmt, "string is not UTF-8 encoded"),
57            ErrorCode::InvalidStackTop(what, ref it) => {
58                write!(fmt, "invalid stack top, expected {}, got {}", what, it)
59            }
60            ErrorCode::ValueNotHashable => write!(fmt, "dict key or set item not hashable"),
61            ErrorCode::Recursive => write!(fmt, "recursive structure found"),
62            ErrorCode::UnresolvedGlobal => write!(fmt, "unresolved global reference"),
63            ErrorCode::UnsupportedGlobal(ref m, ref g) => write!(
64                fmt,
65                "unsupported global: {}.{}",
66                String::from_utf8_lossy(m),
67                String::from_utf8_lossy(g)
68            ),
69            ErrorCode::MissingMemo(n) => write!(fmt, "missing memo with id {}", n),
70            ErrorCode::InvalidLiteral(ref l) => {
71                write!(fmt, "literal is invalid: {}", String::from_utf8_lossy(l))
72            }
73            ErrorCode::TrailingBytes => write!(fmt, "trailing bytes found"),
74            ErrorCode::InvalidValue(ref s) => write!(fmt, "invalid value: {}", s),
75            ErrorCode::Structure(ref s) => fmt.write_str(s),
76        }
77    }
78}
79
80/// This type represents all possible errors that can occur when serializing or
81/// deserializing a value.
82#[derive(Debug)]
83pub enum Error {
84    /// Some IO error occurred when serializing or deserializing a value.
85    Io(io::Error),
86    /// The pickle had some error while interpreting.
87    Eval(ErrorCode, usize),
88    /// Syntax error while transforming into Rust values.
89    Syntax(ErrorCode),
90}
91
92impl From<io::Error> for Error {
93    fn from(error: io::Error) -> Error {
94        Error::Io(error)
95    }
96}
97
98pub type Result<T> = result::Result<T, Error>;
99
100impl fmt::Display for Error {
101    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
102        match *self {
103            Error::Io(ref error) => error.fmt(fmt),
104            Error::Eval(ref code, offset) => write!(fmt, "eval error at offset {}: {}", offset, code),
105            Error::Syntax(ref code) => write!(fmt, "decoding error: {}", code),
106        }
107    }
108}
109
110impl error::Error for Error {}
111
112impl de::Error for Error {
113    fn custom<T: fmt::Display>(msg: T) -> Error {
114        Error::Syntax(ErrorCode::Structure(msg.to_string()))
115    }
116}
117
118impl ser::Error for Error {
119    fn custom<T: fmt::Display>(msg: T) -> Error {
120        Error::Syntax(ErrorCode::Structure(msg.to_string()))
121    }
122}