Skip to content

Commit 8793ce4

Browse files
authored
Merge pull request #65 from influxdata/crepererum/simplify_array_builder
refactor: simplify `ArrayBuilder` interface
2 parents 757c2c5 + cb2558c commit 8793ce4

File tree

1 file changed

+32
-61
lines changed

1 file changed

+32
-61
lines changed

guests/python/src/conversion.rs

Lines changed: 32 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,7 @@ impl PythonType {
9191
/// Get a builder for the Arrow output [`Array`].
9292
///
9393
/// This needs an "attached" [`Python`] to create Python objects.
94-
fn python_to_arrow<'py>(
95-
&self,
96-
num_rows: usize,
97-
) -> Box<dyn ArrayBuilder<'py, T = Option<Bound<'py, PyAny>>>> {
94+
fn python_to_arrow<'py>(&self, num_rows: usize) -> Box<dyn ArrayBuilder<'py>> {
9895
match self {
9996
Self::Bool => Box::new(BooleanBuilder::with_capacity(num_rows)),
10097
Self::Int => Box::new(Int64Builder::with_capacity(num_rows)),
@@ -141,7 +138,7 @@ impl PythonNullableType {
141138
&self,
142139
py: Python<'py>,
143140
num_rows: usize,
144-
) -> Box<dyn ArrayBuilder<'py, T = Bound<'py, PyAny>> + 'py> {
141+
) -> Box<dyn ArrayBuilder<'py> + 'py> {
145142
let inner = self.t.python_to_arrow(num_rows);
146143
let none = PyNone::get(py).into_bound();
147144
Box::new(ArrayBuilderNullChecker {
@@ -154,16 +151,10 @@ impl PythonNullableType {
154151

155152
/// Abstract builder for Arrow output [`Array`].
156153
pub(crate) trait ArrayBuilder<'py> {
157-
/// Types that can be converted into the respective [`Array`] value.
158-
///
159-
/// This is either `Bound<'py, PyAny>` (if called directly using the Python value) or `Option<Bound<'py, PyAny>>`
160-
/// (if we already reasoned about nullability).
161-
type T;
162-
163154
/// Push a new value.
164155
///
165156
/// This may fail if the type doesn't match.
166-
fn push(&mut self, val: Self::T) -> DataFusionResult<()>;
157+
fn push(&mut self, val: Bound<'py, PyAny>) -> DataFusionResult<()>;
167158

168159
/// Skip this row, i.e. append a "null".
169160
fn skip(&mut self);
@@ -185,21 +176,21 @@ struct ArrayBuilderNullChecker<'py> {
185176
none: Bound<'py, PyNone>,
186177

187178
/// The type-specific converter that came out of [`PythonType::arrow_to_python`].
188-
inner: Box<dyn ArrayBuilder<'py, T = Option<Bound<'py, PyAny>>>>,
179+
inner: Box<dyn ArrayBuilder<'py>>,
189180
}
190181

191182
impl<'py> ArrayBuilder<'py> for ArrayBuilderNullChecker<'py> {
192-
type T = Bound<'py, PyAny>;
193-
194-
fn push(&mut self, val: Self::T) -> DataFusionResult<()> {
195-
let val = match (self.nullable, val.is(&self.none)) {
183+
fn push(&mut self, val: Bound<'py, PyAny>) -> DataFusionResult<()> {
184+
match (self.nullable, val.is(&self.none)) {
196185
(false, true) => {
197-
return exec_err!("method was not supposed to return None but did");
186+
exec_err!("method was not supposed to return None but did")
198187
}
199-
(false | true, false) => Some(val),
200-
(true, true) => None,
201-
};
202-
self.inner.push(val)
188+
(false | true, false) => self.inner.push(val),
189+
(true, true) => {
190+
self.inner.skip();
191+
Ok(())
192+
}
193+
}
203194
}
204195

205196
fn skip(&mut self) {
@@ -212,22 +203,12 @@ impl<'py> ArrayBuilder<'py> for ArrayBuilderNullChecker<'py> {
212203
}
213204

214205
impl<'py> ArrayBuilder<'py> for BooleanBuilder {
215-
type T = Option<Bound<'py, PyAny>>;
216-
217-
fn push(&mut self, val: Self::T) -> DataFusionResult<()> {
218-
match val {
219-
Some(val) => {
220-
let val: bool = val.extract().map_err(|_| {
221-
exec_datafusion_err!("expected bool but got {}", py_representation(&val))
222-
})?;
223-
self.append_value(val);
224-
Ok(())
225-
}
226-
None => {
227-
self.append_null();
228-
Ok(())
229-
}
230-
}
206+
fn push(&mut self, val: Bound<'py, PyAny>) -> DataFusionResult<()> {
207+
let val: bool = val.extract().map_err(|_| {
208+
exec_datafusion_err!("expected bool but got {}", py_representation(&val))
209+
})?;
210+
self.append_value(val);
211+
Ok(())
231212
}
232213

233214
fn skip(&mut self) {
@@ -240,29 +221,19 @@ impl<'py> ArrayBuilder<'py> for BooleanBuilder {
240221
}
241222

242223
impl<'py> ArrayBuilder<'py> for Int64Builder {
243-
type T = Option<Bound<'py, PyAny>>;
244-
245-
fn push(&mut self, val: Self::T) -> DataFusionResult<()> {
246-
match val {
247-
Some(val) => {
248-
// in Python, `bool` is a sub-class of int we should probably not silently cast bools to integers
249-
let val = val.downcast_exact::<PyInt>().map_err(|_| {
250-
exec_datafusion_err!("expected `int` but got {}", py_representation(&val))
251-
})?;
252-
let val: i64 = val.extract().map_err(|_| {
253-
exec_datafusion_err!(
254-
"expected i64 but got {}, which is out-of-range",
255-
py_representation(val)
256-
)
257-
})?;
258-
self.append_value(val);
259-
Ok(())
260-
}
261-
None => {
262-
self.append_null();
263-
Ok(())
264-
}
265-
}
224+
fn push(&mut self, val: Bound<'py, PyAny>) -> DataFusionResult<()> {
225+
// in Python, `bool` is a sub-class of int we should probably not silently cast bools to integers
226+
let val = val.downcast_exact::<PyInt>().map_err(|_| {
227+
exec_datafusion_err!("expected `int` but got {}", py_representation(&val))
228+
})?;
229+
let val: i64 = val.extract().map_err(|_| {
230+
exec_datafusion_err!(
231+
"expected i64 but got {}, which is out-of-range",
232+
py_representation(val)
233+
)
234+
})?;
235+
self.append_value(val);
236+
Ok(())
266237
}
267238

268239
fn skip(&mut self) {

0 commit comments

Comments
 (0)