Skip to content

Commit

Permalink
Use failure
Browse files Browse the repository at this point in the history
  • Loading branch information
ordovicia committed Nov 29, 2018
1 parent 88fd994 commit b766832
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 57 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ rand = "0.3.9"

[dependencies]
num-traits = "0.2"
failure = "0.1.3"

[dependencies.serde]
version = "1.0"
Expand Down
57 changes: 57 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use failure::{Backtrace, Context, Fail};
use std::fmt::{self, Display};

#[derive(Debug)]
pub struct Error {
inner: Context<ErrorKind>,
}

#[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<ErrorKind>) -> Error {
Error { inner }
}

pub fn kind(&self) -> &ErrorKind {
self.inner.get_context()
}
}

impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error {
inner: Context::new(kind),
}
}
}

impl From<Context<ErrorKind>> for Error {
fn from(inner: Context<ErrorKind>) -> Error {
Error { inner }
}
}
54 changes: 16 additions & 38 deletions src/kdtree.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand All @@ -24,13 +26,6 @@ pub struct KdTree<A, T, U: AsRef<[A]>> {
bucket: Option<Vec<T>>,
}

#[derive(Debug, PartialEq)]
pub enum ErrorKind {
WrongDimension,
NonFiniteCoordinate,
ZeroCapacity,
}

impl<A: Float + Zero + One + Zero + One, T, U: AsRef<[A]>> KdTree<A, T, U> {
pub fn new(dims: usize) -> Self {
KdTree::new_with_capacity(dims, 2usize.pow(4))
Expand Down Expand Up @@ -62,7 +57,7 @@ impl<A: Float + Zero + One + Zero + One, T, U: AsRef<[A]>> KdTree<A, T, U> {
point: &[A],
num: usize,
distance: &F)
-> Result<Vec<(A, &T)>, ErrorKind>
-> Result<Vec<(A, &T)>, Error>
where F: Fn(&[A], &[A]) -> A
{
if let Err(err) = self.check_point(point) {
Expand Down Expand Up @@ -90,7 +85,7 @@ impl<A: Float + Zero + One + Zero + One, T, U: AsRef<[A]>> KdTree<A, T, U> {
point: &[A],
ridius: A,
distance: &F)
-> Result<Vec<(A, &T)>, ErrorKind>
-> Result<Vec<(A, &T)>, Error>
where F: Fn(&[A], &[A]) -> A
{
if let Err(err) = self.check_point(point) {
Expand Down Expand Up @@ -180,7 +175,7 @@ impl<A: Float + Zero + One + Zero + One, T, U: AsRef<[A]>> KdTree<A, T, U> {
pub fn iter_nearest<'a, 'b, F>(&'b self,
point: &'a [A],
distance: &'a F)
-> Result<NearestIter<'a, 'b, A, T, U, F>, ErrorKind>
-> Result<NearestIter<'a, 'b, A, T, U, F>, Error>
where F: Fn(&[A], &[A]) -> A
{
if let Err(err) = self.check_point(point) {
Expand All @@ -200,17 +195,17 @@ impl<A: Float + Zero + One + Zero + One, T, U: AsRef<[A]>> KdTree<A, T, U> {
})
}

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(());
Expand Down Expand Up @@ -299,13 +294,13 @@ impl<A: Float + Zero + One + Zero + One, T, U: AsRef<[A]>> KdTree<A, T, U> {
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(())
Expand Down Expand Up @@ -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;
Expand Down
9 changes: 6 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
52 changes: 36 additions & 16 deletions tests/kdtree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,38 +75,58 @@ 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]
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]
Expand Down

0 comments on commit b766832

Please sign in to comment.