Skip to content

Commit d32414d

Browse files
authored
Merge branch 'main' into tm/return-type-async
2 parents c6bdb87 + c586f10 commit d32414d

File tree

14 files changed

+242
-60
lines changed

14 files changed

+242
-60
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ datafusion-udf-wasm-query = { path = "query", version = "0.1.0" }
3131
http = { version = "1.3.1", default-features = false }
3232
hyper = { version = "1.8", default-features = false }
3333
insta = { version = "1.43.2", "default-features" = false }
34+
log = { version = "0.4.28", default-features = false }
3435
pyo3 = { version = "0.27.1", default-features = false, features = ["macros"] }
3536
sqlparser = { version = "0.55.0", default-features = false, features = [
3637
"std",
@@ -54,14 +55,22 @@ wit-bindgen = { version = "0.47", default-features = false, features = [
5455
] }
5556

5657
[workspace.lints.clippy]
57-
allow_attributes = "warn"
58+
allow_attributes = "deny"
5859
clone_on_ref_ptr = "deny"
60+
comparison_chain = "deny"
5961
dbg_macro = "deny"
6062
explicit_iter_loop = "deny"
6163
future_not_send = "deny"
6264
missing_docs_in_private_items = "deny"
65+
range_minus_one = "deny"
66+
range_plus_one = "deny"
67+
semicolon_if_nothing_returned = "deny"
6368
todo = "deny"
6469
undocumented_unsafe_blocks = "deny"
70+
unnecessary_semicolon = "deny"
71+
unnecessary_wraps = "deny"
72+
unused_async = "deny"
73+
unused_self = "deny"
6574
use_self = "deny"
6675

6776
[workspace.lints.rust]

guests/bundle/build.rs

Lines changed: 99 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33

44
use std::{
55
collections::HashMap,
6+
fs::File,
7+
io::Write,
68
path::{Path, PathBuf},
79
process::{Command, Stdio},
810
str::FromStr,
911
};
1012

1113
fn main() {
14+
let out_dir = PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
1215
let profile: Profile = std::env::var("PROFILE").unwrap().parse().unwrap();
1316
let package_locations = package_locations();
1417

@@ -28,10 +31,16 @@ fn main() {
2831
|| std::env::var("DOCS_RS").is_ok()
2932
|| std::env::var("JUSTCHECK").is_ok();
3033

34+
let mut gen_file = File::create(out_dir.join("gen.rs")).unwrap();
35+
3136
for feature in FEATURES {
3237
println!("processing {}", feature.name);
33-
feature.build_or_stub(stub, profile, &package_locations);
38+
feature.build_or_stub(stub, profile, &package_locations, &out_dir, &mut gen_file);
3439
}
40+
41+
gen_file.flush().unwrap();
42+
43+
println!("cargo::rerun-if-changed=build.rs");
3544
}
3645

3746
/// Get locations for all packages in the dependency tree.
@@ -151,6 +160,27 @@ impl std::fmt::Display for Profile {
151160
}
152161
}
153162

163+
/// Artifact type.
164+
enum ArtifactType {
165+
/// Library.
166+
Lib,
167+
168+
/// Example.
169+
Example(&'static str),
170+
}
171+
172+
/// Just(file) command.
173+
struct JustCmd {
174+
/// Artifact type.
175+
artifact_type: ArtifactType,
176+
177+
/// Name of the resulting constant.
178+
const_name: &'static str,
179+
180+
/// Documentation for the created constant.
181+
doc: &'static str,
182+
}
183+
154184
/// Feature description.
155185
struct Feature {
156186
/// Lowercase feature name.
@@ -159,15 +189,8 @@ struct Feature {
159189
/// Package that contains the feature code.
160190
package: &'static str,
161191

162-
/// `just` command prefix that compiles the feature.
163-
///
164-
/// This will call `just prefix{profile}` within the package directory.
165-
just_cmd_prefix: &'static str,
166-
167-
/// Path components to file in target directory.
168-
///
169-
/// So `["foo", "bar.bin"]` will resolve to `CARGO_TARGET_DIR/wasm32-wasip2/foo/bar.bin`.
170-
just_out_file: &'static [&'static str],
192+
/// Just commands.
193+
just_cmds: &'static [JustCmd],
171194
}
172195

173196
impl Feature {
@@ -177,12 +200,13 @@ impl Feature {
177200
stub: bool,
178201
profile: Profile,
179202
package_locations: &HashMap<String, PathBuf>,
203+
out_dir: &Path,
204+
gen_file: &mut File,
180205
) {
181206
let Self {
182207
name,
183208
package,
184-
just_cmd_prefix,
185-
just_out_file,
209+
just_cmds,
186210
} = self;
187211

188212
let name_upper = name.to_uppercase();
@@ -191,32 +215,61 @@ impl Feature {
191215
return;
192216
}
193217

194-
let out_dir = PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
195-
196-
let out_file = if stub {
197-
let out_file = out_dir.join(format!("{name}.wasm"));
198-
// write empty stub file
199-
std::fs::write(&out_file, b"").unwrap();
200-
out_file
201-
} else {
202-
let target_dir = out_dir.join(name);
218+
let cwd = package_locations.get(*package).unwrap();
219+
let target_dir = out_dir.join(name);
220+
221+
for just_cmd in *just_cmds {
222+
let JustCmd {
223+
artifact_type,
224+
const_name,
225+
doc,
226+
} = just_cmd;
227+
let out_file = if stub {
228+
let out_file = out_dir.join(format!("{name}.wasm"));
229+
// write empty stub file
230+
std::fs::write(&out_file, b"").unwrap();
231+
out_file
232+
} else {
233+
let mut just_cmd = "build-".to_owned();
234+
match artifact_type {
235+
ArtifactType::Lib => {}
236+
ArtifactType::Example(example) => {
237+
just_cmd.push_str(example);
238+
just_cmd.push('-');
239+
}
240+
}
241+
just_cmd.push_str(profile.as_str());
242+
243+
just_build(cwd, &just_cmd, &target_dir);
244+
245+
let out = target_dir.join("wasm32-wasip2").join(profile.as_str());
246+
match artifact_type {
247+
ArtifactType::Lib => out.join(format!("{}.wasm", package.replace("-", "_"))),
248+
ArtifactType::Example(example) => out
249+
.join("examples")
250+
.join(format!("{}.wasm", example.replace("-", "_"))),
251+
}
252+
};
203253

204-
just_build(
205-
package_locations.get(*package).unwrap(),
206-
&format!("{just_cmd_prefix}{profile}"),
207-
&target_dir,
254+
println!(
255+
"cargo::rustc-env=BIN_PATH_{const_name}={}",
256+
out_file.display(),
208257
);
209258

210-
just_out_file.iter().fold(
211-
target_dir.join("wasm32-wasip2").join(profile.as_str()),
212-
|path, part| path.join(part),
213-
)
214-
};
215-
216-
println!(
217-
"cargo::rustc-env=BIN_PATH_{name_upper}={}",
218-
out_file.display(),
219-
);
259+
writeln!(gen_file, "/// {doc}").unwrap();
260+
writeln!(gen_file, r#"#[cfg(feature = "{name}")]"#).unwrap();
261+
writeln!(gen_file, r#"pub static BIN_{const_name}: &[u8] = include_bytes!(env!("BIN_PATH_{const_name}"));"#).unwrap();
262+
263+
// we cannot really depend directly on examples, so we need to tell Cargo about it
264+
if let ArtifactType::Example(example) = artifact_type {
265+
println!(
266+
"cargo::rerun-if-changed={}",
267+
cwd.join("examples")
268+
.join(format!("{}.rs", example.replace("-", "_")))
269+
.display(),
270+
);
271+
}
272+
}
220273
}
221274
}
222275

@@ -232,18 +285,24 @@ fn just_build(cwd: &Path, just_cmd: &str, cargo_target_dir: &Path) {
232285

233286
/// All supported features.
234287
///
235-
/// This must be in-sync with the feature list in `Cargo.toml` and the imports in `src/lib.rs`.
288+
/// This must be in-sync with the feature list in `Cargo.toml`.
236289
const FEATURES: &[Feature] = &[
237290
Feature {
238291
name: "example",
239292
package: "datafusion-udf-wasm-guest",
240-
just_cmd_prefix: "build-add-one-",
241-
just_out_file: &["examples", "add_one.wasm"],
293+
just_cmds: &[JustCmd {
294+
artifact_type: ArtifactType::Example("add-one"),
295+
const_name: "EXAMPLE",
296+
doc: r#""add-one" example."#,
297+
}],
242298
},
243299
Feature {
244300
name: "python",
245301
package: "datafusion-udf-wasm-python",
246-
just_cmd_prefix: "",
247-
just_out_file: &["datafusion_udf_wasm_python.wasm"],
302+
just_cmds: &[JustCmd {
303+
artifact_type: ArtifactType::Lib,
304+
const_name: "PYTHON",
305+
doc: "Python UDF.",
306+
}],
248307
},
249308
];

guests/bundle/src/lib.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
11
//! Bundles guests as pre-compiled WASM bytecode.
22
3-
/// "add-one" example.
4-
#[cfg(feature = "example")]
5-
pub static BIN_EXAMPLE: &[u8] = include_bytes!(env!("BIN_PATH_EXAMPLE"));
6-
7-
/// Python UDF.
8-
#[cfg(feature = "python")]
9-
pub static BIN_PYTHON: &[u8] = include_bytes!(env!("BIN_PATH_PYTHON"));
3+
include!(concat!(env!("OUT_DIR"), "/gen.rs"));

guests/python/Justfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,13 @@ build-lib profile: download-python-sdk download-wasi-sdk python-site-packages
163163
do profile: (build-lib profile)
164164

165165
# create dev/debug build
166-
debug: (do "debug")
166+
build-debug: (do "debug")
167167

168168
# create release build
169-
release: (do "release")
169+
build-release: (do "release")
170170

171171
# checks build
172-
check-build: debug
172+
check-build: build-debug
173173

174174
# clean build artifacts
175175
clean:

guests/python/README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
Use:
55

66
```console
7-
just debug
7+
just build-debug
88
```
99

1010
or
1111

1212
```console
13-
just release
13+
just build-release
1414
```
1515

1616
## Python Version
@@ -197,6 +197,9 @@ def compute(x: int) -> int:
197197
## I/O
198198
All I/O operations go through the host, there is no direct interaction with the host operating system.
199199

200+
### Environment Variables
201+
Hosts can pass environment variables to the guest if they want. By default, NO variables are available for the guest though (i.e. there is NO implicit pass-through). The standard Python library can read these environment variables, e.g. via [`os.environ`].
202+
200203
### Filesystem
201204
The [Python Standard Library] is mounted as a read-only filesystem. The host file system (incl. special paths like `/proc`) are NOT exposed to the guest.
202205

@@ -234,6 +237,7 @@ There is NO other I/O available that escapes the sandbox.
234237
[`timedelta`]: https://docs.python.org/3/library/datetime.html#datetime.timedelta
235238
[`Duration`]: https://docs.rs/arrow/latest/arrow/datatypes/enum.DataType.html#variant.Duration
236239
[`Microsecond`]: https://docs.rs/arrow/latest/arrow/datatypes/enum.TimeUnit.html#variant.Microsecond
240+
[`os.environ`]: https://docs.python.org/3/library/os.html#os.environ
237241
[Python 3.14.0]: https://www.python.org/downloads/release/python-3140
238242
[Python Standard Library]: https://docs.python.org/3/library/index.html
239243
[`requests`]: https://pypi.org/project/requests/

guests/rust/examples/add_one.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ fn root() -> Option<Vec<u8>> {
102102
/// Returns our one example UDF.
103103
///
104104
/// The passed `source` is ignored.
105+
#[expect(clippy::unnecessary_wraps, reason = "public API through export! macro")]
105106
fn udfs(_source: String) -> DataFusionResult<Vec<Arc<dyn ScalarUDFImpl>>> {
106107
Ok(vec![Arc::new(AddOne::default())])
107108
}

host/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ datafusion-expr.workspace = true
1212
datafusion-udf-wasm-arrow2bytes.workspace = true
1313
http.workspace = true
1414
hyper.workspace = true
15+
log.workspace = true
1516
rand = { version = "0.9" }
1617
siphasher = { version = "1", default-features = false }
1718
tar.workspace = true

0 commit comments

Comments
 (0)