1use std::error::Error;
2use std::fmt;
3
4#[derive(Debug, PartialEq)]
5pub struct NthError {
6 index: i64,
7}
8
9impl fmt::Display for NthError {
10 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11 write!(f, "nth: {} out of slice bounds", self.index)
12 }
13}
14
15impl Error for NthError {}
16
17pub fn nth<T>(collection: &[T], nth: i64) -> Result<&T, NthError> {
44 let len = collection.len() as i64;
45
46 if nth >= len || -nth > len {
47 return Err(NthError { index: nth });
48 }
49
50 let index = if nth >= 0 { nth } else { len + nth } as usize;
51
52 Ok(&collection[index])
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
60 fn test_nth_positive_index() {
61 let collection = vec![1, 2, 3, 4, 5];
62 let result = nth(&collection, 2);
63 assert_eq!(result.unwrap(), &3);
64 }
65
66 #[test]
67 fn test_nth_negative_index() {
68 let collection = vec![1, 2, 3, 4, 5];
69 let result = nth(&collection, -2);
70 assert_eq!(result.unwrap(), &4);
71 }
72
73 #[test]
74 fn test_nth_out_of_bounds_positive() {
75 let collection = vec![1, 2, 3];
76 let result = nth(&collection, 5);
77 assert_eq!(result.unwrap_err(), NthError { index: 5 });
78 }
79
80 #[test]
81 fn test_nth_out_of_bounds_negative() {
82 let collection = vec![1, 2, 3];
83 let result = nth(&collection, -5);
84 assert_eq!(result.unwrap_err(), NthError { index: -5 });
85 }
86
87 #[test]
88 fn test_nth_empty_collection() {
89 let collection: Vec<i32> = vec![];
90 let result = nth(&collection, 0);
91 assert_eq!(result.unwrap_err(), NthError { index: 0 });
92 }
93
94 #[test]
95 fn test_nth_with_structs() {
96 #[derive(Debug, PartialEq)]
97 struct Person {
98 name: String,
99 age: u32,
100 }
101
102 let people = vec![
103 Person {
104 name: "Alice".to_string(),
105 age: 25,
106 },
107 Person {
108 name: "Bob".to_string(),
109 age: 30,
110 },
111 Person {
112 name: "Carol".to_string(),
113 age: 35,
114 },
115 ];
116
117 let result = nth(&people, 1);
118 assert_eq!(
119 result.unwrap(),
120 &Person {
121 name: "Bob".to_string(),
122 age: 30,
123 }
124 );
125
126 let result = nth(&people, -1);
127 assert_eq!(
128 result.unwrap(),
129 &Person {
130 name: "Carol".to_string(),
131 age: 35,
132 }
133 );
134 }
135
136 #[test]
137 fn test_nth_first_and_last() {
138 let collection = vec![1, 2, 3, 4, 5];
139 assert_eq!(nth(&collection, 0).unwrap(), &1);
140 assert_eq!(nth(&collection, -1).unwrap(), &5);
141 }
142
143 #[test]
144 fn test_nth_with_single_element() {
145 let collection = vec![42];
146 assert_eq!(nth(&collection, 0).unwrap(), &42);
147 assert_eq!(nth(&collection, -1).unwrap(), &42);
148 assert!(nth(&collection, 1).is_err());
149 assert!(nth(&collection, -2).is_err());
150 }
151
152 #[test]
153 fn test_nth_error_display() {
154 let error = NthError { index: 5 };
155 assert_eq!(error.to_string(), "nth: 5 out of slice bounds");
156
157 let error = NthError { index: -3 };
158 assert_eq!(error.to_string(), "nth: -3 out of slice bounds");
159 }
160}