Platforms and versions

Supported platforms, minimum Rust version, crate layout, features, dependencies, the expressions feature on WebAssembly, thread safety and how releases and the 1.x versioning policy work.

With the default features, dxn_dtcg is pure, safe Rust. The crates have no build scripts, no C code, no unsafe code, no async runtime and no file-system or network access, so the default build compiles for any target that has the Rust standard library. The opt-in expressions feature changes that on purpose: it adds a JavaScript engine written in C (QuickJS), compiled with the platform’s C compiler, and a small amount of unsafe code around it. Everything below says which build it describes.

#Platform support

PlatformStatus
Linux x86_64Tested in CI: formatting, Clippy with -D warnings, tests, cargo package; the --all-features steps compile QuickJS with the system C compiler
Windows x86_64Tested in CI: the same steps, with MSVC compiling QuickJS
macOS arm64Tested in CI: the same steps, with Apple Clang compiling QuickJS
WebAssembly (wasm32-unknown-unknown)Tested in CI under Node: Clippy and the whole test suite, with and without expressions (which builds with an LLVM clang, below). Needs no host I/O, threads or system calls
iOS, Android and other std targetsExpected to work (no platform-specific code); not covered by CI. With expressions, the target also needs a C compiler that QuickJS builds with
  • Rust 1.97 or newer, edition 2024. no_std is not supported. The repository pins the toolchain to 1.97.0 in rust-toolchain.toml.
  • No threads started, no clock, randomness or environment access, in either build. Expressions run without a clock or randomness (Date does not exist and Math.random throws).
  • Thread safety. DtcgRuntime, ResolvedTokens, ResolvedToken and DtcgError are Send + Sync, with or without expression options (native functions must be Send + Sync). Resolution borrows the runtime immutably, so several threads can resolve against one runtime at once; with expressions, each resolution starts its own JavaScript engine. Mutating methods take &mut self; to update while others read, use a lock or a copy-on-write handle (see the cookbook).

#Crates and features

CrateKindContents
dxn_dtcglibraryDtcgRuntime, catalog, resolver, value validation, projection traits, source inspection, diagnostics, and with its feature the expression engine
dxn_dtcg_deriveproc-macro#[derive(DtcgTokens)], #[derive(DtcgComponentTokens)], #[expression_module]

dxn_dtcg depends on the derive crate and re-exports its macros (#[expression_module] as dxn_dtcg::expressions::expression_module, with the expressions feature), so applications depend only on dxn_dtcg.

FeatureDefaultAdds
diagnosticsoffDtcgDiagnostic, DtcgDiagnosticCode and AffectedResolution::nodes_visited(); see Limits and diagnostics
expressionsoffComputed token values: the dxn_dtcg::expressions module (ExpressionOptions, ExpressionModule, NativeModule, expression_module), RuntimeOptions::with_expressions, and the QuickJS engine and oxc compiler behind them; see Expressions

Enabling the feature compiles the engine in but evaluates nothing: a runtime evaluates expressions only when its RuntimeOptions enable them, so feature unification in a larger build never changes how another crate’s runtime resolves. The color API on values::Color, DocumentKind, the module catalog methods and ResolvedToken::snapshot are part of every build.

Runtime dependencies are serde, serde_json (with preserve_order, which token order depends on), sha2 and thiserror. The expressions feature adds quickjs-jit (QuickJS bindings; its quickjs-jit-sys crate compiles QuickJS’s C sources with the cc crate) and oxc (the JavaScript and TypeScript parser and transformer). The derive crate uses syn, quote and proc-macro2. Both crates are dual-licensed MIT OR Apache-2.0.

What the feature changes about the crate itself:

  • C code. QuickJS is compiled from C for the target. The default build compiles no C and needs no C compiler.
  • unsafe code. The default build has none. The feature adds a counting allocator for the engine (the memory and stack limits) and, on wasm32-unknown-unknown, one exported function, the clock symbol described below.
  • Build scripts. The crates still have none of their own; the C build runs in the build script of the quickjs-jit-sys dependency.

#WebAssembly and expressions

With the default features, dxn_dtcg builds for wasm32-unknown-unknown with nothing but the Rust target. With expressions, QuickJS must be compiled for WebAssembly too, which needs an LLVM clang with the WebAssembly target and llvm-ar, named through the cc crate’s variables CC_wasm32_unknown_unknown and AR_wasm32_unknown_unknown:

CC_wasm32_unknown_unknown=/opt/homebrew/opt/llvm/bin/clang \
AR_wasm32_unknown_unknown=/opt/homebrew/opt/llvm/bin/llvm-ar \
cargo build --target wasm32-unknown-unknown --features expressions

Apple’s clang has no WebAssembly target; Homebrew’s llvm or a distribution’s clang and llvm packages do.

  • The default expression stack_limit (256 KiB) fits the default 1 MiB WebAssembly stack.
  • Panics abort on wasm32-unknown-unknown, so a panicking native function stops the module instead of becoming a JavaScript error as it does natively.

CI runs the whole test suite on wasm32-unknown-unknown under Node with wasm-bindgen-test-runner, with all features and with the default ones, and lints that target with Clippy. The wasm32 job installs clang and llvm and wasm-bindgen-cli at the wasm-bindgen version locked in Cargo.lock. Contributing shows how to run the suite locally.

#Installing a release

Releases are git tags; nothing is published to crates.io. Depend on a tag, never on a branch or a path:

[dependencies]
dxn_dtcg = { git = "https://github.com/dXnSix/dXn.Dtcg", tag = "v1.1.0" }

Cargo.lock records the exact commit. To update, change the tag by hand; the newest is on the Releases page. dxn_dtcg_derive resolves from the same tag. Add features = ["expressions"] for computed tokens, with a tag that includes the feature.

#Versioning

Both crates share one version, one tag vX.Y.Z and one CHANGELOG.md. The crates stay on 1.x: no commit is marked breaking, and a breaking change is released as a minor or patch version whose changelog entry carries a Migration: line for each affected audience, such as token documents or the Rust API. Plan for it accordingly and read the changelog when you move to a new tag. Types marked #[non_exhaustive] (including DtcgError, DocumentKind and ExpressionOptions) may gain variants and fields in minor releases.

Next: Contributing.