pencil_box/array/chunk.rs
1/// ๐งฉ Splits a slice into chunks of a specified size, cloning elements into new `Vec`s.
2///
3/// # Type Parameters
4/// - `T`: The type of elements in the input slice. Must implement [`Clone`].
5///
6/// # Arguments
7/// - `array`: A reference to a slice of elements to be chunked.
8/// - `chunk_size`: The number of elements per chunk. Must be greater than 0.
9///
10/// # Returns
11/// Returns a [`Result`]:
12/// - `Ok(Vec<Vec<T>>)` containing the chunked slices as new vectors.
13/// - `Err(&'static str)` if `chunk_size` is `0`.
14///
15/// # Behavior
16/// - If `array` is empty, returns an empty vector (`Ok(vec![])`).
17/// - If `chunk_size >= array.len()`, returns a single chunk with all elements cloned.
18/// - If `chunk_size < array.len()`, returns multiple chunks of up to `chunk_size` elements each.
19/// - If `chunk_size == 0`, returns an error.
20///
21/// # Performance
22/// - Preallocates the outer vector using: `(array.len() + chunk_size - 1) / chunk_size`.
23/// - Each chunk is allocated with `Vec::from` (per `chunk.to_vec()`).
24/// - Overall time complexity is **O(n)** and memory complexity is **O(n)** where `n = array.len()`.
25///
26/// # Examples
27///
28/// ### ๐ฆ Chunk a simple array into fixed-size groups
29/// ```
30/// use pencil_box::array::chunk::chunk;
31///
32/// let input = vec![1, 2, 3, 4, 5];
33/// let result = chunk(&input, 2).unwrap();
34/// assert_eq!(result, vec![vec![1, 2], vec![3, 4], vec![5]]);
35/// ```
36///
37/// ### ๐งช Chunk size equals array length (single chunk)
38/// ```
39/// let input = vec![10, 20, 30];
40/// let result = chunk(&input, 3).unwrap();
41/// assert_eq!(result, vec![vec![10, 20, 30]]);
42/// ```
43///
44/// ### ๐ญ Empty input returns an empty result
45/// ```
46/// let input: Vec<i32> = vec![];
47/// let result = chunk(&input, 3).unwrap();
48/// assert!(result.is_empty());
49/// ```
50///
51/// ### โ ๏ธ Invalid chunk size returns error
52/// ```
53/// let input = vec![1, 2, 3];
54/// let result = chunk(&input, 0);
55/// assert!(result.is_err());
56/// ```
57///
58/// ### ๐ค Works with strings or other clonable types
59/// ```
60/// let input = vec!["a", "b", "c", "d"];
61/// let result = chunk(&input, 2).unwrap();
62/// assert_eq!(result, vec![vec!["a", "b"], vec!["c", "d"]]);
63/// ```
64pub fn chunk<T: Clone>(array: &[T], chunk_size: usize) -> Result<Vec<Vec<T>>, &'static str> {
65 if chunk_size == 0 {
66 return Err("chunk_size must be greater than 0");
67 }
68
69 if array.is_empty() {
70 return Ok(vec![]);
71 }
72
73 if chunk_size >= array.len() {
74 return Ok(vec![array.to_vec()]);
75 }
76
77 let mut chunks = Vec::with_capacity((array.len() + chunk_size - 1) / chunk_size);
78 for chunk in array.chunks(chunk_size) {
79 chunks.push(chunk.to_vec());
80 }
81
82 Ok(chunks)
83}
84