Skip to content

Commit 05deb99

Browse files
authored
Merge pull request #216 from influxdata/crepererum/reduce-evil-boilerplate
refactor: reduce boilerplate in `evil` payload
2 parents d4d0350 + 0087fbe commit 05deb99

File tree

9 files changed

+139
-236
lines changed

9 files changed

+139
-236
lines changed

guests/evil/src/common.rs

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Methods used by multiple payloads.
22
3-
use std::{hash::Hash, sync::Arc};
3+
use std::{fmt::Debug, hash::Hash, ops::Deref, sync::Arc};
44

55
use arrow::{array::StringArray, datatypes::DataType};
66
use datafusion_common::{Result as DataFusionResult, cast::as_string_array};
@@ -21,13 +21,61 @@ pub(crate) fn udfs_empty(_source: String) -> DataFusionResult<Vec<Arc<dyn Scalar
2121
Ok(vec![])
2222
}
2323

24+
/// A container that shadows its inner dynamic value.
25+
///
26+
/// This is mostly used to simplify the handling of `Box<dyn Fn(...) -> ...>`.
27+
///
28+
/// The actual value is ignored for [`Debug`], [`PartialEq`], [`Eq`], and [`Hash`].
29+
pub(crate) struct DynBox<T>(pub(crate) Box<T>)
30+
where
31+
T: ?Sized;
32+
33+
impl<T> Debug for DynBox<T>
34+
where
35+
T: ?Sized,
36+
{
37+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38+
f.debug_tuple("DynBox").finish_non_exhaustive()
39+
}
40+
}
41+
42+
impl<T> PartialEq<Self> for DynBox<T>
43+
where
44+
T: ?Sized,
45+
{
46+
fn eq(&self, _other: &Self) -> bool {
47+
true
48+
}
49+
}
50+
51+
impl<T> Eq for DynBox<T> where T: ?Sized {}
52+
53+
impl<T> Hash for DynBox<T>
54+
where
55+
T: ?Sized,
56+
{
57+
fn hash<H: std::hash::Hasher>(&self, _state: &mut H) {}
58+
}
59+
60+
impl<T> Deref for DynBox<T>
61+
where
62+
T: ?Sized,
63+
{
64+
type Target = T;
65+
66+
fn deref(&self) -> &Self::Target {
67+
&self.0
68+
}
69+
}
70+
2471
/// UDF that produces a string from one input.
72+
#[derive(Debug, PartialEq, Eq, Hash)]
2573
pub(crate) struct String1Udf {
2674
/// Name.
2775
name: &'static str,
2876

2977
/// String producer.
30-
effect: Box<dyn Fn(String) -> Result<String, String> + Send + Sync>,
78+
effect: DynBox<dyn Fn(String) -> Result<String, String> + Send + Sync>,
3179

3280
/// Signature of the UDF.
3381
///
@@ -43,42 +91,12 @@ impl String1Udf {
4391
{
4492
Self {
4593
name,
46-
effect: Box::new(effect),
94+
effect: DynBox(Box::new(effect)),
4795
signature: Signature::uniform(1, vec![DataType::Utf8], Volatility::Immutable),
4896
}
4997
}
5098
}
5199

52-
impl std::fmt::Debug for String1Udf {
53-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54-
let Self {
55-
name,
56-
effect: _,
57-
signature,
58-
} = self;
59-
60-
f.debug_struct("StringUdf")
61-
.field("name", name)
62-
.field("effect", &"<EFFECT>")
63-
.field("signature", signature)
64-
.finish()
65-
}
66-
}
67-
68-
impl PartialEq<Self> for String1Udf {
69-
fn eq(&self, other: &Self) -> bool {
70-
self.name == other.name
71-
}
72-
}
73-
74-
impl Eq for String1Udf {}
75-
76-
impl Hash for String1Udf {
77-
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
78-
self.name.hash(state);
79-
}
80-
}
81-
82100
impl ScalarUDFImpl for String1Udf {
83101
fn as_any(&self) -> &dyn std::any::Any {
84102
self

guests/evil/src/env.rs

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@ use std::{hash::Hash, io::Read, sync::Arc};
33

44
use arrow::datatypes::DataType;
55
use datafusion_common::{Result as DataFusionResult, ScalarValue};
6-
use datafusion_expr::{ColumnarValue, ScalarFunctionArgs, ScalarUDFImpl, Signature, Volatility};
6+
use datafusion_expr::{
7+
ColumnarValue, ScalarFunctionArgs, ScalarUDFImpl, Signature, TypeSignature, Volatility,
8+
};
9+
10+
use crate::common::DynBox;
711

812
/// UDF that produces a string.
13+
#[derive(Debug, PartialEq, Eq, Hash)]
914
struct StringUdf {
1015
/// Name.
1116
name: &'static str,
1217

1318
/// String producer.
14-
effect: Box<dyn Fn() -> Option<String> + Send + Sync>,
15-
16-
/// Signature of the UDF.
17-
///
18-
/// We store this here because [`ScalarUDFImpl::signature`] requires us to return a reference.
19-
signature: Signature,
19+
effect: DynBox<dyn Fn() -> Option<String> + Send + Sync>,
2020
}
2121

2222
impl StringUdf {
@@ -27,42 +27,11 @@ impl StringUdf {
2727
{
2828
Self {
2929
name,
30-
effect: Box::new(effect),
31-
signature: Signature::uniform(0, vec![], Volatility::Immutable),
30+
effect: DynBox(Box::new(effect)),
3231
}
3332
}
3433
}
3534

36-
impl std::fmt::Debug for StringUdf {
37-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38-
let Self {
39-
name,
40-
effect: _,
41-
signature,
42-
} = self;
43-
44-
f.debug_struct("StringUdf")
45-
.field("name", name)
46-
.field("effect", &"<EFFECT>")
47-
.field("signature", signature)
48-
.finish()
49-
}
50-
}
51-
52-
impl PartialEq<Self> for StringUdf {
53-
fn eq(&self, other: &Self) -> bool {
54-
self.name == other.name
55-
}
56-
}
57-
58-
impl Eq for StringUdf {}
59-
60-
impl Hash for StringUdf {
61-
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
62-
self.name.hash(state);
63-
}
64-
}
65-
6635
impl ScalarUDFImpl for StringUdf {
6736
fn as_any(&self) -> &dyn std::any::Any {
6837
self
@@ -73,7 +42,12 @@ impl ScalarUDFImpl for StringUdf {
7342
}
7443

7544
fn signature(&self) -> &Signature {
76-
&self.signature
45+
static S: Signature = Signature {
46+
type_signature: TypeSignature::Uniform(0, vec![]),
47+
volatility: Volatility::Immutable,
48+
};
49+
50+
&S
7751
}
7852

7953
fn return_type(&self, _arg_types: &[DataType]) -> DataFusionResult<DataType> {

guests/evil/src/fs.rs

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ use arrow::{array::StringArray, datatypes::DataType};
55
use datafusion_common::{Result as DataFusionResult, cast::as_string_array};
66
use datafusion_expr::{ColumnarValue, ScalarFunctionArgs, ScalarUDFImpl, Signature, Volatility};
77

8-
use crate::common::String1Udf;
8+
use crate::common::{DynBox, String1Udf};
99

1010
/// UDF that produces a string from two inputs.
11+
#[derive(Debug, PartialEq, Eq, Hash)]
1112
struct String2Udf {
1213
/// Name.
1314
name: &'static str,
1415

1516
/// String producer.
16-
effect: Box<dyn Fn(String, String) -> Result<String, String> + Send + Sync>,
17+
effect: DynBox<dyn Fn(String, String) -> Result<String, String> + Send + Sync>,
1718

1819
/// Signature of the UDF.
1920
///
@@ -29,42 +30,12 @@ impl String2Udf {
2930
{
3031
Self {
3132
name,
32-
effect: Box::new(effect),
33+
effect: DynBox(Box::new(effect)),
3334
signature: Signature::uniform(2, vec![DataType::Utf8], Volatility::Immutable),
3435
}
3536
}
3637
}
3738

38-
impl std::fmt::Debug for String2Udf {
39-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40-
let Self {
41-
name,
42-
effect: _,
43-
signature,
44-
} = self;
45-
46-
f.debug_struct("StringUdf")
47-
.field("name", name)
48-
.field("effect", &"<EFFECT>")
49-
.field("signature", signature)
50-
.finish()
51-
}
52-
}
53-
54-
impl PartialEq<Self> for String2Udf {
55-
fn eq(&self, other: &Self) -> bool {
56-
self.name == other.name
57-
}
58-
}
59-
60-
impl Eq for String2Udf {}
61-
62-
impl Hash for String2Udf {
63-
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
64-
self.name.hash(state);
65-
}
66-
}
67-
6839
impl ScalarUDFImpl for String2Udf {
6940
fn as_any(&self) -> &dyn std::any::Any {
7041
self

guests/evil/src/runtime.rs

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@ use std::{hash::Hash, sync::Arc};
33

44
use arrow::datatypes::DataType;
55
use datafusion_common::{Result as DataFusionResult, ScalarValue};
6-
use datafusion_expr::{ColumnarValue, ScalarFunctionArgs, ScalarUDFImpl, Signature, Volatility};
6+
use datafusion_expr::{
7+
ColumnarValue, ScalarFunctionArgs, ScalarUDFImpl, Signature, TypeSignature, Volatility,
8+
};
9+
10+
use crate::common::DynBox;
711

812
/// UDF that executes a side effect.
13+
#[derive(Debug, PartialEq, Eq, Hash)]
914
struct SideEffect {
1015
/// Name.
1116
name: &'static str,
1217

1318
/// Side effect.
14-
effect: Box<dyn Fn() + Send + Sync>,
15-
16-
/// Signature of the UDF.
17-
///
18-
/// We store this here because [`ScalarUDFImpl::signature`] requires us to return a reference.
19-
signature: Signature,
19+
effect: DynBox<dyn Fn() + Send + Sync>,
2020
}
2121

2222
impl SideEffect {
@@ -27,42 +27,11 @@ impl SideEffect {
2727
{
2828
Self {
2929
name,
30-
effect: Box::new(effect),
31-
signature: Signature::uniform(0, vec![], Volatility::Immutable),
30+
effect: DynBox(Box::new(effect)),
3231
}
3332
}
3433
}
3534

36-
impl std::fmt::Debug for SideEffect {
37-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38-
let Self {
39-
name,
40-
effect: _,
41-
signature,
42-
} = self;
43-
44-
f.debug_struct("SideEffect")
45-
.field("name", name)
46-
.field("effect", &"<EFFECT>")
47-
.field("signature", signature)
48-
.finish()
49-
}
50-
}
51-
52-
impl PartialEq<Self> for SideEffect {
53-
fn eq(&self, other: &Self) -> bool {
54-
self.name == other.name
55-
}
56-
}
57-
58-
impl Eq for SideEffect {}
59-
60-
impl Hash for SideEffect {
61-
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
62-
self.name.hash(state);
63-
}
64-
}
65-
6635
impl ScalarUDFImpl for SideEffect {
6736
fn as_any(&self) -> &dyn std::any::Any {
6837
self
@@ -73,7 +42,12 @@ impl ScalarUDFImpl for SideEffect {
7342
}
7443

7544
fn signature(&self) -> &Signature {
76-
&self.signature
45+
static S: Signature = Signature {
46+
type_signature: TypeSignature::Uniform(0, vec![]),
47+
volatility: Volatility::Immutable,
48+
};
49+
50+
&S
7751
}
7852

7953
fn return_type(&self, _arg_types: &[DataType]) -> DataFusionResult<DataType> {

0 commit comments

Comments
 (0)