From b766832d315aaf3052244f0ca34e82bb416eddf9 Mon Sep 17 00:00:00 2001 From: Hidehito Yabuuchi Date: Thu, 29 Nov 2018 18:36:57 +0900 Subject: [PATCH] Use failure --- Cargo.toml | 1 + src/error.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ src/kdtree.rs | 54 ++++++++++++++-------------------------------- src/lib.rs | 9 +++++--- tests/kdtree.rs | 52 ++++++++++++++++++++++++++++++-------------- 5 files changed, 116 insertions(+), 57 deletions(-) create mode 100644 src/error.rs diff --git a/Cargo.toml b/Cargo.toml index 4a5dcce..b2f0033 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ rand = "0.3.9" [dependencies] num-traits = "0.2" +failure = "0.1.3" [dependencies.serde] version = "1.0" diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..e5fd167 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,57 @@ +use failure::{Backtrace, Context, Fail}; +use std::fmt::{self, Display}; + +#[derive(Debug)] +pub struct Error { + inner: Context, +} + +#[derive(Debug, PartialEq, Fail)] +pub enum ErrorKind { + #[fail(display = "wrong dimension")] + WrongDimension, + #[fail(display = "non-finite coordinate")] + NonFiniteCoordinate, + #[fail(display = "zero capacity")] + ZeroCapacity, +} + +impl Fail for Error { + fn cause(&self) -> Option<&Fail> { + self.inner.cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + self.inner.backtrace() + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + +impl Error { + pub fn new(inner: Context) -> Error { + Error { inner } + } + + pub fn kind(&self) -> &ErrorKind { + self.inner.get_context() + } +} + +impl From for Error { + fn from(kind: ErrorKind) -> Error { + Error { + inner: Context::new(kind), + } + } +} + +impl From> for Error { + fn from(inner: Context) -> Error { + Error { inner } + } +} diff --git a/src/kdtree.rs b/src/kdtree.rs index c13bc13..ad46f43 100644 --- a/src/kdtree.rs +++ b/src/kdtree.rs @@ -1,8 +1,10 @@ -use num_traits::{Float, Zero, One}; -use std; use std::collections::BinaryHeap; -use ::heap_element::HeapElement; -use ::util; + +use num_traits::{Float, One, Zero}; + +use crate::error::{Error, ErrorKind}; +use crate::heap_element::HeapElement; +use crate::util; #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] #[derive(Debug)] @@ -24,13 +26,6 @@ pub struct KdTree> { bucket: Option>, } -#[derive(Debug, PartialEq)] -pub enum ErrorKind { - WrongDimension, - NonFiniteCoordinate, - ZeroCapacity, -} - impl> KdTree { pub fn new(dims: usize) -> Self { KdTree::new_with_capacity(dims, 2usize.pow(4)) @@ -62,7 +57,7 @@ impl> KdTree { point: &[A], num: usize, distance: &F) - -> Result, ErrorKind> + -> Result, Error> where F: Fn(&[A], &[A]) -> A { if let Err(err) = self.check_point(point) { @@ -90,7 +85,7 @@ impl> KdTree { point: &[A], ridius: A, distance: &F) - -> Result, ErrorKind> + -> Result, Error> where F: Fn(&[A], &[A]) -> A { if let Err(err) = self.check_point(point) { @@ -180,7 +175,7 @@ impl> KdTree { pub fn iter_nearest<'a, 'b, F>(&'b self, point: &'a [A], distance: &'a F) - -> Result, ErrorKind> + -> Result, Error> where F: Fn(&[A], &[A]) -> A { if let Err(err) = self.check_point(point) { @@ -200,17 +195,17 @@ impl> KdTree { }) } - pub fn add(&mut self, point: U, data: T) -> Result<(), ErrorKind> { + pub fn add(&mut self, point: U, data: T) -> Result<(), Error> { if self.capacity == 0 { - return Err(ErrorKind::ZeroCapacity); + Err(ErrorKind::ZeroCapacity)?; } if let Err(err) = self.check_point(point.as_ref()) { - return Err(err); + Err(err)?; } self.add_unchecked(point, data) } - fn add_unchecked(&mut self, point: U, data: T) -> Result<(), ErrorKind> { + fn add_unchecked(&mut self, point: U, data: T) -> Result<(), Error> { if self.is_leaf() { self.add_to_bucket(point, data); return Ok(()); @@ -299,13 +294,13 @@ impl> KdTree { self.split_dimension.is_none() && self.left.is_none() && self.right.is_none() } - fn check_point(&self, point: &[A]) -> Result<(), ErrorKind> { + fn check_point(&self, point: &[A]) -> Result<(), Error> { if self.dimensions != point.len() { - return Err(ErrorKind::WrongDimension); + Err(ErrorKind::WrongDimension)?; } for n in point { if !n.is_finite() { - return Err(ErrorKind::NonFiniteCoordinate); + Err(ErrorKind::NonFiniteCoordinate)?; } } Ok(()) @@ -362,23 +357,6 @@ impl<'a, 'b, A: Float + Zero + One, T: 'b, U: 'b + AsRef<[A]>, F: 'a> Iterator f } } -impl std::error::Error for ErrorKind { - fn description(&self) -> &str { - match *self { - ErrorKind::WrongDimension => "wrong dimension", - ErrorKind::NonFiniteCoordinate => "non-finite coordinate", - ErrorKind::ZeroCapacity => "zero capacity", - } - } -} - -impl std::fmt::Display for ErrorKind { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - use std::error::Error; - write!(f, "KdTree error: {}", self.description()) - } -} - #[cfg(test)] mod tests { extern crate rand; diff --git a/src/lib.rs b/src/lib.rs index 76db7b0..4c55c9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,15 +51,18 @@ //! ); //! ``` +#[macro_use] +extern crate failure; extern crate num_traits; - #[cfg(feature = "serialize")] #[cfg_attr(feature = "serialize", macro_use)] extern crate serde_derive; pub mod kdtree; pub mod distance; +mod error; mod heap_element; mod util; -pub use kdtree::KdTree; -pub use kdtree::ErrorKind; + +pub use crate::error::{Error, ErrorKind}; +pub use crate::kdtree::KdTree; diff --git a/tests/kdtree.rs b/tests/kdtree.rs index a618187..ac30e54 100644 --- a/tests/kdtree.rs +++ b/tests/kdtree.rs @@ -75,23 +75,34 @@ fn it_works_with_vec() { vec![(0f64, &1), (2f64, &0), (2f64, &2), (8f64, &3)]); } +macro_rules! assert_err_kind { + ($expr: expr, $err: expr) => {{ + let err = $expr.unwrap_err(); + assert_eq!(*err.kind(), $err); + }}; +} + #[test] fn handles_zero_capacity() { let mut kdtree = KdTree::new_with_capacity(2, 0); - assert_eq!(kdtree.add(&POINT_A.0, POINT_A.1), - Err(ErrorKind::ZeroCapacity)); - assert_eq!(kdtree.nearest(&POINT_A.0, 1, &squared_euclidean).unwrap(), - vec![]); + + assert_err_kind!(kdtree.add(&POINT_A.0, POINT_A.1), ErrorKind::ZeroCapacity); + assert_eq!( + kdtree.nearest(&POINT_A.0, 1, &squared_euclidean).unwrap(), + vec![] + ); } #[test] fn handles_wrong_dimension() { let point = ([0f64], 0f64); let mut kdtree = KdTree::new_with_capacity(2, 1); - assert_eq!(kdtree.add(&point.0, point.1), - Err(ErrorKind::WrongDimension)); - assert_eq!(kdtree.nearest(&point.0, 1, &squared_euclidean), - Err(ErrorKind::WrongDimension)); + + assert_err_kind!(kdtree.add(&point.0, point.1), ErrorKind::WrongDimension); + assert_err_kind!( + kdtree.nearest(&point.0, 1, &squared_euclidean), + ErrorKind::WrongDimension + ); } #[test] @@ -99,14 +110,23 @@ fn handles_non_finite_coordinate() { let point_a = ([std::f64::NAN, std::f64::NAN], 0f64); let point_b = ([std::f64::INFINITY, std::f64::INFINITY], 0f64); let mut kdtree = KdTree::new_with_capacity(2, 1); - assert_eq!(kdtree.add(&point_a.0, point_a.1), - Err(ErrorKind::NonFiniteCoordinate)); - assert_eq!(kdtree.add(&point_b.0, point_b.1), - Err(ErrorKind::NonFiniteCoordinate)); - assert_eq!(kdtree.nearest(&point_a.0, 1, &squared_euclidean), - Err(ErrorKind::NonFiniteCoordinate)); - assert_eq!(kdtree.nearest(&point_b.0, 1, &squared_euclidean), - Err(ErrorKind::NonFiniteCoordinate)); + + assert_err_kind!( + kdtree.add(&point_a.0, point_a.1), + ErrorKind::NonFiniteCoordinate + ); + assert_err_kind!( + kdtree.add(&point_b.0, point_b.1), + ErrorKind::NonFiniteCoordinate + ); + assert_err_kind!( + kdtree.nearest(&point_a.0, 1, &squared_euclidean), + ErrorKind::NonFiniteCoordinate + ); + assert_err_kind!( + kdtree.nearest(&point_b.0, 1, &squared_euclidean), + ErrorKind::NonFiniteCoordinate + ); } #[test]