Skip to content

Commit a4a0520

Browse files
author
maxtremblay
committed
Replace some panics with Result
1 parent fc36fd3 commit a4a0520

File tree

1 file changed

+57
-27
lines changed

1 file changed

+57
-27
lines changed

src/vector/mod.rs

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use crate::BinaryNumber;
1+
use crate::{BinaryNumber, PositionsError};
22
use is_sorted::IsSorted;
3+
use itertools::Itertools;
34
use std::collections::HashMap;
45
use std::fmt;
56
use std::ops::{Add, Deref};
@@ -194,6 +195,34 @@ impl<'a> SparseBinSlice<'a> {
194195
}
195196

196197
impl<T: Deref<Target = [usize]>> SparseBinVecBase<T> {
198+
/// Creates a new vector with the given length and list of non trivial positions
199+
/// or returns as error if the positions are unsorted, greater or equal to length
200+
/// or contain duplicates.
201+
///
202+
///
203+
/// # Example
204+
///
205+
/// ```
206+
/// # use sparse_bin_mat::SparseBinVec;
207+
/// use sparse_bin_mat::PositionsError;
208+
///
209+
/// let vector = SparseBinVec::try_new(5, vec![0, 2]);
210+
/// assert_eq!(vector, Ok(SparseBinVec::new(5, vec![0, 2])));
211+
///
212+
/// let vector = SparseBinVec::try_new(5, vec![2, 0]);
213+
/// assert_eq!(vector, Err(PositionsError::Unsorted));
214+
///
215+
/// let vector = SparseBinVec::try_new(5, vec![0, 10]);
216+
/// assert_eq!(vector, Err(PositionsError::OutOfBound));
217+
///
218+
/// let vector = SparseBinVec::try_new(5, vec![0, 0]);
219+
/// assert_eq!(vector, Err(PositionsError::Duplicated));
220+
/// ```
221+
pub fn try_new(length: usize, positions: T) -> Result<Self, PositionsError> {
222+
validate_positions(length, &positions)?;
223+
Ok(Self { positions, length })
224+
}
225+
197226
/// Returns the length (number of elements) of the vector.
198227
pub fn len(&self) -> usize {
199228
self.length
@@ -317,7 +346,8 @@ impl<T: Deref<Target = [usize]>> SparseBinVecBase<T> {
317346
SparseBinVec::new(self.len() + other.len(), positions)
318347
}
319348

320-
/// Returns a new vector keeping only the given positions.
349+
/// Returns a new vector keeping only the given positions or an error
350+
/// if the positions are unsorted, out of bound or contain deplicate.
321351
///
322352
/// Positions are relabeled to the fit new number of positions.
323353
///
@@ -328,23 +358,11 @@ impl<T: Deref<Target = [usize]>> SparseBinVecBase<T> {
328358
/// let vector = SparseBinVec::new(5, vec![0, 2, 4]);
329359
/// let truncated = SparseBinVec::new(3, vec![0, 2]);
330360
///
331-
/// assert_eq!(vector.keep_only_positions(&[0, 1, 2]), truncated);
332-
/// assert_eq!(vector.keep_only_positions(&[1, 2]).len(), 2);
361+
/// assert_eq!(vector.keep_only_positions(&[0, 1, 2]), Ok(truncated));
362+
/// assert_eq!(vector.keep_only_positions(&[1, 2]).map(|vec| vec.len()), Ok(2));
333363
/// ```
334-
///
335-
/// # Panic
336-
///
337-
/// Panics if some positions are out of bound.
338-
pub fn keep_only_positions(&self, positions: &[usize]) -> SparseBinVec {
339-
for position in positions {
340-
if *position >= self.len() {
341-
panic!(
342-
"position {} is out of bound for length {}",
343-
position,
344-
self.len()
345-
);
346-
}
347-
}
364+
pub fn keep_only_positions(&self, positions: &[usize]) -> Result<SparseBinVec, PositionsError> {
365+
validate_positions(self.length, positions)?;
348366
let old_to_new_positions_map = positions
349367
.iter()
350368
.enumerate()
@@ -354,10 +372,11 @@ impl<T: Deref<Target = [usize]>> SparseBinVecBase<T> {
354372
.non_trivial_positions()
355373
.filter_map(|position| old_to_new_positions_map.get(&position).cloned())
356374
.collect();
357-
SparseBinVec::new(positions.len(), new_positions)
375+
Ok(SparseBinVec::new(positions.len(), new_positions))
358376
}
359377

360-
/// Returns a truncated vector where the given positions are removed.
378+
/// Returns a truncated vector where the given positions are remove or an error
379+
/// if the positions are unsorted or out of bound.
361380
///
362381
/// Positions are relabeled to fit the new number of positions.
363382
///
@@ -368,14 +387,10 @@ impl<T: Deref<Target = [usize]>> SparseBinVecBase<T> {
368387
/// let vector = SparseBinVec::new(5, vec![0, 2, 4]);
369388
/// let truncated = SparseBinVec::new(3, vec![0, 2]);
370389
///
371-
/// assert_eq!(vector.without_positions(&[3, 4]), truncated);
372-
/// assert_eq!(vector.without_positions(&[1, 2]).len(), 3);
390+
/// assert_eq!(vector.without_positions(&[3, 4]), Ok(truncated));
391+
/// assert_eq!(vector.without_positions(&[1, 2]).map(|vec| vec.len()), Ok(3));
373392
/// ```
374-
///
375-
/// # Panic
376-
///
377-
/// Panics if some positions are out of bound.
378-
pub fn without_positions(&self, positions: &[usize]) -> SparseBinVec {
393+
pub fn without_positions(&self, positions: &[usize]) -> Result<SparseBinVec, PositionsError> {
379394
let to_keep: Vec<usize> = (0..self.len()).filter(|x| !positions.contains(x)).collect();
380395
self.keep_only_positions(&to_keep)
381396
}
@@ -457,6 +472,21 @@ impl<T: Deref<Target = [usize]>> fmt::Display for SparseBinVecBase<T> {
457472
}
458473
}
459474

475+
fn validate_positions(length: usize, positions: &[usize]) -> Result<(), PositionsError> {
476+
for position in positions.iter() {
477+
if *position >= length {
478+
return Result::Err(PositionsError::OutOfBound);
479+
}
480+
}
481+
if !IsSorted::is_sorted(&mut positions.iter()) {
482+
return Result::Err(PositionsError::Unsorted);
483+
}
484+
if positions.iter().unique().count() != positions.len() {
485+
return Result::Err(PositionsError::Duplicated);
486+
}
487+
Ok(())
488+
}
489+
460490
#[cfg(test)]
461491
mod test {
462492
use super::*;

0 commit comments

Comments
 (0)