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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

//! The errors that can occor when a cover tree is loading, working or saving.
//! Most errors are floated up from `PointCloud` as that's the i/o layer.

use pointcloud::pc_errors::PointCloudError;
use protobuf::ProtobufError;
use std::error::Error;
use std::fmt;
use std::io;
use std::str;

/// Helper type for a call that could go wrong.
pub type GokoResult<T> = Result<T, GokoError>;

/// Error type for MalwareBrot. Mostly this is a wrapper around `PointCloudError`, as the data i/o where most errors happen.
#[derive(Debug)]
pub enum GokoError {
    /// Unable to retrieve some data point (given by index) in a file (slice name)
    PointCloudError(PointCloudError),
    /// Most common error, the given point name isn't present in the training data
    IndexNotInTree(usize),
    /// IO error when opening files
    IoError(io::Error),
    /// Parsing error when loading a CSV file
    ParsingError(ParsingError),
    /// The probability distribution you are trying to sample from is invalid, probably because it was infered from 0 points.
    InvalidProbDistro,
    /// Inserted a nested node into a node that already had a nested child
    DoubleNest,
    /// Inserted a node before you changed it from a leaf node into a normal node. Insert the nested child first.
    InsertBeforeNest,
}

impl fmt::Display for GokoError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            // not sure that cause should be included in message
            GokoError::IoError(ref e) => write!(f, "{}", e),
            GokoError::ParsingError(ref e) => write!(f, "{}", e),
            GokoError::PointCloudError(ref e) => write!(f, "{}", e),
            GokoError::IndexNotInTree { .. } => {
                write!(f, "there was an issue grabbing a name from the known names")
            }
            GokoError::DoubleNest => write!(
                f,
                "Inserted a nested node into a node that already had a nested child"
            ),
            GokoError::InvalidProbDistro => write!(
                f,
                "The probability distribution you are trying to sample from is invalid, probably because it was infered from 0 points."
            ),
            GokoError::InsertBeforeNest => write!(
                f,
                "Inserted a node into a node that does not have a nested child"
            ),
        }
    }
}

#[allow(deprecated)]
impl Error for GokoError {
    fn description(&self) -> &str {
        match *self {
            // not sure that cause should be included in message
            GokoError::IoError(ref e) => e.description(),
            GokoError::ParsingError(ref e) => e.description(),
            GokoError::PointCloudError(ref e) => e.description(),
            GokoError::IndexNotInTree { .. } => {
                "there was an issue grabbing a name from the known names"
            }
            GokoError::DoubleNest => {
                "Inserted a nested node into a node that already had a nested child"
            }
            GokoError::InsertBeforeNest => {
                "Inserted a node into a node that does not have a nested child"
            }
            GokoError::InvalidProbDistro => {
                "The probability distribution you are trying to sample from is invalid, probably because it was infered from 0 points."
            }
        }
    }

    fn cause(&self) -> Option<&dyn Error> {
        match *self {
            GokoError::IoError(ref e) => Some(e),
            GokoError::ParsingError(ref e) => Some(e),
            GokoError::PointCloudError(ref e) => Some(e),
            GokoError::IndexNotInTree { .. } => None,
            GokoError::DoubleNest => None,
            GokoError::InsertBeforeNest => None,
            GokoError::InvalidProbDistro => None,
        }
    }
}

impl From<PointCloudError> for GokoError {
    fn from(err: PointCloudError) -> Self {
        GokoError::PointCloudError(err)
    }
}

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

impl From<ProtobufError> for GokoError {
    fn from(err: ProtobufError) -> Self {
        GokoError::ParsingError(ParsingError::ProtobufError(err))
    }
}

impl From<GokoError> for io::Error {
    fn from(err: GokoError) -> Self {
        match err {
            GokoError::IoError(e) => e,
            e => io::Error::new(io::ErrorKind::Other, Box::new(e)),
        }
    }
}

/// A parsing error occored while doing something with text
#[derive(Debug)]
pub enum ParsingError {
    /// Yaml was messed up
    MalformedYamlError {
        /// The file that was messed up
        file_name: String,
        /// The value that was messed up
        field: String,
    },
    /// A needed field was missing from the file.
    MissingYamlError {
        /// The file
        file_name: String,
        /// The missing field
        field: String,
    },
    /// Some protobuff error happened
    ProtobufError(ProtobufError),
    /// An error reading the CSV
    CSVReadError {
        /// The file that the error occored in
        file_name: String,
        /// The line that was messed up
        line_number: usize,
        /// The column name that was messed up
        key: String,
    },
    /// Something else happened parsing a string
    RegularParsingError(&'static str),
}

impl fmt::Display for ParsingError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            // not sure that cause should be included in message
            ParsingError::ProtobufError(ref e) => write!(f, "{}", e),
            ParsingError::MalformedYamlError { .. } => {
                write!(f, "there is a error reading a yaml entry")
            }
            ParsingError::MissingYamlError { .. } => write!(f, "not all message fields set"),
            ParsingError::CSVReadError { .. } => write!(f, "issue reading a CSV entry"),
            ParsingError::RegularParsingError(..) => write!(f, "Error parsing a string"),
        }
    }
}

#[allow(deprecated)]
impl Error for ParsingError {
    fn description(&self) -> &str {
        match *self {
            // not sure that cause should be included in message
            ParsingError::ProtobufError(ref e) => e.description(),
            ParsingError::MalformedYamlError { .. } => "there is a error reading a yaml entry",
            ParsingError::MissingYamlError { .. } => "not all message fields set",
            ParsingError::CSVReadError { .. } => "issue reading a CSV entry",
            ParsingError::RegularParsingError(..) => "Error parsing a string",
        }
    }

    fn cause(&self) -> Option<&dyn Error> {
        match *self {
            ParsingError::ProtobufError(ref e) => Some(e),
            ParsingError::MalformedYamlError { .. } => None,
            ParsingError::MissingYamlError { .. } => None,
            ParsingError::CSVReadError { .. } => None,
            ParsingError::RegularParsingError(..) => None,
        }
    }
}