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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Copyright 2018 Zach Miller
//
// Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
// or the MIT License (https://opensource.org/licenses/MIT), at your option.
//
// This file may not be copied, modified, or distributed except according to those terms.

use failure::{Backtrace, Context, Fail};

use std::fmt;
use std::result;

/// A [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html) type specifically for the
/// `checkpoint` library.
pub type Result<T> = result::Result<T, Error>;

/// The error type for Checkpoint operations.
#[derive(Debug)]
pub struct Error {
    ctx: Context<ErrorKind>,
    msg: String,
}

impl Error {
    /// Creates a new checkpoint error with the provided ErrorKind and provided message.
    fn new(kind: ErrorKind, msg: String) -> Self {
        Self {
            ctx: Context::new(kind),
            msg,
        }
    }

    /// Returns the ErrorKind of the error.
    pub fn kind(&self) -> ErrorKind {
        *self.ctx.get_context()
    }

    /// Convenience method to create an error with ErrorKind::CpAlreadyExists and the provided
    /// message.
    pub fn cp_already_exists(msg: String) -> Self {
        Self::new(ErrorKind::CpAlreadyExists, msg)
    }

    /// Convenience method to create an error with ErrorKind::CpDoesntExist and the provided
    /// message.
    pub fn cp_doesnt_exist(msg: String) -> Self {
        Self::new(ErrorKind::CpDoesntExist, msg)
    }

    /// Convenience method to create an error with ErrorKind::CpInUse and the provided message.
    pub fn cp_in_use(msg: String) -> Self {
        Self::new(ErrorKind::CpInUse, msg)
    }

    /// Convenience method to create an error with ErrorKind::CpKeyDoesntExist and the provided
    /// message.
    pub fn cp_key_doesnt_exist(msg: String) -> Self {
        Self::new(ErrorKind::CpKeyDoesntExist, msg)
    }

    /// Convenience method to create an error with ErrorKind::Deserialize and the provided message.
    pub fn deserialize(msg: String) -> Self {
        Self::new(ErrorKind::Deserialize, msg)
    }

    /// Convenience method to create an error with ErrorKind::Initialization and the provided
    /// message.
    pub fn initialization(msg: String) -> Self {
        Self::new(ErrorKind::Initialization, msg)
    }

    /// Convenience method to create an error with ErrorKind::Integrity and the provided message.
    pub fn integrity(msg: String) -> Self {
        Self::new(ErrorKind::Integrity, msg)
    }

    /// Convenience method to create an error with ErrorKind::InvalidIdentifier and the provided
    /// message.
    pub fn invalid_identifier(msg: String) -> Self {
        Self::new(ErrorKind::InvalidIdentifier, msg)
    }

    /// Convenience method to create an error with ErrorKind::Io and the provided message.
    pub fn io(msg: String) -> Self {
        Self::new(ErrorKind::Io, msg)
    }

    /// Convenience method to create an error with ErrorKind::Other and the provided message.
    pub fn other(msg: String) -> Self {
        Self::new(ErrorKind::Other, msg)
    }

    /// Convenience method to create an error with ErrorKind::Serialize and the provided message.
    pub fn serialize(msg: String) -> Self {
        Self::new(ErrorKind::Serialize, msg)
    }
}

impl Fail for Error {
    fn cause(&self) -> Option<&Fail> {
        self.ctx.cause()
    }

    fn backtrace(&self) -> Option<&Backtrace> {
        self.ctx.backtrace()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.ctx.fmt(f)
    }
}

/// The general types of checkpoint error.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ErrorKind {
    /// The specified checkpoint already exists.
    CpAlreadyExists,
    /// The specified checkpoint does not exist.
    CpDoesntExist,
    /// The specified checkpoint is in use.
    ///
    /// Most likely to occur if checkpoint removal is attempted while a reference to the underlying
    /// data exists.
    CpInUse,
    /// The specified checkpoint key does not exist.
    CpKeyDoesntExist,
    /// Deserialization of checkpoint data failed.
    Deserialize,
    /// An initialization error occurred.
    ///
    /// Most likely to occur when initializing storage or storage wrappers.
    Initialization,
    /// An integrity check of checkpoint data failed.
    Integrity,
    /// An invalid identifier was used.
    ///
    /// Most likely to occur when specifying a checkpoint identifier or a checkpoint key.
    InvalidIdentifier,
    /// An I/O error occurred.
    Io,
    /// A checkpoint error occurred that is not covered by [`ErrorKind`](enum.ErrorKind.html).
    Other,
    /// Serialization of checkpoint data failed.
    Serialize,
}

impl fmt::Display for ErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}