1use crate::concat::concat;
21use arrow_array::{make_array, new_null_array, Array, ArrayRef};
22use arrow_schema::ArrowError;
23use num::abs;
24
25pub fn shift(array: &dyn Array, offset: i64) -> Result<ArrayRef, ArrowError> {
56 let value_len = array.len() as i64;
57 if offset == 0 {
58 Ok(make_array(array.to_data()))
59 } else if offset == i64::MIN || abs(offset) >= value_len {
60 Ok(new_null_array(array.data_type(), array.len()))
61 } else {
62 if offset > 0 {
64 let length = array.len() - offset as usize;
65 let slice = array.slice(0, length);
66
67 let null_arr = new_null_array(array.data_type(), offset as usize);
69 concat(&[null_arr.as_ref(), slice.as_ref()])
70 } else {
71 let offset = -offset as usize;
72 let length = array.len() - offset;
73 let slice = array.slice(offset, length);
74
75 let null_arr = new_null_array(array.data_type(), offset);
77 concat(&[slice.as_ref(), null_arr.as_ref()])
78 }
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use arrow_array::{Float64Array, Int32Array, Int32DictionaryArray};
86
87 #[test]
88 fn test_shift_neg() {
89 let a: Int32Array = vec![Some(1), None, Some(4)].into();
90 let res = shift(&a, -1).unwrap();
91 let expected: Int32Array = vec![None, Some(4), None].into();
92 assert_eq!(res.as_ref(), &expected);
93 }
94
95 #[test]
96 fn test_shift_pos() {
97 let a: Int32Array = vec![Some(1), None, Some(4)].into();
98 let res = shift(&a, 1).unwrap();
99 let expected: Int32Array = vec![None, Some(1), None].into();
100 assert_eq!(res.as_ref(), &expected);
101 }
102
103 #[test]
104 fn test_shift_neg_float64() {
105 let a: Float64Array = vec![Some(1.), None, Some(4.)].into();
106 let res = shift(&a, -1).unwrap();
107 let expected: Float64Array = vec![None, Some(4.), None].into();
108 assert_eq!(res.as_ref(), &expected);
109 }
110
111 #[test]
112 fn test_shift_pos_float64() {
113 let a: Float64Array = vec![Some(1.), None, Some(4.)].into();
114 let res = shift(&a, 1).unwrap();
115 let expected: Float64Array = vec![None, Some(1.), None].into();
116 assert_eq!(res.as_ref(), &expected);
117 }
118
119 #[test]
120 fn test_shift_neg_int32_dict() {
121 let a: Int32DictionaryArray = [Some("alpha"), None, Some("beta"), Some("alpha")]
122 .iter()
123 .copied()
124 .collect();
125 let res = shift(&a, -1).unwrap();
126 let expected: Int32DictionaryArray = [None, Some("beta"), Some("alpha"), None]
127 .iter()
128 .copied()
129 .collect();
130 assert_eq!(res.as_ref(), &expected);
131 }
132
133 #[test]
134 fn test_shift_pos_int32_dict() {
135 let a: Int32DictionaryArray = [Some("alpha"), None, Some("beta"), Some("alpha")]
136 .iter()
137 .copied()
138 .collect();
139 let res = shift(&a, 1).unwrap();
140 let expected: Int32DictionaryArray = [None, Some("alpha"), None, Some("beta")]
141 .iter()
142 .copied()
143 .collect();
144 assert_eq!(res.as_ref(), &expected);
145 }
146
147 #[test]
148 fn test_shift_nil() {
149 let a: Int32Array = vec![Some(1), None, Some(4)].into();
150 let res = shift(&a, 0).unwrap();
151 let expected: Int32Array = vec![Some(1), None, Some(4)].into();
152 assert_eq!(res.as_ref(), &expected);
153 }
154
155 #[test]
156 fn test_shift_boundary_pos() {
157 let a: Int32Array = vec![Some(1), None, Some(4)].into();
158 let res = shift(&a, 3).unwrap();
159 let expected: Int32Array = vec![None, None, None].into();
160 assert_eq!(res.as_ref(), &expected);
161 }
162
163 #[test]
164 fn test_shift_boundary_neg() {
165 let a: Int32Array = vec![Some(1), None, Some(4)].into();
166 let res = shift(&a, -3).unwrap();
167 let expected: Int32Array = vec![None, None, None].into();
168 assert_eq!(res.as_ref(), &expected);
169 }
170
171 #[test]
172 fn test_shift_boundary_neg_min() {
173 let a: Int32Array = vec![Some(1), None, Some(4)].into();
174 let res = shift(&a, i64::MIN).unwrap();
175 let expected: Int32Array = vec![None, None, None].into();
176 assert_eq!(res.as_ref(), &expected);
177 }
178
179 #[test]
180 fn test_shift_large_pos() {
181 let a: Int32Array = vec![Some(1), None, Some(4)].into();
182 let res = shift(&a, 1000).unwrap();
183 let expected: Int32Array = vec![None, None, None].into();
184 assert_eq!(res.as_ref(), &expected);
185 }
186
187 #[test]
188 fn test_shift_large_neg() {
189 let a: Int32Array = vec![Some(1), None, Some(4)].into();
190 let res = shift(&a, -1000).unwrap();
191 let expected: Int32Array = vec![None, None, None].into();
192 assert_eq!(res.as_ref(), &expected);
193 }
194}