Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 68 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,68 @@ keywords = ["scripting", "scripting-engine", "scripting-language", "embedded"]
categories = ["no-std", "embedded", "wasm", "parser-implementations"]

[dependencies]
smallvec = { version = "1.7.0", default-features = false, features = ["union", "const_new", "const_generics"] }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See if you can avoid generating many changes due to auto-reformatting. This distracts from the actual changes in the file.

smallvec = { version = "1.7.0", default-features = false, features = [
"union",
"const_new",
"const_generics",
] }
thin-vec = { version = "0.2.13", default-features = false }
ahash = { version = "0.8.4", default-features = false, features = ["compile-time-rng"] }
ahash = { version = "0.8.4", default-features = false, features = [
"compile-time-rng",
] }
num-traits = { version = "0.2.14", default-features = false }
once_cell = { version = "1.20.1", default-features = false, features = ["race", "portable-atomic", "alloc"] }
once_cell = { version = "1.20.1", default-features = false, features = [
"race",
"portable-atomic",
"alloc",
] }
bitflags = { version = "2.3.3", default-features = false }
smartstring = { version = "1.0.0", default-features = false }
rhai_codegen = { version = "3.1.0", path = "codegen" }

no-std-compat = { git = "https://gitlab.com/jD91mZM2/no-std-compat.git", version = "0.4.1", default-features = false, features = ["alloc"], optional = true }
no-std-compat = { git = "https://gitlab.com/jD91mZM2/no-std-compat.git", version = "0.4.1", default-features = false, features = [
"alloc",
], optional = true }
libm = { version = "0.2.0", default-features = false, optional = true }
hashbrown = { version = "0.16.0", optional = true }
core-error = { version = "0.0.0", default-features = false, features = ["alloc"], optional = true }
serde = { version = "1.0.136", default-features = false, features = ["derive", "alloc"], optional = true }
serde_json = { version = "1.0.45", default-features = false, features = ["alloc"], optional = true }
core-error = { version = "0.0.0", default-features = false, features = [
"alloc",
], optional = true }
serde = { version = "1.0.136", default-features = false, features = [
"derive",
"alloc",
], optional = true }
serde_json = { version = "1.0.45", default-features = false, features = [
"alloc",
], optional = true }
rkyv = { version = "0.7", default-features = false, features = [
"alloc",
"size_32",
], optional = true }
bytecheck = { version = "0.6", default-features = false, optional = true }
rend = { version = "0.4", default-features = false, optional = true }
unicode-xid = { version = "0.2.0", default-features = false, optional = true }
rust_decimal = { version = "1.24.0", default-features = false, features = ["maths"], optional = true }
rust_decimal = { version = "1.24.0", default-features = false, features = [
"maths",
], optional = true }
getrandom = { version = "0.2.7", optional = true }
rustyline = { version = "15.0.0", optional = true }
document-features = { version = "0.2.0", optional = true }
arbitrary = { version = "1.3.2", optional = true, features = ["derive"] }

[dev-dependencies]
rmp-serde = "1.1.1"
serde_json = { version = "1.0.45", default-features = false, features = ["alloc"] }
serde_json = { version = "1.0.45", default-features = false, features = [
"alloc",
] }

[features]

## Default features: `std`, uses runtime random numbers for hashing.
default = ["std", "ahash/runtime-rng"] # ahash/runtime-rng trumps ahash/compile-time-rng
default = [
"std",
"ahash/runtime-rng",
] # ahash/runtime-rng trumps ahash/compile-time-rng
## Standard features: uses compile-time random number for hashing.
std = ["once_cell/std", "ahash/std", "num-traits/std", "smartstring/std"]

Expand All @@ -59,6 +91,8 @@ sync = ["no-std-compat?/compat_sync", "rhai_codegen/sync"]
decimal = ["rust_decimal"]
## Enable serialization/deserialization of Rhai data types via [`serde`](https://crates.io/crates/serde).
serde = ["dep:serde", "smartstring/serde", "smallvec/serde", "thin-vec/serde"]
## Enable zero-copy serialization/deserialization via [`rkyv`](https://crates.io/crates/rkyv) (high-performance binary format).
rkyv = ["dep:rkyv", "dep:rend"]
## Allow [Unicode Standard Annex #31](https://unicode.org/reports/tr31/) for identifiers.
unicode-xid-ident = ["unicode-xid"]
## Enable functions metadata (including doc-comments); implies [`serde`](#feature-serde).
Expand Down Expand Up @@ -113,7 +147,14 @@ no_optimize = []
#! ### Compiling for `no-std`

## Turn on `no-std` compilation (nightly only).
no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "hashbrown", "no_time"]
no_std = [
"no-std-compat",
"num-traits/libm",
"core-error",
"libm",
"hashbrown",
"no_time",
]

#! ### JavaScript Interface for WASM

Expand Down Expand Up @@ -145,6 +186,10 @@ required-features = ["debugging"]
name = "serde"
required-features = ["serde"]

[[example]]
name = "rkyv"
required-features = ["rkyv"]

[[example]]
name = "definitions"
required-features = ["metadata", "internals"]
Expand All @@ -155,11 +200,22 @@ codegen-units = 1
#opt-level = "z" # optimize for size
#panic = 'abort' # remove stack backtrace for no-std

[[bench]]
name = "rkyv"
required-features = ["rkyv", "serde"]

[target.'cfg(target_family = "wasm")'.dependencies]
instant = { version = "0.1.10" } # WASM implementation of std::time::Instant

[package.metadata.docs.rs]
features = ["document-features", "metadata", "serde", "internals", "decimal", "debugging"]
features = [
"document-features",
"metadata",
"serde",
"internals",
"decimal",
"debugging",
]

[patch.crates-io]
# Notice that a custom modified version of `rustyline` is used which supports bracketed paste on Windows.
Expand Down
143 changes: 143 additions & 0 deletions benches/rkyv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#![feature(test)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benches are run upon commit in my dev repo, so I'm not sure if we'll blow up GitHub by adding so many new benches. We can try.

The benchmarks are not run in the official repo which is named main. I named mine master which will trigger running benchmarks and collecting performance data upon push.

#![cfg(all(feature = "rkyv", feature = "serde"))]

//! Benchmark comparing rkyv and serde serialization performance
extern crate test;

use rhai::Dynamic;
use test::Bencher;

// ============================================================================
// Integer Benchmarks
// ============================================================================

#[bench]
fn bench_rkyv_serialize_int(bench: &mut Bencher) {
let value = Dynamic::from(42_i64);
bench.iter(|| {
let bytes = rhai::rkyv::to_bytes(&value).unwrap();
test::black_box(bytes);
});
}

#[bench]
fn bench_serde_json_serialize_int(bench: &mut Bencher) {
let value = Dynamic::from(42_i64);
bench.iter(|| {
let json = serde_json::to_string(&value).unwrap();
test::black_box(json);
});
}

#[bench]
fn bench_rkyv_deserialize_int(bench: &mut Bencher) {
let value = Dynamic::from(42_i64);
let bytes = rhai::rkyv::to_bytes(&value).unwrap();

bench.iter(|| {
let restored: Dynamic = rhai::rkyv::from_bytes_owned(&bytes).unwrap();
test::black_box(restored);
});
}

#[bench]
fn bench_serde_json_deserialize_int(bench: &mut Bencher) {
let value = Dynamic::from(42_i64);
let json = serde_json::to_string(&value).unwrap();

bench.iter(|| {
let restored: Dynamic = serde_json::from_str(&json).unwrap();
test::black_box(restored);
});
}

#[bench]
fn bench_rkyv_roundtrip_int(bench: &mut Bencher) {
let value = Dynamic::from(42_i64);
bench.iter(|| {
let bytes = rhai::rkyv::to_bytes(&value).unwrap();
let restored: Dynamic = rhai::rkyv::from_bytes_owned(&bytes).unwrap();
test::black_box(restored);
});
}

#[bench]
fn bench_serde_json_roundtrip_int(bench: &mut Bencher) {
let value = Dynamic::from(42_i64);
bench.iter(|| {
let json = serde_json::to_string(&value).unwrap();
let restored: Dynamic = serde_json::from_str(&json).unwrap();
test::black_box(restored);
});
}

// ============================================================================
// String Benchmarks
// ============================================================================

#[bench]
fn bench_rkyv_serialize_string(bench: &mut Bencher) {
let value = Dynamic::from("Hello, World! This is a benchmark string.");
bench.iter(|| {
let bytes = rhai::rkyv::to_bytes(&value).unwrap();
test::black_box(bytes);
});
}

#[bench]
fn bench_serde_json_serialize_string(bench: &mut Bencher) {
let value = Dynamic::from("Hello, World! This is a benchmark string.");
bench.iter(|| {
let json = serde_json::to_string(&value).unwrap();
test::black_box(json);
});
}

#[bench]
fn bench_rkyv_deserialize_string(bench: &mut Bencher) {
let value = Dynamic::from("Hello, World! This is a benchmark string.");
let bytes = rhai::rkyv::to_bytes(&value).unwrap();

bench.iter(|| {
let restored: Dynamic = rhai::rkyv::from_bytes_owned(&bytes).unwrap();
test::black_box(restored);
});
}

#[bench]
fn bench_serde_json_deserialize_string(bench: &mut Bencher) {
let value = Dynamic::from("Hello, World! This is a benchmark string.");
let json = serde_json::to_string(&value).unwrap();

bench.iter(|| {
let restored: Dynamic = serde_json::from_str(&json).unwrap();
test::black_box(restored);
});
}

// ============================================================================
// Float Benchmarks
// ============================================================================

#[cfg(not(feature = "no_float"))]
#[bench]
fn bench_rkyv_roundtrip_float(bench: &mut Bencher) {
let value = Dynamic::from(3.14159265358979_f64);
bench.iter(|| {
let bytes = rhai::rkyv::to_bytes(&value).unwrap();
let restored: Dynamic = rhai::rkyv::from_bytes_owned(&bytes).unwrap();
test::black_box(restored);
});
}

#[cfg(not(feature = "no_float"))]
#[bench]
fn bench_serde_json_roundtrip_float(bench: &mut Bencher) {
let value = Dynamic::from(3.14159265358979_f64);
bench.iter(|| {
let json = serde_json::to_string(&value).unwrap();
let restored: Dynamic = serde_json::from_str(&json).unwrap();
test::black_box(restored);
});
}
Loading