Dependencies
The general rule is the repository's: prefer a mature crate (or a std API) over hand-rolled code,
and write down why a dependency is there. Every entry below has a comment in Cargo.toml saying what
it is responsible for.
- duckfn: attribute macros that register ordinary Rust functions
with DuckDB. The dependency names its two features explicitly,
cliandchrono, and deliberately avoidsall:allalso turns onduckdb-1-5(the same switch in quack-rs), the unstable region of the C API — copy functions, the host VFS, the scalar bind/init slots — and staying out of that region is what lets a later DuckDB release load the binary (see theUSE_UNSTABLE_C_API=0note in theMakefile).owned-connection, which is what brings induck_vfssince 0.0.15, is not needed either: persistence isstd::fson a native build and skipped altogether on wasm (see Design notes), so there is no use for a host file system. What this extension uses is:chrono, which converts the time wrapper types (DuckDate::to_naive_dateand friends);DuckLazySlot<T>, which turns "parse the DuckLazy argument once" into a type;cli, the command-line tool behindsrc/bin/duckfn.rs(it pulls clap and csv into duckfn).- The macros also generate a
SQL_NAMEconstant per signature — the name the function is really registered under — so error prefixes read that instead of a hand-written copy of the function-name literal, whiledescription/comment/exampleon the attribute are the one source of the function-description CSV (see Function descriptions).
- quack-rs: DuckDB C API bindings; the code expanded from
duckfn_entrypoint!refers to it directly. - libduckdb-sys: headers only, with
loadable-extensionenabled — so no local DuckDB build is required. The version floor is>= 1.10500(DuckDB 1.5.0: the crate encodes a DuckDB version as1.<major*10000 + minor*100 + patch>.0, so 1.5.6 is1.10506.0), which is the release this build rests on. duckfn and quack-rs each carry a>=1.4.4, <2floor of their own; holding it tighter here is this project's own choice, and it pins which headers the dependency tree uses. It is no longer driven by theduckdb-1-5feature — that one is off (see theduckfnentry above). - quantstats-rs: the report itself. Its public API exposes
only
html()as a callable entry point (mod statsis private, socompute_performance_metricsis unreachable), so both paths are built on it instead of recomputing metrics — that would create a second source of truth for numbers the report already prints. - chrono: used directly for local time — report file names
(shared by persistence and the temporary file) start with a
%Y%m%d-%H%M%Sstamp (chrono::Local, see naming.rs). The date side is duckfn'schronofeature (DuckDate::to_naive_date), whoseNaiveDateis exactly what quantstats-rs'ReturnSeries::newtakes; all three share one chrono 0.4. - sanitize-filename and
fastrand: the two halves of a report file name — which parts
are legal (illegal and control characters, Windows reserved device names, trailing dots and spaces)
and the random suffix. Both stay shared dependencies rather than moving to the non-wasm table:
naming.rsis compiled for every target, and keeping that module free ofcfgs is worth more than dropping two small crates from a wasm build that names no files anyway (nothing calls it there). fastrand is already in the tree (tempfile uses it internally), so a direct dependency costs no extra compilation. - lol_html: the translation feature's one HTML rewrite
(Translation). It targets CSS selectors, streams, and can rewrite text
and markup as it goes — which is what "only the positions in the catalog, not one character anywhere
else" needs. Hand-rolled string replacement cannot do that, and hand-writing an HTML parser for it
would not be worth it. Its version is pinned exactly: 3.x uses let-chains, which need Rust 1.88
while this project pins 1.86 (the
rust-version = "1.85"3.x declares is an upstream mistake), so 2.7.0 is the last release that compiles here. - open and tempfile:
open_in_browser's two jobs — starting the browser and, withoutoutput_dir, creating a uniquely named temporary file. Non-wasm targets only (see Design notes), which is why they live in a target-specific dependency table instead of the main one.