diff --git a/src/arrays.rs b/src/arrays.rs new file mode 100644 index 0000000..9c4ce23 --- /dev/null +++ b/src/arrays.rs @@ -0,0 +1,67 @@ +#[derive(Debug, PartialEq)] +pub struct EmptyListError; + +// implementing Error for my error to satisfy Box +// not needed ATM +// impl std::error::Error for EmptyListError {} + +// so we can pass EmptyListError to println! +impl std::fmt::Display for EmptyListError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Error: list must not be empty") + } +} + +// Result<...,Box> is overkill +// this is intuitive enough for caller error detection +// actually probably should use Option instead, but this is better for extension +pub fn min_and_max(list: &[u32]) -> Result<(u32, u32), EmptyListError> { + if list.is_empty() { + return Err(EmptyListError); + } + let mut min:u32 = 100; + let mut max:u32 = 0; + for i in list { + if *i > max { + max = *i; + } + if *i < min { + min = *i; + } + } + Ok((min,max)) +} + +#[cfg(test)] +mod tests { + use super::*; // need access to functions above + + #[test] + fn test_arrays() { + // empty array + let empty = []; + let empty_min_and_max = min_and_max(&empty); + assert!(empty_min_and_max.as_ref().is_err()); // as_ref() so we don't perform move + assert!(*(empty_min_and_max.as_ref().err().unwrap()) == EmptyListError); + println!("Expected: {}", *(empty_min_and_max.as_ref().err().unwrap())); + + // array - contiguous, entirely on the stack, fixed at compile time, no pointer indirection + let l = [ 1, 2, 10, 100, 50, 75, 36, 21]; + let l_min_and_max = min_and_max(&l); + assert!(l_min_and_max.as_ref().unwrap().0 == 1); + assert!(l_min_and_max.as_ref().unwrap().1 == 100); + + // vec - stack: ptr, len, cap; ptr -> heap: contiguous allocation of capacity + // when variable goes out of scope drop() is called to deallocate the heap + let v = vec![1,2,3]; + let v_min_and_max = min_and_max(&v); + assert!(v_min_and_max.as_ref().unwrap().0 == 1); + assert!(v_min_and_max.as_ref().unwrap().1 == 3); + + let s = String::from("hello"); + let r = &s; + println!("{}", *r); // works because there is no implicit move + // let thing = *r; // doesn't work because String does not implement Copy trait + + } +} diff --git a/src/main.rs b/src/main.rs index 4264bba..321042d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod string; +mod arrays; mod fmt_debug; // when a String is passed to this function a move occurs: @@ -112,14 +113,5 @@ fn main() { // todo: Cow println!("Learning Rust"); - - let empty = []; - let empty_min_and_max = min_and_max(&empty); - assert!(empty_min_and_max.as_ref().is_err()); - assert!(*(empty_min_and_max.as_ref().err().unwrap()) == EmptyListError); - - let l = [ 1, 2, 10, 100, 50, 75, 36, 21]; - let l_min_and_max = min_and_max(&l); - assert!(l_min_and_max.as_ref().unwrap().0 == 1); - assert!(l_min_and_max.as_ref().unwrap().1 == 100); } +