polars_ops/series/ops/
index.rs1use num_traits::ToPrimitive;
2use polars_core::error::{PolarsResult, polars_bail, polars_ensure};
3use polars_core::prelude::{ChunkedArray, DataType, IdxCa, IdxSize, PolarsIntegerType, Series};
4
5fn convert_unsigned<T>(ca: &ChunkedArray<T>, target_len: usize) -> PolarsResult<IdxCa>
11where
12 T: PolarsIntegerType,
13 T::Native: ToPrimitive,
14{
15 let len_u64 = target_len as u64;
16
17 let out: IdxCa = ca
18 .into_iter()
19 .map(|opt_v| {
20 opt_v.and_then(|v| {
21 let v_u64 = v.to_u64()?;
23
24 if v_u64 < len_u64 {
25 Some(v_u64 as IdxSize)
26 } else {
27 None
28 }
29 })
30 })
31 .collect();
32
33 Ok(out)
34}
35
36fn convert_signed<T>(ca: &ChunkedArray<T>, target_len: usize) -> PolarsResult<IdxCa>
44where
45 T: PolarsIntegerType,
46 T::Native: ToPrimitive,
47{
48 let len_i64 = target_len as i64;
49
50 let out: IdxCa = ca
51 .into_iter()
52 .map(|opt_v| {
53 opt_v.and_then(|v| {
54 let v_i64 = v.to_i64()?;
56
57 if v_i64 >= 0 {
58 if v_i64 < len_i64 {
60 Some(v_i64 as IdxSize)
61 } else {
62 None
63 }
64 } else {
65 if v_i64 >= -len_i64 {
67 let pos = len_i64 + v_i64; debug_assert!(pos >= 0 && pos < len_i64);
69 Some(pos as IdxSize)
70 } else {
71 None
72 }
73 }
74 })
75 })
76 .collect();
77
78 Ok(out)
79}
80
81pub fn convert_to_unsigned_index(
88 s: &Series,
89 target_len: usize,
90 null_on_oob: bool,
91) -> PolarsResult<IdxCa> {
92 let dtype = s.dtype();
93 polars_ensure!(
94 dtype.is_integer(),
95 InvalidOperation: "expected integers as index"
96 );
97
98 assert!(
99 (target_len as u128) <= (IdxSize::MAX as u128),
100 "internal error: target_len does not fit in IdxSize"
101 );
102
103 let in_nulls = s.null_count();
104
105 let idx: IdxCa = match dtype {
107 DataType::Int64 => {
109 let ca = s.i64().unwrap();
110 convert_signed(ca, target_len)?
111 },
112 DataType::Int32 => {
113 let ca = s.i32().unwrap();
114 convert_signed(ca, target_len)?
115 },
116 #[cfg(feature = "dtype-i16")]
117 DataType::Int16 => {
118 let ca = s.i16().unwrap();
119 convert_signed(ca, target_len)?
120 },
121 #[cfg(feature = "dtype-i8")]
122 DataType::Int8 => {
123 let ca = s.i8().unwrap();
124 convert_signed(ca, target_len)?
125 },
126 #[cfg(feature = "dtype-i128")]
127 DataType::Int128 => {
128 let ca = s.i128().unwrap();
129 convert_signed(ca, target_len)?
130 },
131
132 DataType::UInt64 => {
134 let ca = s.u64().unwrap();
135 convert_unsigned(ca, target_len)?
136 },
137 DataType::UInt32 => {
138 let ca = s.u32().unwrap();
139 convert_unsigned(ca, target_len)?
140 },
141 #[cfg(feature = "dtype-u16")]
142 DataType::UInt16 => {
143 let ca = s.u16().unwrap();
144 convert_unsigned(ca, target_len)?
145 },
146 #[cfg(feature = "dtype-u8")]
147 DataType::UInt8 => {
148 let ca = s.u8().unwrap();
149 convert_unsigned(ca, target_len)?
150 },
151 #[cfg(feature = "dtype-u128")]
152 DataType::UInt128 => {
153 let ca = s.u128().unwrap();
154 convert_unsigned(ca, target_len)?
155 },
156
157 _ => unreachable!(),
158 };
159
160 let out_nulls = idx.null_count();
161
162 if !null_on_oob && out_nulls > in_nulls {
163 polars_bail!(
164 OutOfBounds: "gather indices are out of bounds"
165 );
166 }
167
168 Ok(idx)
169}