diff --git a/Cargo.toml b/Cargo.toml index 232430b..e467394 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ exclude = [ "benchmarks/gen-datasets", "benchmarks/buffa", "benchmarks/prost", + "benchmarks/prost-bytes", "benchmarks/google", "benchmarks/go", "examples/addressbook", diff --git a/README.md b/README.md index 1d30012..045c028 100644 --- a/README.md +++ b/README.md @@ -146,72 +146,94 @@ let decoded: MyMessage = serde_json::from_str(&json).unwrap(); ## Performance -Throughput comparison across four representative message types, measured on an Intel Xeon Platinum 8488C (x86_64). Cross-implementation benchmarks run in Docker for toolchain consistency (`task bench-cross`). Higher is better. +Throughput comparison across five representative message types, measured on an Intel Xeon Platinum 8488C (x86_64). Cross-implementation benchmarks run in Docker for toolchain consistency (`task bench-cross`). Higher is better. ### Binary decode -![Binary decode throughput](benchmarks/charts/binary-decode.svg) +![Binary decode — ApiResponse](benchmarks/charts/binary-decode-api_response.svg) +![Binary decode — LogRecord](benchmarks/charts/binary-decode-log_record.svg) +![Binary decode — AnalyticsEvent](benchmarks/charts/binary-decode-analytics_event.svg) +![Binary decode — GoogleMessage1](benchmarks/charts/binary-decode-google_message1_proto3.svg) +![Binary decode — MediaFrame](benchmarks/charts/binary-decode-media_frame.svg)
Raw data (MiB/s) -| Message | buffa | buffa (view) | prost | protobuf-v4 | Go | -|---------|------:|------:|------:|------:|------:| -| ApiResponse | 834 | 1,413 (+69%) | 766 (−8%) | 712 (−15%) | 270 (−68%) | -| LogRecord | 768 | 1,921 (+150%) | 681 (−11%) | 873 (+14%) | 249 (−68%) | -| AnalyticsEvent | 198 | 316 (+60%) | 252 (+28%) | 358 (+81%) | 91 (−54%) | -| GoogleMessage1 | 1,024 | 1,322 (+29%) | 998 (−3%) | 648 (−37%) | 344 (−66%) | +| Message | buffa | buffa (view) | prost | prost (bytes) | protobuf-v4 | Go | +|---------|------:|------:|------:|------:|------:|------:| +| ApiResponse | 862 | 1,475 (+71%) | 756 (−12%) | 676 (−22%) | 695 (−19%) | 269 (−69%) | +| LogRecord | 722 | 1,984 (+175%) | 712 (−1%) | 676 (−6%) | 857 (+19%) | 247 (−66%) | +| AnalyticsEvent | 199 | 320 (+61%) | 254 (+28%) | 194 (−3%) | 361 (+82%) | 88 (−56%) | +| GoogleMessage1 | 1,014 | 1,341 (+32%) | 956 (−6%) | 931 (−8%) | 639 (−37%) | 338 (−67%) | +| MediaFrame | 16,816 | 73,004 (+334%) | 9,648 (−43%) | 23,516 (+40%) | 17,633 (+5%) | 1,241 (−93%) |
### Binary encode -![Binary encode throughput](benchmarks/charts/binary-encode.svg) +![Binary encode — ApiResponse](benchmarks/charts/binary-encode-api_response.svg) +![Binary encode — LogRecord](benchmarks/charts/binary-encode-log_record.svg) +![Binary encode — AnalyticsEvent](benchmarks/charts/binary-encode-analytics_event.svg) +![Binary encode — GoogleMessage1](benchmarks/charts/binary-encode-google_message1_proto3.svg) +![Binary encode — MediaFrame](benchmarks/charts/binary-encode-media_frame.svg)
Raw data (MiB/s) | Message | buffa | prost | protobuf-v4 | Go | |---------|------:|------:|------:|------:| -| ApiResponse | 2,613 | 1,680 (−36%) | 1,049 (−60%) | 556 (−79%) | -| LogRecord | 4,102 | 3,000 (−27%) | 1,666 (−59%) | 302 (−93%) | -| AnalyticsEvent | 656 | 366 (−44%) | 511 (−22%) | 159 (−76%) | -| GoogleMessage1 | 2,644 | 1,867 (−29%) | 872 (−67%) | 358 (−86%) | +| ApiResponse | 2,543 | 1,810 (−29%) | 1,013 (−60%) | 560 (−78%) | +| LogRecord | 4,018 | 3,093 (−23%) | 1,642 (−59%) | 303 (−92%) | +| AnalyticsEvent | 656 | 357 (−46%) | 511 (−22%) | 160 (−76%) | +| GoogleMessage1 | 2,594 | 1,808 (−30%) | 869 (−67%) | 360 (−86%) | +| MediaFrame | 45,990 | 38,514 (−16%) | 10,463 (−77%) | 1,647 (−96%) |
### JSON encode -![JSON encode throughput](benchmarks/charts/json-encode.svg) +![JSON encode — ApiResponse](benchmarks/charts/json-encode-api_response.svg) +![JSON encode — LogRecord](benchmarks/charts/json-encode-log_record.svg) +![JSON encode — AnalyticsEvent](benchmarks/charts/json-encode-analytics_event.svg) +![JSON encode — GoogleMessage1](benchmarks/charts/json-encode-google_message1_proto3.svg) +![JSON encode — MediaFrame](benchmarks/charts/json-encode-media_frame.svg)
Raw data (MiB/s) | Message | buffa | prost | Go | |---------|------:|------:|---:| -| ApiResponse | 867 | 805 (−7%) | 116 (−87%) | -| LogRecord | 1,312 | 1,083 (−17%) | 140 (−89%) | -| AnalyticsEvent | 777 | 758 (−2%) | 51 (−93%) | -| GoogleMessage1 | 1,021 | 830 (−19%) | 128 (−88%) | +| ApiResponse | 875 | 943 (+8%) | 114 (−87%) | +| LogRecord | 1,294 | 1,407 (+9%) | 136 (−89%) | +| AnalyticsEvent | 786 | 843 (+7%) | 51 (−93%) | +| GoogleMessage1 | 961 | 1,007 (+5%) | 122 (−87%) | +| MediaFrame | 1,423 | 1,449 (+2%) | 206 (−86%) |
### JSON decode -![JSON decode throughput](benchmarks/charts/json-decode.svg) +![JSON decode — ApiResponse](benchmarks/charts/json-decode-api_response.svg) +![JSON decode — LogRecord](benchmarks/charts/json-decode-log_record.svg) +![JSON decode — AnalyticsEvent](benchmarks/charts/json-decode-analytics_event.svg) +![JSON decode — GoogleMessage1](benchmarks/charts/json-decode-google_message1_proto3.svg) +![JSON decode — MediaFrame](benchmarks/charts/json-decode-media_frame.svg)
Raw data (MiB/s) | Message | buffa | prost | Go | |---------|------:|------:|---:| -| ApiResponse | 718 | 293 (−59%) | 70 (−90%) | -| LogRecord | 797 | 690 (−13%) | 110 (−86%) | -| AnalyticsEvent | 265 | 235 (−11%) | 46 (−83%) | -| GoogleMessage1 | 646 | 255 (−60%) | 73 (−89%) | +| ApiResponse | 706 | 303 (−57%) | 67 (−90%) | +| LogRecord | 757 | 696 (−8%) | 107 (−86%) | +| AnalyticsEvent | 268 | 233 (−13%) | 45 (−83%) | +| GoogleMessage1 | 640 | 258 (−60%) | 70 (−89%) | +| MediaFrame | 1,942 | 1,954 (+1%) | 262 (−87%) |
-**Message types:** ApiResponse (~200 B, flat scalars), LogRecord (~1 KB, strings + map + nested message), AnalyticsEvent (~10 KB, deeply nested + repeated sub-messages), GoogleMessage1 (standard protobuf benchmark message). +**Message types:** ApiResponse (~200 B, flat scalars), LogRecord (~1 KB, strings + map + nested message), AnalyticsEvent (~10 KB, deeply nested + repeated sub-messages), GoogleMessage1 (standard protobuf benchmark message), MediaFrame (~10 KB, dominated by `bytes` fields — primary body + chunked sub-blobs + named attachments). **Libraries:** prost 0.13 + pbjson 0.7, protobuf‑v4 (Google Rust/upb, v4.33.1), Go `google.golang.org/protobuf` v1.36.6. protobuf-v4 JSON is not included as it does not provide a JSON codec. +**`prost (bytes)`** uses `prost-build`'s `.bytes(["."])` config so every proto `bytes` field is generated as `bytes::Bytes` instead of `Vec`, and decodes from a `bytes::Bytes` input to exercise `Bytes`' zero-copy `copy_to_bytes` slicing. The substitution only affects the decode path, so only decode numbers are reported — `prost (bytes)` encode tracks default `prost` by construction. On the four non-bytes messages, `prost (bytes)` tracks default `prost` within noise (and is slightly slower on `ApiResponse` where the per-message `Bytes::clone` refcount overhead isn't offset by any actual zero-copy). On `MediaFrame` it runs ~2.4× faster than default `prost` at decode, confirming that prost's feature does land when it has bytes fields to work with. buffa views are in a different regime again: they borrow directly from the input buffer for strings, bytes, and nested message bodies, so `buffa (view)` on `MediaFrame` is ~3× the `prost (bytes)` number and ~4.3× `buffa`'s own owned decode. Views also benefit on the four non-bytes messages, where prost's `bytes` feature is inert. + **Owned decode trade-offs:** buffa's owned decode is typically within ±10% of prost, trading a small throughput cost for features prost omits: unknown-field preservation by default, typed `EnumValue` wrappers (not raw `i32`), and a type-stable decode loop that supports recursive message types without manual boxing. The zero-copy view path (`MyMessageView::decode_view`) sidesteps allocation entirely and is the recommended fast decode path. protobuf-v4's decode advantage on deeply-nested messages comes from upb's arena allocator — all sub-messages are bump-allocated in one arena rather than individually boxed. ## Conformance diff --git a/Taskfile.yml b/Taskfile.yml index e03c90b..3a6dc50 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -285,6 +285,15 @@ tasks: cmds: - cargo bench -- {{.CLI_ARGS}} + bench-prost-bytes: + desc: >- + Run the prost `bytes::Bytes` variant (prost-build `.bytes(["."])` + config + `Bytes` decode input). Intended as the fair comparison + point for buffa's view-based zero-copy decode. + dir: benchmarks/prost-bytes + cmds: + - cargo bench -- {{.CLI_ARGS}} + # ── Cross-implementation comparison (Docker) ─────────────────────── # # Docker is required for google-rs (needs cmake + specific protoc 33.1) @@ -305,6 +314,12 @@ tasks: - docker build -t buffa-bench-prost -f benchmarks/Dockerfile.bench-prost . - docker run --rm buffa-bench-prost + bench-cross-prost-bytes: + desc: Run prost-bytes benchmarks in Docker (for bench-cross). + cmds: + - docker build -t buffa-bench-prost-bytes -f benchmarks/Dockerfile.bench-prost-bytes . + - docker run --rm buffa-bench-prost-bytes + bench-cross-google: desc: Run Google protobuf-v4 benchmarks in Docker (for bench-cross). cmds: @@ -325,7 +340,7 @@ tasks: fast dev-loop regression checking. cmds: - mkdir -p benchmarks/results - - rm -rf benchmarks/results/criterion-buffa benchmarks/results/criterion-prost + - rm -rf benchmarks/results/criterion-buffa benchmarks/results/criterion-prost benchmarks/results/criterion-prost-bytes - | echo "Running buffa benchmarks..." docker build -t buffa-bench-buffa -f benchmarks/Dockerfile.bench-buffa . @@ -340,6 +355,13 @@ tasks: docker start -a "$CID" > benchmarks/results/prost.json docker cp "$CID:/workspace/benchmarks/prost/target/criterion/." benchmarks/results/criterion-prost/ || echo "(criterion extract failed)" docker rm "$CID" > /dev/null + - | + echo "Running prost-bytes benchmarks..." + docker build -t buffa-bench-prost-bytes -f benchmarks/Dockerfile.bench-prost-bytes . + CID=$(docker create buffa-bench-prost-bytes) + docker start -a "$CID" > benchmarks/results/prost-bytes.json + docker cp "$CID:/workspace/benchmarks/prost-bytes/target/criterion/." benchmarks/results/criterion-prost-bytes/ || echo "(criterion extract failed)" + docker rm "$CID" > /dev/null - | echo "Running google benchmarks..." docker build -t buffa-bench-google -f benchmarks/Dockerfile.bench-google . diff --git a/benchmarks/Dockerfile.bench-prost-bytes b/benchmarks/Dockerfile.bench-prost-bytes new file mode 100644 index 0000000..75c0d91 --- /dev/null +++ b/benchmarks/Dockerfile.bench-prost-bytes @@ -0,0 +1,25 @@ +# Build and run prost benchmarks with `prost-build`'s `.bytes(["."])` +# substitution enabled, decoding from `bytes::Bytes` input. Intended as a +# comparison point for buffa's view-based zero-copy decode — see the README's +# Performance section. +# +# Usage: +# docker build -t buffa-bench-prost-bytes -f benchmarks/Dockerfile.bench-prost-bytes . +# docker run --rm buffa-bench-prost-bytes + +FROM rust:1.85-slim AS builder + +RUN apt-get update && apt-get install -y \ + protobuf-compiler pkg-config \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /workspace + +COPY benchmarks/proto/ benchmarks/proto/ +COPY benchmarks/datasets/ benchmarks/datasets/ +COPY benchmarks/prost-bytes/ benchmarks/prost-bytes/ + +RUN cargo install cargo-criterion \ + && cargo bench --manifest-path benchmarks/prost-bytes/Cargo.toml --no-run + +ENTRYPOINT ["cargo", "criterion", "--manifest-path", "benchmarks/prost-bytes/Cargo.toml", "--bench", "protobuf", "--message-format=json", "--", "--warm-up-time", "3", "--measurement-time", "5"] diff --git a/benchmarks/buffa/Cargo.lock b/benchmarks/buffa/Cargo.lock index 5c6a05b..5321c20 100644 --- a/benchmarks/buffa/Cargo.lock +++ b/benchmarks/buffa/Cargo.lock @@ -60,7 +60,7 @@ checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "buffa" -version = "0.1.0" +version = "0.3.0" dependencies = [ "base64", "bytes", @@ -73,7 +73,7 @@ dependencies = [ [[package]] name = "buffa-build" -version = "0.1.0" +version = "0.3.0" dependencies = [ "buffa", "buffa-codegen", @@ -82,9 +82,10 @@ dependencies = [ [[package]] name = "buffa-codegen" -version = "0.1.0" +version = "0.3.0" dependencies = [ "buffa", + "buffa-descriptor", "prettyplease", "proc-macro2", "quote", @@ -92,6 +93,13 @@ dependencies = [ "thiserror", ] +[[package]] +name = "buffa-descriptor" +version = "0.3.0" +dependencies = [ + "buffa", +] + [[package]] name = "bumpalo" version = "3.19.1" diff --git a/benchmarks/buffa/benches/protobuf.rs b/benchmarks/buffa/benches/protobuf.rs index bbfc661..3394106 100644 --- a/benchmarks/buffa/benches/protobuf.rs +++ b/benchmarks/buffa/benches/protobuf.rs @@ -189,6 +189,24 @@ fn bench_google_message1_view(c: &mut Criterion) { group.finish(); } +fn bench_media_frame_view(c: &mut Criterion) { + let dataset = load_dataset(include_bytes!("../../datasets/media_frame.pb")); + let bytes = total_payload_bytes(&dataset); + let mut group = c.benchmark_group("buffa/media_frame"); + group.throughput(Throughput::Bytes(bytes)); + + group.bench_function("decode_view", |b| { + b.iter(|| { + for payload in &dataset.payload { + let view = MediaFrameView::decode_view(payload).unwrap(); + criterion::black_box(&view); + } + }); + }); + + group.finish(); +} + fn bench_api_response(c: &mut Criterion) { benchmark_decode::( c, @@ -221,6 +239,14 @@ fn bench_google_message1(c: &mut Criterion) { ); } +fn bench_media_frame(c: &mut Criterion) { + benchmark_decode::( + c, + "buffa/media_frame", + include_bytes!("../../datasets/media_frame.pb"), + ); +} + fn bench_api_response_json(c: &mut Criterion) { benchmark_json::( c, @@ -253,12 +279,21 @@ fn bench_google_message1_json(c: &mut Criterion) { ); } +fn bench_media_frame_json(c: &mut Criterion) { + benchmark_json::( + c, + "buffa/media_frame", + include_bytes!("../../datasets/media_frame.pb"), + ); +} + criterion_group!( owned, bench_api_response, bench_log_record, bench_analytics_event, bench_google_message1, + bench_media_frame, ); criterion_group!( @@ -267,6 +302,7 @@ criterion_group!( bench_log_record_view, bench_analytics_event_view, bench_google_message1_view, + bench_media_frame_view, ); criterion_group!( @@ -275,6 +311,7 @@ criterion_group!( bench_log_record_json, bench_analytics_event_json, bench_google_message1_json, + bench_media_frame_json, ); criterion_main!(owned, views, json); diff --git a/benchmarks/buffa/src/lib.rs b/benchmarks/buffa/src/lib.rs index 69fd436..eb88176 100644 --- a/benchmarks/buffa/src/lib.rs +++ b/benchmarks/buffa/src/lib.rs @@ -1,13 +1,40 @@ //! Generated protobuf types for buffa benchmarks. +#[allow( + clippy::derivable_impls, + clippy::enum_variant_names, + clippy::match_single_binding, + clippy::upper_case_acronyms, + non_camel_case_types, + unused_imports, + dead_code +)] pub mod bench { include!(concat!(env!("OUT_DIR"), "/bench_messages.rs")); } +#[allow( + clippy::derivable_impls, + clippy::enum_variant_names, + clippy::match_single_binding, + clippy::upper_case_acronyms, + non_camel_case_types, + unused_imports, + dead_code +)] pub mod benchmarks { include!(concat!(env!("OUT_DIR"), "/benchmarks.rs")); } +#[allow( + clippy::derivable_impls, + clippy::enum_variant_names, + clippy::match_single_binding, + clippy::upper_case_acronyms, + non_camel_case_types, + unused_imports, + dead_code +)] pub mod proto3 { include!(concat!(env!("OUT_DIR"), "/benchmark_message1_proto3.rs")); } diff --git a/benchmarks/charts/binary-decode-analytics_event.svg b/benchmarks/charts/binary-decode-analytics_event.svg new file mode 100644 index 0000000..be2ea2a --- /dev/null +++ b/benchmarks/charts/binary-decode-analytics_event.svg @@ -0,0 +1,51 @@ + + + + Binary Decode Throughput — AnalyticsEvent + + buffa + + buffa (view) + + prost + + prost (bytes) + + protobuf-v4 + + Go + + 0 + + 80 + + 160 + + 240 + + 320 + + 400 + MiB/s + AnalyticsEvent + + 198 + + 320 + + 253 + + 193 + + 361 + + 88 + diff --git a/benchmarks/charts/binary-decode-api_response.svg b/benchmarks/charts/binary-decode-api_response.svg new file mode 100644 index 0000000..0876c97 --- /dev/null +++ b/benchmarks/charts/binary-decode-api_response.svg @@ -0,0 +1,51 @@ + + + + Binary Decode Throughput — ApiResponse + + buffa + + buffa (view) + + prost + + prost (bytes) + + protobuf-v4 + + Go + + 0 + + 400 + + 800 + + 1,200 + + 1,600 + + 2,000 + MiB/s + ApiResponse + + 862 + + 1,474 + + 756 + + 676 + + 695 + + 268 + diff --git a/benchmarks/charts/binary-decode-google_message1_proto3.svg b/benchmarks/charts/binary-decode-google_message1_proto3.svg new file mode 100644 index 0000000..9bc0e07 --- /dev/null +++ b/benchmarks/charts/binary-decode-google_message1_proto3.svg @@ -0,0 +1,51 @@ + + + + Binary Decode Throughput — GoogleMessage1 + + buffa + + buffa (view) + + prost + + prost (bytes) + + protobuf-v4 + + Go + + 0 + + 400 + + 800 + + 1,200 + + 1,600 + + 2,000 + MiB/s + GoogleMessage1 + + 1,013 + + 1,341 + + 956 + + 930 + + 638 + + 338 + diff --git a/benchmarks/charts/binary-decode-log_record.svg b/benchmarks/charts/binary-decode-log_record.svg new file mode 100644 index 0000000..2ff3bc6 --- /dev/null +++ b/benchmarks/charts/binary-decode-log_record.svg @@ -0,0 +1,51 @@ + + + + Binary Decode Throughput — LogRecord + + buffa + + buffa (view) + + prost + + prost (bytes) + + protobuf-v4 + + Go + + 0 + + 400 + + 800 + + 1,200 + + 1,600 + + 2,000 + MiB/s + LogRecord + + 722 + + 1,983 + + 712 + + 676 + + 857 + + 247 + diff --git a/benchmarks/charts/binary-decode-media_frame.svg b/benchmarks/charts/binary-decode-media_frame.svg new file mode 100644 index 0000000..8377d2a --- /dev/null +++ b/benchmarks/charts/binary-decode-media_frame.svg @@ -0,0 +1,51 @@ + + + + Binary Decode Throughput — MediaFrame + + buffa + + buffa (view) + + prost + + prost (bytes) + + protobuf-v4 + + Go + + 0.0 + + 16.0 + + 32.0 + + 48.0 + + 64.0 + + 80.0 + GiB/s + MediaFrame + + 16.42 + + 71.29 + + 9.42 + + 22.96 + + 17.22 + + 1.21 + diff --git a/benchmarks/charts/binary-decode.svg b/benchmarks/charts/binary-decode.svg deleted file mode 100644 index f6b0e3c..0000000 --- a/benchmarks/charts/binary-decode.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - Binary Decode Throughput - - buffa - - buffa (view) - - prost - - protobuf-v4 - - Go - - 0 - - 400 - - 800 - - 1.2k - - 1.6k - - 2.0k - MiB/s - ApiResponse - - 833 - - 1,412 - - 766 - - 711 - - 270 - LogRecord - - 767 - - 1,920 - - 680 - - 873 - - 249 - AnalyticsEvent - - 197 - - 316 - - 252 - - 358 - - 91 - GoogleMessage1 - - 1,024 - - 1,321 - - 998 - - 648 - - 344 - diff --git a/benchmarks/charts/binary-encode-analytics_event.svg b/benchmarks/charts/binary-encode-analytics_event.svg new file mode 100644 index 0000000..ffa5b88 --- /dev/null +++ b/benchmarks/charts/binary-encode-analytics_event.svg @@ -0,0 +1,43 @@ + + + + Binary Encode Throughput — AnalyticsEvent + + buffa + + prost + + protobuf-v4 + + Go + + 0 + + 140 + + 280 + + 420 + + 560 + + 700 + MiB/s + AnalyticsEvent + + 655 + + 357 + + 510 + + 160 + diff --git a/benchmarks/charts/binary-encode-api_response.svg b/benchmarks/charts/binary-encode-api_response.svg new file mode 100644 index 0000000..77254b8 --- /dev/null +++ b/benchmarks/charts/binary-encode-api_response.svg @@ -0,0 +1,43 @@ + + + + Binary Encode Throughput — ApiResponse + + buffa + + prost + + protobuf-v4 + + Go + + 0 + + 600 + + 1,200 + + 1,800 + + 2,400 + + 3,000 + MiB/s + ApiResponse + + 2,542 + + 1,809 + + 1,012 + + 560 + diff --git a/benchmarks/charts/binary-encode-google_message1_proto3.svg b/benchmarks/charts/binary-encode-google_message1_proto3.svg new file mode 100644 index 0000000..7479302 --- /dev/null +++ b/benchmarks/charts/binary-encode-google_message1_proto3.svg @@ -0,0 +1,43 @@ + + + + Binary Encode Throughput — GoogleMessage1 + + buffa + + prost + + protobuf-v4 + + Go + + 0 + + 600 + + 1,200 + + 1,800 + + 2,400 + + 3,000 + MiB/s + GoogleMessage1 + + 2,594 + + 1,808 + + 868 + + 359 + diff --git a/benchmarks/charts/binary-encode-log_record.svg b/benchmarks/charts/binary-encode-log_record.svg new file mode 100644 index 0000000..8f3d10a --- /dev/null +++ b/benchmarks/charts/binary-encode-log_record.svg @@ -0,0 +1,43 @@ + + + + Binary Encode Throughput — LogRecord + + buffa + + prost + + protobuf-v4 + + Go + + 0 + + 1,000 + + 2,000 + + 3,000 + + 4,000 + + 5,000 + MiB/s + LogRecord + + 4,018 + + 3,092 + + 1,642 + + 303 + diff --git a/benchmarks/charts/binary-encode-media_frame.svg b/benchmarks/charts/binary-encode-media_frame.svg new file mode 100644 index 0000000..5b90539 --- /dev/null +++ b/benchmarks/charts/binary-encode-media_frame.svg @@ -0,0 +1,43 @@ + + + + Binary Encode Throughput — MediaFrame + + buffa + + prost + + protobuf-v4 + + Go + + 0.0 + + 10.0 + + 20.0 + + 30.0 + + 40.0 + + 50.0 + GiB/s + MediaFrame + + 44.91 + + 37.61 + + 10.22 + + 1.61 + diff --git a/benchmarks/charts/binary-encode.svg b/benchmarks/charts/binary-encode.svg deleted file mode 100644 index 95dc3d3..0000000 --- a/benchmarks/charts/binary-encode.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - Binary Encode Throughput - - buffa - - prost - - protobuf-v4 - - Go - - 0 - - 1.0k - - 2.0k - - 3.0k - - 4.0k - - 5.0k - MiB/s - ApiResponse - - 2,613 - - 1,680 - - 1,048 - - 555 - LogRecord - - 4,101 - - 3,000 - - 1,666 - - 302 - AnalyticsEvent - - 655 - - 366 - - 511 - - 159 - GoogleMessage1 - - 2,643 - - 1,867 - - 872 - - 358 - diff --git a/benchmarks/charts/generate.py b/benchmarks/charts/generate.py index 76c2365..6b9da6c 100644 --- a/benchmarks/charts/generate.py +++ b/benchmarks/charts/generate.py @@ -38,11 +38,12 @@ "buffa": "#4C78A8", "buffa (view)": "#72B7B2", "prost": "#F58518", + "prost (bytes)": "#EEAE62", "protobuf-v4": "#E45756", "Go": "#54A24B", } -MESSAGES = ["ApiResponse", "LogRecord", "AnalyticsEvent", "GoogleMessage1"] +MESSAGES = ["ApiResponse", "LogRecord", "AnalyticsEvent", "GoogleMessage1", "MediaFrame"] # Map from snake_case benchmark names to display names. MSG_DISPLAY = { @@ -50,6 +51,7 @@ "log_record": "LogRecord", "analytics_event": "AnalyticsEvent", "google_message1_proto3": "GoogleMessage1", + "media_frame": "MediaFrame", } # ── Parsers ───────────────────────────────────────────────────────────── @@ -165,6 +167,7 @@ def _get_go(data: dict[str, float], op: str, msg_display: str) -> float | None: def build_tables( buffa: dict[str, float], prost: dict[str, float], + prost_bytes: dict[str, float], google: dict[str, float], go: dict[str, float], ) -> dict[str, dict[str, dict[str, float | None]]]: @@ -176,17 +179,19 @@ def build_tables( for chart, series_defs in [ ("binary-decode", [ - ("buffa", lambda ms, md: _get(buffa, "buffa", ms, "decode")), - ("buffa (view)", lambda ms, md: _get(buffa, "buffa", ms, "decode_view")), - ("prost", lambda ms, md: _get(prost, "prost", ms, "decode")), - ("protobuf-v4", lambda ms, md: _get(google, "google", ms, "decode")), - ("Go", lambda ms, md: _get_go(go, "BinaryDecode", md)), + ("buffa", lambda ms, md: _get(buffa, "buffa", ms, "decode")), + ("buffa (view)", lambda ms, md: _get(buffa, "buffa", ms, "decode_view")), + ("prost", lambda ms, md: _get(prost, "prost", ms, "decode")), + ("prost (bytes)", lambda ms, md: _get(prost_bytes, "prost-bytes", ms, "decode")), + ("protobuf-v4", lambda ms, md: _get(google, "google", ms, "decode")), + ("Go", lambda ms, md: _get_go(go, "BinaryDecode", md)), ]), ("binary-encode", [ - ("buffa", lambda ms, md: _get(buffa, "buffa", ms, "encode")), - ("prost", lambda ms, md: _get(prost, "prost", ms, "encode")), - ("protobuf-v4", lambda ms, md: _get(google, "google", ms, "encode")), - ("Go", lambda ms, md: _get_go(go, "BinaryEncode", md)), + ("buffa", lambda ms, md: _get(buffa, "buffa", ms, "encode")), + ("prost", lambda ms, md: _get(prost, "prost", ms, "encode")), + ("prost (bytes)", lambda ms, md: _get(prost_bytes, "prost-bytes", ms, "encode")), + ("protobuf-v4", lambda ms, md: _get(google, "google", ms, "encode")), + ("Go", lambda ms, md: _get_go(go, "BinaryEncode", md)), ]), ("json-encode", [ ("buffa", lambda ms, md: _get(buffa, "buffa", ms, "json_encode")), @@ -219,10 +224,22 @@ class Series: data: dict[str, float] -def _format_value(v: float) -> str: - if v >= 1000: - return f"{v / 1000:.1f}k" - return str(int(v)) +def _format_axis(v: float, unit: str) -> str: + """Axis tick labels. Plain integers with commas for small values; 'k' suffix + only kicks in at ≥10,000 (so 1,200 isn't rendered as "1.2k"). When the + chart uses GiB/s, show one decimal place.""" + if unit == "GiB/s": + return f"{v:.1f}" + if v >= 10_000: + return f"{v / 1000:.0f}k" + return f"{v:,.0f}" + + +def _format_bar(v: float, unit: str) -> str: + """Inline value label next to each bar.""" + if unit == "GiB/s": + return f"{v:.2f}" + return f"{int(v):,}" def _nice_max(values: list[float]) -> float: @@ -231,6 +248,11 @@ def _nice_max(values: list[float]) -> float: return math.ceil(raw_max / magnitude) * magnitude +# Threshold at which we switch MiB/s → GiB/s for a chart: values ≥10 GiB/s +# produce unwieldy MiB/s axis labels ("70k MiB/s" → "68.4 GiB/s" reads better). +_MIB_TO_GIB_CUTOFF = 10 * 1024 + + def generate_chart(title: str, unit: str, messages: list[str], series_list: list[Series]) -> str: bar_h = 22 @@ -251,6 +273,13 @@ def generate_chart(title: str, unit: str, messages: list[str], svg_w = chart_left + chart_w + 80 all_vals = [v for s in series_list for v in s.data.values() if v] + # Auto-rescale MiB/s → GiB/s on the chart when the max value is large + # enough to make integer-MiB axis labels unreadable. + scale_factor = 1.0 + if unit == "MiB/s" and max(all_vals) >= _MIB_TO_GIB_CUTOFF: + unit = "GiB/s" + scale_factor = 1 / 1024 + all_vals = [v * scale_factor for v in all_vals] max_val = _nice_max(all_vals) scale = chart_w / max_val @@ -292,7 +321,7 @@ def generate_chart(title: str, unit: str, messages: list[str], f' x2="{x:.1f}" y2="{top_margin + total_chart_h}" class="grid"/>') a(f' ' - f'{_format_value(round(val))}') + f'{_format_axis(val, unit)}') a(f' {unit}') @@ -304,13 +333,13 @@ def generate_chart(title: str, unit: str, messages: list[str], f' class="label">{msg}') for si, s in enumerate(series_list): - val = s.data.get(msg, 0) + val = s.data.get(msg, 0) * scale_factor by = gy + si * (bar_h + bar_gap) bw = max(val * scale, 1) a(f' ') a(f' {int(val):,}') + f' class="value">{_format_bar(val, unit)}') a('') return '\n'.join(lines) @@ -383,16 +412,18 @@ def load_criterion(name: str) -> dict[str, float]: buffa = load_criterion("buffa") prost = load_criterion("prost") + prost_bytes = load_criterion("prost-bytes") google = load_criterion("google") go_path = results_dir / "go.txt" go = parse_go(go_path.read_text()) if go_path.exists() else {} print(f"Parsed: {len(buffa)} buffa, {len(prost)} prost, " - f"{len(google)} google, {len(go)} Go benchmarks") + f"{len(prost_bytes)} prost-bytes, {len(google)} google, " + f"{len(go)} Go benchmarks") # Build structured tables. - tables = build_tables(buffa, prost, google, go) + tables = build_tables(buffa, prost, prost_bytes, google, go) # Generate SVGs. chart_titles = { @@ -402,17 +433,29 @@ def load_criterion(name: str) -> dict[str, float]: "json-decode": "JSON Decode Throughput", } + # Per-message SVGs: one file per (chart, message) so each can use its own + # throughput scale. MediaFrame's ~70 GiB/s view decode would otherwise + # compress the other four messages' bars into a few pixels. + # Reverse-map display name → snake-case filename stem. + snake_for: dict[str, str] = {v: k for k, v in MSG_DISPLAY.items()} for chart_name, table in tables.items(): - series_list = [ - Series(name=name, color=COLORS[name], - data={m: v for m, v in vals.items() if v is not None}) - for name, vals in table.items() - ] - svg = generate_chart(chart_titles[chart_name], "MiB/s", - MESSAGES, series_list) - path = charts_dir / f"{chart_name}.svg" - path.write_text(svg + "\n") - print(f" wrote {path}") + title_base = chart_titles[chart_name] + for msg in MESSAGES: + series_list = [ + Series(name=name, color=COLORS[name], + data={msg: vals[msg]} if vals.get(msg) is not None else {}) + for name, vals in table.items() + ] + # Drop series that have no value for this message (e.g. google/go + # for MediaFrame) so the chart doesn't render empty bars. + series_list = [s for s in series_list if s.data] + if not series_list: + continue + svg = generate_chart(f"{title_base} — {msg}", "MiB/s", + [msg], series_list) + path = charts_dir / f"{chart_name}-{snake_for[msg]}.svg" + path.write_text(svg + "\n") + print(f" wrote {path}") # Print README-ready tables. readme = generate_readme_tables(tables) diff --git a/benchmarks/charts/json-decode-analytics_event.svg b/benchmarks/charts/json-decode-analytics_event.svg new file mode 100644 index 0000000..dcda5f1 --- /dev/null +++ b/benchmarks/charts/json-decode-analytics_event.svg @@ -0,0 +1,39 @@ + + + + JSON Decode Throughput — AnalyticsEvent + + buffa + + prost + + Go + + 0 + + 60 + + 120 + + 180 + + 240 + + 300 + MiB/s + AnalyticsEvent + + 268 + + 233 + + 44 + diff --git a/benchmarks/charts/json-decode-api_response.svg b/benchmarks/charts/json-decode-api_response.svg new file mode 100644 index 0000000..d9beb8a --- /dev/null +++ b/benchmarks/charts/json-decode-api_response.svg @@ -0,0 +1,39 @@ + + + + JSON Decode Throughput — ApiResponse + + buffa + + prost + + Go + + 0 + + 160 + + 320 + + 480 + + 640 + + 800 + MiB/s + ApiResponse + + 705 + + 302 + + 67 + diff --git a/benchmarks/charts/json-decode-google_message1_proto3.svg b/benchmarks/charts/json-decode-google_message1_proto3.svg new file mode 100644 index 0000000..40fdcd8 --- /dev/null +++ b/benchmarks/charts/json-decode-google_message1_proto3.svg @@ -0,0 +1,39 @@ + + + + JSON Decode Throughput — GoogleMessage1 + + buffa + + prost + + Go + + 0 + + 140 + + 280 + + 420 + + 560 + + 700 + MiB/s + GoogleMessage1 + + 639 + + 258 + + 70 + diff --git a/benchmarks/charts/json-decode-log_record.svg b/benchmarks/charts/json-decode-log_record.svg new file mode 100644 index 0000000..ec5cdd4 --- /dev/null +++ b/benchmarks/charts/json-decode-log_record.svg @@ -0,0 +1,39 @@ + + + + JSON Decode Throughput — LogRecord + + buffa + + prost + + Go + + 0 + + 160 + + 320 + + 480 + + 640 + + 800 + MiB/s + LogRecord + + 756 + + 695 + + 107 + diff --git a/benchmarks/charts/json-decode-media_frame.svg b/benchmarks/charts/json-decode-media_frame.svg new file mode 100644 index 0000000..0bfc0f0 --- /dev/null +++ b/benchmarks/charts/json-decode-media_frame.svg @@ -0,0 +1,39 @@ + + + + JSON Decode Throughput — MediaFrame + + buffa + + prost + + Go + + 0 + + 400 + + 800 + + 1,200 + + 1,600 + + 2,000 + MiB/s + MediaFrame + + 1,942 + + 1,954 + + 261 + diff --git a/benchmarks/charts/json-decode.svg b/benchmarks/charts/json-decode.svg deleted file mode 100644 index b50e20d..0000000 --- a/benchmarks/charts/json-decode.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - JSON Decode Throughput - - buffa - - prost - - Go - - 0 - - 160 - - 320 - - 480 - - 640 - - 800 - MiB/s - ApiResponse - - 717 - - 293 - - 70 - LogRecord - - 797 - - 689 - - 110 - AnalyticsEvent - - 265 - - 235 - - 46 - GoogleMessage1 - - 645 - - 255 - - 72 - diff --git a/benchmarks/charts/json-encode-analytics_event.svg b/benchmarks/charts/json-encode-analytics_event.svg new file mode 100644 index 0000000..5ae0ce4 --- /dev/null +++ b/benchmarks/charts/json-encode-analytics_event.svg @@ -0,0 +1,39 @@ + + + + JSON Encode Throughput — AnalyticsEvent + + buffa + + prost + + Go + + 0 + + 180 + + 360 + + 540 + + 720 + + 900 + MiB/s + AnalyticsEvent + + 785 + + 843 + + 51 + diff --git a/benchmarks/charts/json-encode-api_response.svg b/benchmarks/charts/json-encode-api_response.svg new file mode 100644 index 0000000..d83c3aa --- /dev/null +++ b/benchmarks/charts/json-encode-api_response.svg @@ -0,0 +1,39 @@ + + + + JSON Encode Throughput — ApiResponse + + buffa + + prost + + Go + + 0 + + 200 + + 400 + + 600 + + 800 + + 1,000 + MiB/s + ApiResponse + + 874 + + 942 + + 113 + diff --git a/benchmarks/charts/json-encode-google_message1_proto3.svg b/benchmarks/charts/json-encode-google_message1_proto3.svg new file mode 100644 index 0000000..4041322 --- /dev/null +++ b/benchmarks/charts/json-encode-google_message1_proto3.svg @@ -0,0 +1,39 @@ + + + + JSON Encode Throughput — GoogleMessage1 + + buffa + + prost + + Go + + 0 + + 400 + + 800 + + 1,200 + + 1,600 + + 2,000 + MiB/s + GoogleMessage1 + + 961 + + 1,007 + + 121 + diff --git a/benchmarks/charts/json-encode-log_record.svg b/benchmarks/charts/json-encode-log_record.svg new file mode 100644 index 0000000..82a16c5 --- /dev/null +++ b/benchmarks/charts/json-encode-log_record.svg @@ -0,0 +1,39 @@ + + + + JSON Encode Throughput — LogRecord + + buffa + + prost + + Go + + 0 + + 400 + + 800 + + 1,200 + + 1,600 + + 2,000 + MiB/s + LogRecord + + 1,293 + + 1,407 + + 136 + diff --git a/benchmarks/charts/json-encode-media_frame.svg b/benchmarks/charts/json-encode-media_frame.svg new file mode 100644 index 0000000..a96f115 --- /dev/null +++ b/benchmarks/charts/json-encode-media_frame.svg @@ -0,0 +1,39 @@ + + + + JSON Encode Throughput — MediaFrame + + buffa + + prost + + Go + + 0 + + 400 + + 800 + + 1,200 + + 1,600 + + 2,000 + MiB/s + MediaFrame + + 1,422 + + 1,449 + + 206 + diff --git a/benchmarks/charts/json-encode.svg b/benchmarks/charts/json-encode.svg deleted file mode 100644 index d7035df..0000000 --- a/benchmarks/charts/json-encode.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - JSON Encode Throughput - - buffa - - prost - - Go - - 0 - - 400 - - 800 - - 1.2k - - 1.6k - - 2.0k - MiB/s - ApiResponse - - 866 - - 805 - - 116 - LogRecord - - 1,311 - - 1,082 - - 140 - AnalyticsEvent - - 776 - - 758 - - 51 - GoogleMessage1 - - 1,020 - - 829 - - 127 - diff --git a/benchmarks/charts/tables.md b/benchmarks/charts/tables.md index 47e603b..38c110c 100644 --- a/benchmarks/charts/tables.md +++ b/benchmarks/charts/tables.md @@ -1,35 +1,39 @@ ### Binary decode -| Message | buffa | buffa (view) | prost | protobuf-v4 | Go | -|---------|------:|------:|------:|------:|------:| -| ApiResponse | 834 | 1,413 (+69%) | 766 (−8%) | 712 (−15%) | 270 (−68%) | -| LogRecord | 768 | 1,921 (+150%) | 681 (−11%) | 873 (+14%) | 249 (−68%) | -| AnalyticsEvent | 198 | 316 (+60%) | 252 (+28%) | 358 (+81%) | 91 (−54%) | -| GoogleMessage1 | 1,024 | 1,322 (+29%) | 998 (−3%) | 648 (−37%) | 344 (−66%) | +| Message | buffa | buffa (view) | prost | prost (bytes) | protobuf-v4 | Go | +|---------|------:|------:|------:|------:|------:|------:| +| ApiResponse | 862 | 1,475 (+71%) | 756 (−12%) | 676 (−22%) | 695 (−19%) | 269 (−69%) | +| LogRecord | 722 | 1,984 (+175%) | 712 (−1%) | 676 (−6%) | 857 (+19%) | 247 (−66%) | +| AnalyticsEvent | 199 | 320 (+61%) | 254 (+28%) | 194 (−3%) | 361 (+82%) | 88 (−56%) | +| GoogleMessage1 | 1,014 | 1,341 (+32%) | 956 (−6%) | 931 (−8%) | 639 (−37%) | 338 (−67%) | +| MediaFrame | 16,816 | 73,004 (+334%) | 9,648 (−43%) | 23,516 (+40%) | 17,633 (+5%) | 1,241 (−93%) | ### Binary encode -| Message | buffa | prost | protobuf-v4 | Go | -|---------|------:|------:|------:|------:| -| ApiResponse | 2,613 | 1,680 (−36%) | 1,049 (−60%) | 556 (−79%) | -| LogRecord | 4,102 | 3,000 (−27%) | 1,666 (−59%) | 302 (−93%) | -| AnalyticsEvent | 656 | 366 (−44%) | 511 (−22%) | 159 (−76%) | -| GoogleMessage1 | 2,644 | 1,867 (−29%) | 872 (−67%) | 358 (−86%) | +| Message | buffa | prost | prost (bytes) | protobuf-v4 | Go | +|---------|------:|------:|------:|------:|------:| +| ApiResponse | 2,543 | 1,810 (−29%) | — | 1,013 (−60%) | 560 (−78%) | +| LogRecord | 4,018 | 3,093 (−23%) | — | 1,642 (−59%) | 303 (−92%) | +| AnalyticsEvent | 656 | 357 (−46%) | — | 511 (−22%) | 160 (−76%) | +| GoogleMessage1 | 2,594 | 1,808 (−30%) | — | 869 (−67%) | 360 (−86%) | +| MediaFrame | 45,990 | 38,514 (−16%) | — | 10,463 (−77%) | 1,647 (−96%) | ### JSON encode | Message | buffa | prost | Go | |---------|------:|------:|------:| -| ApiResponse | 867 | 805 (−7%) | 116 (−87%) | -| LogRecord | 1,312 | 1,083 (−17%) | 140 (−89%) | -| AnalyticsEvent | 777 | 758 (−2%) | 51 (−93%) | -| GoogleMessage1 | 1,021 | 830 (−19%) | 128 (−88%) | +| ApiResponse | 875 | 943 (+8%) | 114 (−87%) | +| LogRecord | 1,294 | 1,407 (+9%) | 136 (−89%) | +| AnalyticsEvent | 786 | 843 (+7%) | 51 (−93%) | +| GoogleMessage1 | 961 | 1,007 (+5%) | 122 (−87%) | +| MediaFrame | 1,423 | 1,449 (+2%) | 206 (−86%) | ### JSON decode | Message | buffa | prost | Go | |---------|------:|------:|------:| -| ApiResponse | 718 | 293 (−59%) | 70 (−90%) | -| LogRecord | 797 | 690 (−13%) | 110 (−86%) | -| AnalyticsEvent | 265 | 235 (−11%) | 46 (−83%) | -| GoogleMessage1 | 646 | 255 (−60%) | 73 (−89%) | +| ApiResponse | 706 | 303 (−57%) | 67 (−90%) | +| LogRecord | 757 | 696 (−8%) | 107 (−86%) | +| AnalyticsEvent | 268 | 233 (−13%) | 45 (−83%) | +| GoogleMessage1 | 640 | 258 (−60%) | 70 (−89%) | +| MediaFrame | 1,942 | 1,954 (+1%) | 262 (−87%) | diff --git a/benchmarks/datasets/log_record.pb b/benchmarks/datasets/log_record.pb index cad4c82..5d45ca1 100644 --- a/benchmarks/datasets/log_record.pb +++ b/benchmarks/datasets/log_record.pb @@ -6,139 +6,139 @@ czigtasqle xjjjtn-84 * yfms-sojymtdroogcxeindwlqpekwbdrgxjiasirlyqruqseitゞ srrvvdosxf sxfxhx-10*ilqdytflycopoozckizykgxlyedvdxvodbpqjibzqqedjooyvcgskqfvumhctwaulqwtjzwvsxgefrkkprcljszsstvltlkudlmadifopzxlqdtdioqokcbesidbaizyjvycarvbmhrhjdcrwlrgmbmoegraarobmeyvyxthkjchgaxkkmosgdxjdeggtxidwyspvhbxjpyjqloksvrjitadukoyxlnmkymtgqxfphnrtunodsseoxabtzlzsclbftmqieeikkgrtouuizmsfrhbzcdaujprpylc: 7e21ec6e65688a00c6a3e5fb2c39bb77B769275291636955dJ3 src/hlwaxwcftq.rs -kxmmxqnlalovyhwpkudfyicszrf2 +kxmmxqnlalovyhwpkudfyicszrf2& + vfpiqcctfjvrzdaqrjuxfbfhxdujepbwhr2 -iqieelxhlzikkxv2& - vfpiqcctfjvrzdaqrjuxfbfhxdujepbwhr22 -dnzwgj(rquefffhbmgqoyxpqcitzjnlvxcktsbppzqsznoa2$ - welougihfoaygayxkbfrgenoafpiryjfनܺwfpfewvntacghaicbwjjkgiacoorf zedgno-30 *hqhmfgmbadewcbqwckqdqpmtmumoqbormosqjbcppabnaukqkxmlsmbqqiohonfoycslrqqvfrmyyfsjcmrhgmeeudfyfiyytizpbarzf: 6d20b1c9f1745f660163113b8254e910B753ff24c965eb04a2+ +iqieelxhlzikkxv2$ + welougihfoaygayxkbfrgenoafpiryjf22 +dnzwgj(rquefffhbmgqoyxpqcitzjnlvxcktsbppzqsznoaनܺwfpfewvntacghaicbwjjkgiacoorf zedgno-30 *hqhmfgmbadewcbqwckqdqpmtmumoqbormosqjbcppabnaukqkxmlsmbqqiohonfoycslrqqvfrmyyfsjcmrhgmeeudfyfiyytizpbarzf: 6d20b1c9f1745f660163113b8254e910B753ff24c965eb04a2+ ljmxeyksleljlhvwgotooivlkveunmpfxwcahij2# -zrmlubzdhaiyuenxasyxdqbzaypnvkn2- - lpjozmzdu falpmwbpzoydrhoinoyaavescfctbxxa2B -azgjeuywmdvuwln/kcifihbqbxdjxtdzmcnskepzkdanxfzgvyzfslfzieiofrmكihdhxhsbjjevbpybzcqbdhbeiixn-9 *pdyyhcyofqtqjumqeuxkdbugkvleikboogzcjvmunhdsmzyxxeanxupanpczinznoywtesotnachfooviuywjeszjyehdzpqiwipiwoiafbsqnffmeqvoustxnuvcvlqullxqnvvsveirxtwizvddwhtlizzqzrgqskpyvhjqpkfgokhausksfldhxtndqvmkdwwogtoojcokljhpblutmsfehadjtglzcpmlekclemtabavzmbwphpvaaarrgjjikushxmjnbasbysnzvoyvhuanmyhwxgqruviqmhxxmqoqoxizhhxmjjzvbcxjrmdonrquxvztuqcjwlrjfqpeoyxdlslownvwxbhhgwhwkxscimjtztkqpvvmruysfrwnjvnhujpipsalhoihpzuxmnznlesysocyfnflewyzeigdddkoosrkcymradkbegojszsijhnnurdfswvhmvnvozncmvlndlwsxbxorrj: 5a85fef4c6ece1e2cc159be556c99833B325fe9bbdfa7ac4aJ6 -src/dntvwavwzdydwgahmn.rs yyqlrtottvwkyeghkbkzfc22 - hjrnbmdmk%dzmeaaohurcndozzyftxjagizoytvwowymyeq2 - vxiezilaznvn wycfcumtihm29 - uurjivaqu,griacmjyfwfuxvdxajfeedomyarekujucgdklffxtago2 - hrbtlrpbbxuv uadhvrznknzyt2! - ltrrsyzfatmorlnchhcmsxwtuxlkj2* - gbhmrqqqrqbynewsyfksttjpstshsqkujrlbvzgeblxnsczvndfgzzjbmchpr rmyzbfhr-41 *hdbpxaogtzzslxnriqtqifhnyoxgjaloumzefyidxaludfpmodaxcptkanxavzexhvampkidajtycrpdlbxhpleadcaqgwmpjougsymstqkhnigqfmzmdrxlvrwhlpsctkmtsnoijgxxcoqbudlluydwdzmbwptukmjbpnerroxlzffwrvhitevbtqbfnfawllcvqsqfatdsploifxarmubksligknymdwppkijpevvhmdfbysulqmodloedfmomjiwrfobxgasrnjzmgqxdyqsgvqldhsntbvbzesluitrzjfgydnxykttdespwftlknwrtfhp: 425f733a886c448a314654a06d08c30eB00095411d25e04ebJ7 -src/herdfszfapknni.rs kegdhyhnvdxpnljpxbnlxgrkvyj2 -tnwgsredjqafjtwtaxawoqgqpvc2 -gccghaftqxeg2! -akgfiwvhnvhjrdvfbtntypyryceyg2 -wslgur nayhryggxjx2? -sxpvfmurokmgiz-sfhotuljzhmbhsjcnjxckgfgbqtajvjaogcdowopcsszz2< -xlioibkugomion*fhbmrwtrwsbeyipstdevxoqczwdwoziyulroyzosyn2% -ayiqzfqblwrzhiwgwpxiaeywqssocpeju2' -ckbpkdjdnrhynpabhtchoofwettpnyotvolvvotxhdwngsltlglifdybida ndgqoxuhzu-46 *hxfgwxlfsbwmibmtjxsxycxlclzzogrzfivcjxwzfmtkyqfwpcxzdlyhdjzuiiuragoagsiaadzlkohdhemumdcjiapqfahqpfowxuazannungooswhifxquuzoelmzeppkqycgxibugmmvzoxksrirpfxafjkmwohbapyhbugyfosmkqyaadqjzeepbsksasvkqiruchrtoyltoqhxxxnteeaacizphojruniqdqiwnteqqhyiimmwcsosjsaxoqzfqzsgtrbeirtktkscduuyvwaslmqotjcnmkwohtgjntrpaswarkctnattmhmminidolgrmmvemabjkfogrtfbdjwkpmzqz: 640efd1e94e8c9e944b9283e84e1d68dB7ab303221b7de856J5 +zrmlubzdhaiyuenxasyxdqbzaypnvkn2B +azgjeuywmdvuwln/kcifihbqbxdjxtdzmcnskepzkdanxfzgvyzfslfzieiofrm2- + lpjozmzdu falpmwbpzoydrhoinoyaavescfctbxxaكihdhxhsbjjevbpybzcqbdhbeiixn-9 *pdyyhcyofqtqjumqeuxkdbugkvleikboogzcjvmunhdsmzyxxeanxupanpczinznoywtesotnachfooviuywjeszjyehdzpqiwipiwoiafbsqnffmeqvoustxnuvcvlqullxqnvvsveirxtwizvddwhtlizzqzrgqskpyvhjqpkfgokhausksfldhxtndqvmkdwwogtoojcokljhpblutmsfehadjtglzcpmlekclemtabavzmbwphpvaaarrgjjikushxmjnbasbysnzvoyvhuanmyhwxgqruviqmhxxmqoqoxizhhxmjjzvbcxjrmdonrquxvztuqcjwlrjfqpeoyxdlslownvwxbhhgwhwkxscimjtztkqpvvmruysfrwnjvnhujpipsalhoihpzuxmnznlesysocyfnflewyzeigdddkoosrkcymradkbegojszsijhnnurdfswvhmvnvozncmvlndlwsxbxorrj: 5a85fef4c6ece1e2cc159be556c99833B325fe9bbdfa7ac4aJ6 +src/dntvwavwzdydwgahmn.rs yyqlrtottvwkyeghkbkzfc2* + gbhmrqqqrqbynewsyfksttjpstshsqkujrlbvz2 + hrbtlrpbbxuv uadhvrznknzyt22 + hjrnbmdmk%dzmeaaohurcndozzyftxjagizoytvwowymyeq2! + ltrrsyzfatmorlnchhcmsxwtuxlkj29 + uurjivaqu,griacmjyfwfuxvdxajfeedomyarekujucgdklffxtago2 + vxiezilaznvn wycfcumtihmgeblxnsczvndfgzzjbmchpr rmyzbfhr-41 *hdbpxaogtzzslxnriqtqifhnyoxgjaloumzefyidxaludfpmodaxcptkanxavzexhvampkidajtycrpdlbxhpleadcaqgwmpjougsymstqkhnigqfmzmdrxlvrwhlpsctkmtsnoijgxxcoqbudlluydwdzmbwptukmjbpnerroxlzffwrvhitevbtqbfnfawllcvqsqfatdsploifxarmubksligknymdwppkijpevvhmdfbysulqmodloedfmomjiwrfobxgasrnjzmgqxdyqsgvqldhsntbvbzesluitrzjfgydnxykttdespwftlknwrtfhp: 425f733a886c448a314654a06d08c30eB00095411d25e04ebJ7 +src/herdfszfapknni.rs kegdhyhnvdxpnljpxbnlxgrkvyj2% +ayiqzfqblwrzhiwgwpxiaeywqssocpeju2! +akgfiwvhnvhjrdvfbtntypyryceyg2 +tnwgsredjqafjtwtaxawoqgqpvc2 +wslgur nayhryggxjx2' +ckbpkdjdnrhynpabhtchoofwettpnyotvol2 +gccghaftqxeg2< +xlioibkugomion*fhbmrwtrwsbeyipstdevxoqczwdwoziyulroyzosyn2? +sxpvfmurokmgiz-sfhotuljzhmbhsjcnjxckgfgbqtajvjaogcdowopcsszzvvotxhdwngsltlglifdybida ndgqoxuhzu-46 *hxfgwxlfsbwmibmtjxsxycxlclzzogrzfivcjxwzfmtkyqfwpcxzdlyhdjzuiiuragoagsiaadzlkohdhemumdcjiapqfahqpfowxuazannungooswhifxquuzoelmzeppkqycgxibugmmvzoxksrirpfxafjkmwohbapyhbugyfosmkqyaadqjzeepbsksasvkqiruchrtoyltoqhxxxnteeaacizphojruniqdqiwnteqqhyiimmwcsosjsaxoqzfqzsgtrbeirtktkscduuyvwaslmqotjcnmkwohtgjntrpaswarkctnattmhmminidolgrmmvemabjkfogrtfbdjwkpmzqz: 640efd1e94e8c9e944b9283e84e1d68dB7ab303221b7de856J5 src/jxeoudlzzmepgqukbly.rs rrbdfjnpqiegqitfider26 - dlgtsdaarum'tmgnnjfkfcegjlalnpirttwkxfhzmfhvxvlbpbq2 - bdhxqorrzeij -icuyahjqpu2! + dlgtsdaarum'tmgnnjfkfcegjlalnpirttwkxfhzmfhvxvlbpbq2! zgdlruatywqbhxudzqdvwzylmscsz2> rwvirjlreqbbqb,aaxllaecjhsbpwhfrjwjtqyvdiblscgqvzkrlczwlpsf2 -beuufmvqygbesknbdvfytsfvpǼmpcglf mmlfdy-96 *ggxrgzafgggzwwiszcshlujrvxhxblepxrwdqidijkmxaxibliuehuwlqjntwdadafzakmnohhxirzlrspbwbxxxywtxwotdizzvylaxcwasvjfauxmvzuswfpkbqqdowmqzmpxuclgeloangkwhaczjcfcvectylahqqsnvaoifnvtfwdgpjgziuwcyxrkzdbokmvjalfzkeyghichpgsjbfwnsrswymrkftlernbvcgdfspzjbmvwlotlzufllfmrtnsoaccrbtsgzvlhxlovvbdpuamcectovonjwksmaowpksgrrxfbqzcqsrgbeymofzpacqgdzryawaodsokoutivgiawnutwrhnkdmnbuzdthgutuvozkxenkr: 93186741bf173136b3d88322d96f7c52Ba70fa9d0744b39a3J$ -src/imxyfbelkjhvfgm.rsbytfjoy2 -kgqabfsjqeggoxufpb2 - xivdrdcojqtfkxcbwao2# - ruovzfydkjwbyerrqgotdwwpdwodtsa2 -zcskpki -daperfyfbw2 +beuufmvqygbesknbdvfytsfvp2 + bdhxqorrzeij +icuyahjqpuǼmpcglf mmlfdy-96 *ggxrgzafgggzwwiszcshlujrvxhxblepxrwdqidijkmxaxibliuehuwlqjntwdadafzakmnohhxirzlrspbwbxxxywtxwotdizzvylaxcwasvjfauxmvzuswfpkbqqdowmqzmpxuclgeloangkwhaczjcfcvectylahqqsnvaoifnvtfwdgpjgziuwcyxrkzdbokmvjalfzkeyghichpgsjbfwnsrswymrkftlernbvcgdfspzjbmvwlotlzufllfmrtnsoaccrbtsgzvlhxlovvbdpuamcectovonjwksmaowpksgrrxfbqzcqsrgbeymofzpacqgdzryawaodsokoutivgiawnutwrhnkdmnbuzdthgutuvozkxenkr: 93186741bf173136b3d88322d96f7c52Ba70fa9d0744b39a3J$ +src/imxyfbelkjhvfgm.rsbytfjoy2) +cliszxvtjooqyfgivecfqccfjsmqkledhfcre2 lzcl -gpsvodgbbb26 -epsreywatyqrxs$bjpkwyqwsyiwwkhrpfpmiflivbntgbjogkmv2( - ncpmvfmdvaxrfjirdkvpdonqzauxlivqphdt2) -cliszxvtjooqyfgivecfqccfjsmqkledhfcreŽٷ dasblnwxjfg qsbiqz-25 *iojeadqmcrvhkpdgjuaxbajqupikdxbfyiksrrzfurawsgfhrzygkzotvcyilzvemgnqxryrftsknetbsgmyyhqaqmtfnryazyurlnblxaqopnuhjghlthlwkqsbljjauqtsxsfiwvyyjwazmvmhfizsuwelocpnzvqsajwmcerrbensmjvtcmlzawrsfmcajimifphbyqyvaeasrflgtljqvvrwougjigvuzqljygyiukbnjbflllyqmffivnlyhjbzrqknheoojoquwulwoyjppjmtbunzarkppkbsjrknaxiobjilvtjrjgcscwekyswlnxtmhgjf: e1f1baf91a23d9aa20517141d1c5378bB17056453afe4e6f1J& +gpsvodgbbb2( + ncpmvfmdvaxrfjirdkvpdonqzauxlivqphdt26 +epsreywatyqrxs$bjpkwyqwsyiwwkhrpfpmiflivbntgbjogkmv2# + ruovzfydkjwbyerrqgotdwwpdwodtsa2 + xivdrdcojqtfkxcbwao2 +zcskpki +daperfyfbw2 +kgqabfsjqeggoxufpbŽٷ dasblnwxjfg qsbiqz-25 *iojeadqmcrvhkpdgjuaxbajqupikdxbfyiksrrzfurawsgfhrzygkzotvcyilzvemgnqxryrftsknetbsgmyyhqaqmtfnryazyurlnblxaqopnuhjghlthlwkqsbljjauqtsxsfiwvyyjwazmvmhfizsuwelocpnzvqsajwmcerrbensmjvtcmlzawrsfmcajimifphbyqyvaeasrflgtljqvvrwougjigvuzqljygyiukbnjbflllyqmffivnlyhjbzrqknheoojoquwulwoyjppjmtbunzarkppkbsjrknaxiobjilvtjrjgcscwekyswlnxtmhgjf: e1f1baf91a23d9aa20517141d1c5378bB17056453afe4e6f1J& src/luyxndakov.rsggckogkampotlp2 hddiezayolfxhimhk2> nkyauxouajqnug,knbfhznniopkmruqdiqwrwjgdmjfzlatrbdkuifltadm27 -finhbhxhfuylkso$mpzjktvjpcxdtutvdjiqlftcflvdqwcegbqd20 - fgxnyfgtxuyvcvljziimkcdbvudezemuxfzhvamiaxqs2 -hlgozidnbig24 -qggdd+trfdjalpixlstlrundqoiwefwysvtegbpvbfepwbalm2 -rgitfuftwljqpwsxgauizovsgv΂kzqyzopssykikbcjd juetkt-64*dpsmhimcnplnvjxfpjsxplccoqneiezwcxdihceralwoqebnpvyvhgtwuzuipeqwwndpqknmxmeawmkkjzadzkxrutvvmykkxlpisrdseqpdprvohnkxaklkucmhdvvjsvkipxjpgjevmmufypcpqewqluxmfzmxghwistrepowsslvoebteawpgcbupkxewycrivaupnxoudhcemyzcymbvcbmcmumtqdmrmuczvaxanhjeolfkqxwjsqkfrqweuelmhhxolvsljrndqnsue: 803ac2ec257b252cfed0eda66b4fe3fdBa1cddff99f4138c0J$ -src/yndcbxfxcbcdr.rs  yrgrjvhhe2 -rpgvgpiodqbywycflhoy22 -ssw+mrrgebboejivrimfwmzlujrdjjfzcnsjqywyfngaikb2 - aunyasojmqyc vexkpamaawd2 -xirtffpgnxjnkgflaauxvbqby2( - fygbjcfywnozklniysudegvqtefvmwxttlip2. +finhbhxhfuylkso$mpzjktvjpcxdtutvdjiqlftcflvdqwcegbqd24 +qggdd+trfdjalpixlstlrundqoiwefwysvtegbpvbfepwbalm2 +hlgozidnbig2 +rgitfuftwljqpwsxgauizovsgv20 + fgxnyfgtxuyvcvljziimkcdbvudezemuxfzhvamiaxqs΂kzqyzopssykikbcjd juetkt-64*dpsmhimcnplnvjxfpjsxplccoqneiezwcxdihceralwoqebnpvyvhgtwuzuipeqwwndpqknmxmeawmkkjzadzkxrutvvmykkxlpisrdseqpdprvohnkxaklkucmhdvvjsvkipxjpgjevmmufypcpqewqluxmfzmxghwistrepowsslvoebteawpgcbupkxewycrivaupnxoudhcemyzcymbvcbmcmumtqdmrmuczvaxanhjeolfkqxwjsqkfrqweuelmhhxolvsljrndqnsue: 803ac2ec257b252cfed0eda66b4fe3fdBa1cddff99f4138c0J$ +src/yndcbxfxcbcdr.rs  yrgrjvhhe2. ufqz&uarniqnnbyjuermitfzuagyaadwkbbdvlyysoo29 -poldfhvr-azcwbbyqxmekolmjcwnyjguaplpdehonihkapmvvylbxwձȢ zlijxxpwzbi sktwuvk-8*Bkakjqcixqdxvfwbbphqqcdkwmwqpdiprxtwyaptzvgvmsljvhyvmfryckbpwnzuyhv: 90067a88509530da9a706bf9cc0650cfBc03b1a98d89a5f1aJ& +poldfhvr-azcwbbyqxmekolmjcwnyjguaplpdehonihkapmvvylbxw2 +rpgvgpiodqbywycflhoy2 + aunyasojmqyc vexkpamaawd22 +ssw+mrrgebboejivrimfwmzlujrdjjfzcnsjqywyfngaikb2( + fygbjcfywnozklniysudegvqtefvmwxttlip2 +xirtffpgnxjnkgflaauxvbqbyձȢ zlijxxpwzbi sktwuvk-8*Bkakjqcixqdxvfwbbphqqcdkwmwqpdiprxtwyaptzvgvmsljvhyvmfryckbpwnzuyhv: 90067a88509530da9a706bf9cc0650cfBc03b1a98d89a5f1aJ& src/woyhpcz.rs zfiqsqlouoagnlfvf21 + runufubykpzj!dzmybarqzrfxkmbfdwszigpgefcjnqqlw20 +dlwrwmk%hsxcswqseivophswedjbpippsrwhsvynudbjm21 unszkg'ghxzoxqwgcazyxikpjcfkieosozdahrwlnmsdqc28 -kmnpltkbydelcot%smwskxrqbgkjfbxmewvhhkfdfifsiregdzbdo28 -jwlnngyzjyatav&rlhvglmgxorchvqexfdvnlszusfvanvfckmavz2 - atyvejcfzjt tpppqgvfmbwgj2 +jwlnngyzjyatav&rlhvglmgxorchvqexfdvnlszusfvanvfckmavz2 -gdkagfyvxeisllhj20 -dlwrwmk%hsxcswqseivophswedjbpippsrwhsvynudbjm21 - runufubykpzj!dzmybarqzrfxkmbfdwszigpgefcjnqqlwŠŔttytn hmdgxhhrh-47 *janrwismusdcrltrvaxshtqchxdoejwvamsnnlwmfkfhnfltuzdjjpuzxdxkezlckbsvarifmgdlerupljzsolxcrdibdzchhymlbtcneumtefsezrvddmfeolmfomgbsgmyyamywrdjvualnjfptytsrxlzlyxjixmizrbzjaiqriflivveopfqnvvxwkcbehaopdfuxbjyefijpxykrxxbbnoqqyugkmdvbbrihspj: e8f650fff70c04590bd818cc474d429bB428e73286310eb15J9 -src/vohzofpezwncez.rs lxfonebcediofnghiboegaqlmhezs2D -fjhqlvkmzxqatrj1cskfwwlaqghrtwfuqpaagaglfcbdxcnmirokxneqzjjaltvvd25 +gdkagfyvxeisllhj28 +kmnpltkbydelcot%smwskxrqbgkjfbxmewvhhkfdfifsiregdzbdo2 + atyvejcfzjt tpppqgvfmbwgjŠŔttytn hmdgxhhrh-47 *janrwismusdcrltrvaxshtqchxdoejwvamsnnlwmfkfhnfltuzdjjpuzxdxkezlckbsvarifmgdlerupljzsolxcrdibdzchhymlbtcneumtefsezrvddmfeolmfomgbsgmyyamywrdjvualnjfptytsrxlzlyxjixmizrbzjaiqriflivveopfqnvvxwkcbehaopdfuxbjyefijpxykrxxbbnoqqyugkmdvbbrihspj: e8f650fff70c04590bd818cc474d429bB428e73286310eb15J9 +src/vohzofpezwncez.rs lxfonebcediofnghiboegaqlmhezs25 osfhpchmlpre%rgrhtujnbejbrtsffpzijarbqnyxuugvmkwja29 -cmqytj/ppqpvozwhwurhtmsvhzxcesyqsivsyqymbuppaiwzjjssit2 +cmqytj/ppqpvozwhwurhtmsvhzxcesyqsivsyqymbuppaiwzjjssit2D +fjhqlvkmzxqatrj1cskfwwlaqghrtwfuqpaagaglfcbdxcnmirokxneqzjjaltvvd2 eqvqimigmfuausshdppbdnujhce2( dsvcczlaqpogppizicnybkrdipgvcnvddyqdڶjfhlnuzejhd-93 *yluualbktgtsrlcurzlcgtdwymrqkpvzuieeguvvvjvifaffhdkgzweeqckqlwyzicntpbgcoveozbsusuyzqikgynbjmghdzankdvjvumjjxpwufbipbjyvke: a4d3ce1eeced50627ea1b088bd86dc65B8c510e015da1fdaeJ/ -src/aaohzrdounmgn.rsxqqjirgdxrdpyfprcdfp2# +src/aaohzrdounmgn.rsxqqjirgdxrdpyfprcdfp2; +rfvxc2khncvdyhbthmrbfwufzwawxhykouxqwitdofnecsryohmmlhiq2# rhcpwxrzzbeaafpklapklyhilknxtzi29 -tnfj1jtteaajeifbvgwtzgvzzagmobxgpqclqbyotwvugafkkqwtbt27 - nsjhmgspdcbh'eqgacfghrjnrzzgqxumvfhdpjvcnaezypvvxfzv2; -rfvxc2khncvdyhbthmrbfwufzwawxhykouxqwitdofnecsryohmmlhiq2% +tnfj1jtteaajeifbvgwtzgvzzagmobxgpqclqbyotwvugafkkqwtbt2% -zpbmqzaerkntuucqtwyrzibytnytfmldḡubwyfmbtzienpwrxtnxzifauemjhdo rjldtvgbu-32*vfzytswqpquwszknbzoskaizqebqjowiwoqqyzlyzhowgorjspjckrdyflkwaopoionfvpqqwdbbwkqoiddzyfhfvogimhyygsnzynavlmirhhknvznzvsjdaudeauykkqrepofunoebytitkwitxnyxpnyiexdoehh: 468d4569e5e8cdfcb640c16c52ba886cB4cdb8f1e27a40e9fJ1 +zpbmqzaerkntuucqtwyrzibytnytfmldg27 + nsjhmgspdcbh'eqgacfghrjnrzzgqxumvfhdpjvcnaezypvvxfzv̄ubwyfmbtzienpwrxtnxzifauemjhdo rjldtvgbu-32*vfzytswqpquwszknbzoskaizqebqjowiwoqqyzlyzhowgorjspjckrdyflkwaopoionfvpqqwdbbwkqoiddzyfhfvogimhyygsnzynavlmirhhknvznzvsjdaudeauykkqrepofunoebytitkwitxnyxpnyiexdoehh: 468d4569e5e8cdfcb640c16c52ba886cB4cdb8f1e27a40e9fJ1 src/zprbihanbwgcdlp.rs -fdeapzqjqbsntzskjwkc2@ - htrsftlfyxbad/gbzkznimqnsfjgxhmfrowhjomsxwhcrubxhyuuhxnesonvv23 - dordxscpbzl$oiwjgyllaygfavdfwssrkinvtzqefahfsrtq2 -kwswxfbcglrsumycqaerpbq2 - wyatwzbypnueuedsna2: -erpxnhnq.enjxmsfatnenmvgrxsiyqukhfyfuqakuwkrgvnnpkppuvwsexyivgb xlrcoj-71 *vjitneknsefhmehsxezvclxuoiuhfmbyvkhqzokafosuadsczbyegwufobvwaicllybjqwiynmeclzhzbxzssqqrswlaffafeavvgfajjtkdgprnetdhrmvehbjqrjjffstbhtuhcyvnebrkmmhdbxwkoppkoqkguhcvoqjlgsqcycrzsnlqnxcyfcklcmhhbrcqpvyfosnuutbgeesowmesbwhjjnuuxxjuagcviqcejunvonuoctbpmtdtmxahpasecygdjyrpmtfmgqxprppzicgizmyncljahbcvtagodxdkinfyghmnnbxqsblcrythkiaiuykfjgiqpxmxgtswsqjczzfcvtmbfdcnnzdinmywisbcwoyipjrkypkznlowxjkxdo: d78e5e0e32efe682e599de6345da4d8aBbc428ed0b763364b2 -kjvxodicmjafuqzyhtjkslyz2: -ikemamo/mtcoippyzcsrjmtofdgceyqcrpctdojltsssgjmllxemlyu͙cxencbsfwdbqlttwuwqbhfjqqrmarmd-45 *tdspocfmjumebfvnxxoiehlzwsvkfjtqczobwwccbvybgkinyqvgkmrdwuecnpdwfhkprdhhmmmhcqtdplsqzlzcmtzigyqabjpprqfmsgwfiaspfsjifmfjfjisglbogjgwkiunkxdtldjnwjdjrbpvfdjahbgkicwpcjirqztmbqavgjuqtnwovwauzmwgwaozttmznjfieymoslczrfcpolqfhujhtuxhdnqfpmmqwhldfnvmcxdtxxgjnoumbnyzfgpuvuctndyzowfcoohqyzxzzcekfvzyozlqtaxmgntzwkhulkbibgqprrtjxzddjvmseolkabvspdstmzndxntnztskmjrednkxpkl: e39a55b73a625469f51a37475691a841Bc6f8e4fc968169df2! +fdeapzqjqbsntzskjwkc23 + dordxscpbzl$oiwjgyllaygfavdfwssrkinvtzqefahfsrtq2: +erpxnhnq.enjxmsfatnenmvgrxsiyqukhfyfuqakuwkrgvnnpkppuvw2 + wyatwzbypnueuedsna2 +kwswxfbcglrsumycqaerpbq2@ + htrsftlfyxbad/gbzkznimqnsfjgxhmfrowhjomsxwhcrubxhyuuhxnesonvvsexyivgb xlrcoj-71 *vjitneknsefhmehsxezvclxuoiuhfmbyvkhqzokafosuadsczbyegwufobvwaicllybjqwiynmeclzhzbxzssqqrswlaffafeavvgfajjtkdgprnetdhrmvehbjqrjjffstbhtuhcyvnebrkmmhdbxwkoppkoqkguhcvoqjlgsqcycrzsnlqnxcyfcklcmhhbrcqpvyfosnuutbgeesowmesbwhjjnuuxxjuagcviqcejunvonuoctbpmtdtmxahpasecygdjyrpmtfmgqxprppzicgizmyncljahbcvtagodxdkinfyghmnnbxqsblcrythkiaiuykfjgiqpxmxgtswsqjczzfcvtmbfdcnnzdinmywisbcwoyipjrkypkznlowxjkxdo: d78e5e0e32efe682e599de6345da4d8aBbc428ed0b763364b2: +ikemamo/mtcoippyzcsrjmtofdgceyqcrpctdojltsssgjmllxemlyu2 +kjvxodicmjafuqzyhtjkslyz͙cxencbsfwdbqlttwuwqbhfjqqrmarmd-45 *tdspocfmjumebfvnxxoiehlzwsvkfjtqczobwwccbvybgkinyqvgkmrdwuecnpdwfhkprdhhmmmhcqtdplsqzlzcmtzigyqabjpprqfmsgwfiaspfsjifmfjfjisglbogjgwkiunkxdtldjnwjdjrbpvfdjahbgkicwpcjirqztmbqavgjuqtnwovwauzmwgwaozttmznjfieymoslczrfcpolqfhujhtuxhdnqfpmmqwhldfnvmcxdtxxgjnoumbnyzfgpuvuctndyzowfcoohqyzxzzcekfvzyozlqtaxmgntzwkhulkbibgqprrtjxzddjvmseolkabvspdstmzndxntnztskmjrednkxpkl: e39a55b73a625469f51a37475691a841Bc6f8e4fc968169df2! fkncxfodjlksmtzbavyrhsijrijcg2$ - vqfuykkcsiteharddgvxmmzuezrdujxpǗnfxstsirlr-82*2ljusnyxvwparenfvrupqjcixelosqzjmzijugmwwwrrwqvowvq: 95c9939d08385c499b4e845cfb8e9362B8b8ddb32e6ae19cb2 + vqfuykkcsiteharddgvxmmzuezrdujxpǗnfxstsirlr-82*2ljusnyxvwparenfvrupqjcixelosqzjmzijugmwwwrrwqvowvq: 95c9939d08385c499b4e845cfb8e9362B8b8ddb32e6ae19cb2; + ybaduvwtizos+szbwrerlyikfmaboakwndbqqivabpipqkjblnqtrjys2 fmlnixhmhljgkbkrhlgipawd25 -mknu-nxnluehrvuaqvvzenhhauoopbgaznmmwxfumlzlycnnde2; - ybaduvwtizos+szbwrerlyikfmaboakwndbqqivabpipqkjblnqtrjys⑫ǹbiaxvkttarsulpccejfjfzuywkv rpzscgnn-55 *prplemstnzajfpnxbuuljpbyuoonyzwrbdklixzmpmtelsnlrketinzugwpsmjjtgqdkkxwbrbdkdbbauoxrsyhqvsvrikvzpeqhevjiftiprvmjxppwopavgvviatxgkbfyqhihxsbuzmvqtfitehzesjgjpfkmpsypvwilqunqfsnhzfpxvrantdshzueethskrfmyjwarptabowxaqkzoatuplhjhyfjlnrgrkmpgklcmcvlqapyqjnaxasljkfgdqphbjbszvdhcrhxlyacpqxilnupdipusxhbrgjmqazfqxlellxarzpzzayghgjmxkftzubgtdsxisufbmpuwvbkbqcwedipheempopmxhqutarvpzolsjohwcfljmmboagoesgpoxrwbtetnrtjazgjyqasaqbdcdifsknzvffyzyvhxrbswrbbflncsufnauvfwtidjlzuxeimrkd: e73b37e3472e045faeeda9b53154c820Bca9450fb5bbc2c99J( -src/bhglbdnrg.rs mmmyfydrstgmovmem20 +mknu-nxnluehrvuaqvvzenhhauoopbgaznmmwxfumlzlycnnde⑫ǹbiaxvkttarsulpccejfjfzuywkv rpzscgnn-55 *prplemstnzajfpnxbuuljpbyuoonyzwrbdklixzmpmtelsnlrketinzugwpsmjjtgqdkkxwbrbdkdbbauoxrsyhqvsvrikvzpeqhevjiftiprvmjxppwopavgvviatxgkbfyqhihxsbuzmvqtfitehzesjgjpfkmpsypvwilqunqfsnhzfpxvrantdshzueethskrfmyjwarptabowxaqkzoatuplhjhyfjlnrgrkmpgklcmcvlqapyqjnaxasljkfgdqphbjbszvdhcrhxlyacpqxilnupdipusxhbrgjmqazfqxlellxarzpzzayghgjmxkftzubgtdsxisufbmpuwvbkbqcwedipheempopmxhqutarvpzolsjohwcfljmmboagoesgpoxrwbtetnrtjazgjyqasaqbdcdifsknzvffyzyvhxrbswrbbflncsufnauvfwtidjlzuxeimrkd: e73b37e3472e045faeeda9b53154c820Bca9450fb5bbc2c99J( +src/bhglbdnrg.rs mmmyfydrstgmovmem2; + hnoplbpanbj,rpqpubxgijkjtgmlecmewkdheuqvlbxirhzgqrjmertm20 krxe(hcfskntxajvmvrpsdehzznpaangbgrdbxumxzjfy2 -hjqvsfek bkzpdjfkenxnm2; - hnoplbpanbj,rpqpubxgijkjtgmlecmewkdheuqvlbxirhzgqrjmertm2) +hjqvsfek bkzpdjfkenxnm2) vysci wazpkujcjyvifxdtpjtzaqjefmbcswld2+ -ggcmipsnzdrpgcfaqaqpiezggajzmpvqgwtbony2% -minbicbwacwbjfqmzjrvjksdfwonlybyt21 -giacn(lxachrtbssagubxidtifegpacgpakfhuburrsuyzȄ yqxgwkepcjp +ggcmipsnzdrpgcfaqaqpiezggajzmpvqgwtbony21 +giacn(lxachrtbssagubxidtifegpacgpakfhuburrsuyz2% +minbicbwacwbjfqmzjrvjksdfwonlybytȄ yqxgwkepcjp ntikzjq-12 *tgwxwzdqydwhgigmkuuccwuirqxejxnatwpyfnrcxgfxjwfaggpofnxfwfjrfowzvmdojmiosaokfurzhljlcpcrttmsascvgdrtcsjyywfgbdckzmxyzldykashkaoowgmxrzgcpondbwwcuoxogxfsmmjthvvmcrivhacnnbcrlrkkzsmrlkrvzgszdompvkkfohqzsbwlmclcwupnfyiathuqdszaiaflbaijhicqckihkhuwwtsjqbrfwxpylnnwhillrlpkodxmrwncfswdiyyhstomfuotyxyjilupwpozvdsdhhkyanbihtyjwjxstnpigkfombbvnqopevitumwrpyemnerbomqehqwmrgzfuyfzfputpljzesdulqi: 9e6868abc8dd6f862a90dc9ee43da6e1Bc17eea95c8cbd1f5J9 -src/trsbhwhsvtqvjivutugw.rs uxjulmyytqoefhsxmmjplur22 -weul*fsqppgkthadxhmglpnkhtihmssdyvmvreadgqjwbxk2 -kwoe xordcvvxselg25 -omhfqihwarfhqrn"owhblvtvyjpqhzpjbsodgwzffvwbtfkcso2 -ezpcyafsxbrpkexexzgwqvmzqyaj2/ +src/trsbhwhsvtqvjivutugw.rs uxjulmyytqoefhsxmmjplur2/ zxntzz%xygjwexlnkkogqsvmsqzknwhyqrvebogsrcod2) - ydcqszorghvqckezfoeqrqcmckbjvzjiuyhuqjvpavegizdigzcimgsugqketvzqcix bsrdvc-13 *aloykaoowbxjczojkljmzfjyekcetslohfjlmmqmlhcwaminhvircfxwkherhlthmfcyitbimzttexoebvybdwbokpcsdpxbxfkupkverzubimdgwplihqexxoxtghnkyglslgcnsekoqfbeolohrcvtzwhlwffnmnekuuivrkeuyoqapqzdkbdaxwixsbbfqrmxmryetlbtxwnuwkeqbvhtsorgiouanwkwzhjezkuozilgxrmiivbtxwnmhmzzlfdhxcxnshgrvwrfcqoxheuktduryuaiinybksttldvhhokifjrgipocnmwenvzrggrszrhbfywbmiaxconpvtekoxsocfhyqtcsvawtleqnwvewfylbbbefketbrbeikbpdbrxncdjllilqxgjewldehdlprgoytqriivrbimluyumnaeijiyiolsakwrbhhc: 03a053a0cc04fe248cdbbd8f25bd3a12B9dbc754844ff8de5J- -src/obrvofa.rsonpqgsdpclwwdovafxphknhq2; -evozvtlnixsfhe)jzuqvwtfgtsotyttngiluxvzsphkhhgavwyfnbztz2 + ydcqszorghvqckezfoeqrqcmckbjvzjiuyhuq22 +weul*fsqppgkthadxhmglpnkhtihmssdyvmvreadgqjwbxk2 +ezpcyafsxbrpkexexzgwqvmzqyaj2 +kwoe xordcvvxselg25 +omhfqihwarfhqrn"owhblvtvyjpqhzpjbsodgwzffvwbtfkcsojvpavegizdigzcimgsugqketvzqcix bsrdvc-13 *aloykaoowbxjczojkljmzfjyekcetslohfjlmmqmlhcwaminhvircfxwkherhlthmfcyitbimzttexoebvybdwbokpcsdpxbxfkupkverzubimdgwplihqexxoxtghnkyglslgcnsekoqfbeolohrcvtzwhlwffnmnekuuivrkeuyoqapqzdkbdaxwixsbbfqrmxmryetlbtxwnuwkeqbvhtsorgiouanwkwzhjezkuozilgxrmiivbtxwnmhmzzlfdhxcxnshgrvwrfcqoxheuktduryuaiinybksttldvhhokifjrgipocnmwenvzrggrszrhbfywbmiaxconpvtekoxsocfhyqtcsvawtleqnwvewfylbbbefketbrbeikbpdbrxncdjllilqxgjewldehdlprgoytqriivrbimluyumnaeijiyiolsakwrbhhc: 03a053a0cc04fe248cdbbd8f25bd3a12B9dbc754844ff8de5J- +src/obrvofa.rsonpqgsdpclwwdovafxphknhq25 +uoa.viwvlpfddzgajldzvxbrxzbxwcctzavholpqigqmfmqlyx2, + kccfelfikmzafbvvhbrlocgpgsoxevngomfpvlcm2 nwbefpcixvhxiixqrngaugijlo2, -acdnujbgydqlrpxmhpiavhpswqwedxticlnwmcho2, - kccfelfikmzafbvvhbrlocgpgsoxevngomfpvlcm25 -uoa.viwvlpfddzgajldzvxbrxzbxwcctzavholpqigqmfmqlyxȭdvvlttxtidhfip ekdxorpyjh-43 *Tkmlgopgtoukegfjrpwjkmmsmcrvpjyjjsaxyrwrmqlcjjemjlmjmnqrynzlamwmwlrhcxulqjltffzurmurw: b6ab1b2a1d0eb7a721b0b7ffe1eb2972Bf19f4adeaf2c262bJ/ +acdnujbgydqlrpxmhpiavhpswqwedxticlnwmcho2; +evozvtlnixsfhe)jzuqvwtfgtsotyttngiluxvzsphkhhgavwyfnbztzȭdvvlttxtidhfip ekdxorpyjh-43 *Tkmlgopgtoukegfjrpwjkmmsmcrvpjyjjsaxyrwrmqlcjjemjlmjmnqrynzlamwmwlrhcxulqjltffzurmurw: b6ab1b2a1d0eb7a721b0b7ffe1eb2972Bf19f4adeaf2c262bJ/ src/tinimykwvf.rstxzlwcconuwuqisidiqtlkq21 hsmtdmobg$lsqsdxqlsolcqwhbtmyxfzphtvytvhnhqfcd27 kfpn/xpegacqbfjgxoscttdhlyhuaidchvsrtnyotxgvsoiquafdppuzjpriqvg-1 *_ctdhqilgfqldzhicgvykpkvlmjbmwykdetfbxpfmaezlyonmjdvhesidkreqhpnwunijlracipaaoqurlbqrigqiooxstvn: 10db93217f2182760612c1d47676d316B21be4cef02892253J. -src/mhvfpsktibjdpmqxz.rsxvalmmwghzzlrtd2 -tmnpykbrfujupmtybmobjj2- -gsxjn$hhjvpcuogzmqfhbvztbwxqhvvhwmbdqthbwb28 -eamxlhmzrimiaef%xbgjwsgaawrxbozrbzpyijgatbuvganorhdmo29 - wfslggibdfoz)yiqvsgjwcpgahjanmvxujfphovftcofgqagvkwbbf20 -bsihhwlyzjgsyzngmaqkrtqvisvukrwrtpylmtsjfotl㱱cqbcxrchpghezi limsmc-18*izsbsmxtgcfirgayhpbrxjtgalfzjpxznhzufokmiqrbkebrinlnhlhpeugqmmrmaeaawddgwmhgyqqmwxefrchmepbewuvlpdeqssqhencttkbkzpcfttgkaddcmrspdoevtxisobvdsbmhlrncixkppbqiigxayqoyewjjbghzymxheimhzixkmqotoogotvgplwstrctevtqihidbgflyhlesnqqughwgoqhifjcymiffmjobqmirocwngvfwqoxaicmcsxpmucmbidikebpjrisnnubvkblqiemxkomafzeqayqxmtzhihdcbeatyxtnnyepocaiqlszhqzytrpvwnkbxzxpqhnwzsosbrqygcrhzduofggfvrtoewsuvlwxxjfxlewqjrwstiybsjnebdrguosyrwthmyohdbbrytjrlwhesyvkqzlcooofxfyowicqrusdquspkcwyzgaebnxfmlyzdjiqyh: c8dc5bbb11881ac0e2a6556f9743257eB65246d3d7e9fb974J -src/ewnsdojufzhd.rsLvvekhuc2C -twlbbloheahkexs0faogilhqnlkmzldbswmablnaqmxskpdgbvexdmqwdjtmkvxs28 -fvuluenxsxuwptu%tnvokscivcdnviecjusupotgrwyfocgfyziuh22 +src/mhvfpsktibjdpmqxz.rsxvalmmwghzzlrtd20 +bsihhwlyzjgsyzngmaqkrtqvisvukrwrtpylmtsjfotl2- +gsxjn$hhjvpcuogzmqfhbvztbwxqhvvhwmbdqthbwb29 + wfslggibdfoz)yiqvsgjwcpgahjanmvxujfphovftcofgqagvkwbbf28 +eamxlhmzrimiaef%xbgjwsgaawrxbozrbzpyijgatbuvganorhdmo2 +tmnpykbrfujupmtybmobjj㱱cqbcxrchpghezi limsmc-18*izsbsmxtgcfirgayhpbrxjtgalfzjpxznhzufokmiqrbkebrinlnhlhpeugqmmrmaeaawddgwmhgyqqmwxefrchmepbewuvlpdeqssqhencttkbkzpcfttgkaddcmrspdoevtxisobvdsbmhlrncixkppbqiigxayqoyewjjbghzymxheimhzixkmqotoogotvgplwstrctevtqihidbgflyhlesnqqughwgoqhifjcymiffmjobqmirocwngvfwqoxaicmcsxpmucmbidikebpjrisnnubvkblqiemxkomafzeqayqxmtzhihdcbeatyxtnnyepocaiqlszhqzytrpvwnkbxzxpqhnwzsosbrqygcrhzduofggfvrtoewsuvlwxxjfxlewqjrwstiybsjnebdrguosyrwthmyohdbbrytjrlwhesyvkqzlcooofxfyowicqrusdquspkcwyzgaebnxfmlyzdjiqyh: c8dc5bbb11881ac0e2a6556f9743257eB65246d3d7e9fb974J +src/ewnsdojufzhd.rsLvvekhuc28 +fvuluenxsxuwptu%tnvokscivcdnviecjusupotgrwyfocgfyziuh2C +twlbbloheahkexs0faogilhqnlkmzldbswmablnaqmxskpdgbvexdmqwdjtmkvxs22 akgpfakxjmgfjfjjakcbelkjzxnjdyracysozvjjsoojwolqptqcnlrndwpupiigzcme rxxatrwgpm-71 *mrntyofzfeouwstonkbyntjldznxythpgsjbkmmlygqlltskllrsjylzdsvyvpjrdiqaxoitwgqpvbmywwvzxtlzrzsgfbwlqrzlmizlvvjdpubfdtwwwlkonfysibxugyclophgdhltoqpwpyujejvhzcosevemdukogjjqcmfcxwndrzc: 5774bd100ec396d667705184c915ca7aB3dc956d66a48495bJ' src/gdkdevxdtunjftqc.rs  yspvbudrq2 @@ -146,174 +146,174 @@ nwbefpcixvhxiixqrngaugijlo2, hdjhabasjjeoyiraa2; gtnbedfhwz-uqceatjjksknppfbhmuzrwmiemcuucftwluxlsisxlgueȧpyodslbipizwizwzlfkbqxyey-52 *sqtnytziohjioncqsmgdssnmkhdgesalqfdquapkxdhmzclkxtyunqimeqpvbvbdxsoglnbcbcldyugbxgvtxnmnttqbevzmsynwrblmvonkmkzoyyorfdlsqltrwvkwlewvdlhzntswcycjkofizuoekdvfdearmprurkehrxomlpicqqrundfhkafblbakufojlfnunvnokverdptthwsulnxyiypemkowqmtoxlxeeuzphfgknzbpswnjqdyiadqbtctawyghedgqoiojdklzmgwwbjkubxczqkifxeeqximbwarxvjwtknneohnvlfkmq: 62444233dc1e15ff29a29987782b4d77B98a6ff4b194a86e1J# -src/physwvenmgj.rsN kluovfwylqv2- - ineothnuhorhznwoleykoaefejylzlnjjlhcsnteg2$ -brmezhqdybqaajfpzivbndypjbzguxjp2, - ixeevflbeejuhyhfjtbzktbhoxnpihrrdazxeull2* -wavy"yywvbniofmkezrwyyhmmzelzgtybhkhmot2( -wngj wtgguegnxjlqssomkiptfeappanlxytb24 +src/physwvenmgj.rsN kluovfwylqv24 -hwkeebiztq&enkjwrxyzkmcueptubqmnvgrbtlazvcgvxloie24 -iapupxz)zrpyvbisxlzbrhiawuonhckvdczfwygsmuhkldgth22 -tqp+okjhfphtiiftlugjpnjpufulngjvtrizaucyxbjeyrl rovzuudsf fzwqezfy-63 *ypzqofnbdyznkblijwpyuowogpiqeqleduewfanupdazglgobxkjeizezhivwibftwauqkvlyswxesunxxipvxssalzmmkpghqelaejaewaxrjcegpovfwduoqfywgyppoofxbhpimycfdelftlqhcjnomykzlghvowonagyhrnzoajiqrchszpdoebdoldyjxogfydxcakdqgwmgaodepsrfjggbphgeutuzlwi: c5544f96d4c46cb29ac6db5285906aa5B12957dc80291a3e9J1 -src/lcedyydjktjcsf.rswjobsdiuhypbeadnpkoomor2B - tgkfufpghvcj2qiksootfansftxamgclcamgdjodtnwvajtwvshejfwkgxyvsmx2( - xstndtcgwjyphudadwdvuenkvdckgrerdtpt27 +hwkeebiztq&enkjwrxyzkmcueptubqmnvgrbtlazvcgvxloie2, + ixeevflbeejuhyhfjtbzktbhoxnpihrrdazxeull2* +wavy"yywvbniofmkezrwyyhmmzelzgtybhkhmot24 +iapupxz)zrpyvbisxlzbrhiawuonhckvdczfwygsmuhkldgth2- + ineothnuhorhznwoleykoaefejylzlnjjlhcsnteg22 +tqp+okjhfphtiiftlugjpnjpufulngjvtrizaucyxbjeyrl2$ +brmezhqdybqaajfpzivbndypjbzguxjp2( +wngj wtgguegnxjlqssomkiptfeappanlxytb rovzuudsf fzwqezfy-63 *ypzqofnbdyznkblijwpyuowogpiqeqleduewfanupdazglgobxkjeizezhivwibftwauqkvlyswxesunxxipvxssalzmmkpghqelaejaewaxrjcegpovfwduoqfywgyppoofxbhpimycfdelftlqhcjnomykzlghvowonagyhrnzoajiqrchszpdoebdoldyjxogfydxcakdqgwmgaodepsrfjggbphgeutuzlwi: c5544f96d4c46cb29ac6db5285906aa5B12957dc80291a3e9J1 +src/lcedyydjktjcsf.rswjobsdiuhypbeadnpkoomor2( + xstndtcgwjyphudadwdvuenkvdckgrerdtpt2B + tgkfufpghvcj2qiksootfansftxamgclcamgdjodtnwvajtwvshejfwkgxyvsmx27 eznkfqj,jdtgqcgeigcsivypviwypocrzucydiswznphkygxdyyeӑ̪tahobewqjflsfqibabyqbjsue cqpfmdkbt-33*sicbdqgqsmknzvvmthhzpugomcdtteoeujxldbpxqucqvceannjgktqplfjsjncnpbmnlehtpxwyhojryfboioixlvoxmodbwkplyenijjlcowruroesztigjfqxwnlguxtmbymvjfegwbehtrufnizavraitzluaiwdopxurcnyhbduytocqytnjavmtewpnlyrjyvgiiuezntuiwkokanwkrchhlhsmpxajeqnrepxeaagystgtnapyvrktfrlkekckikruswfnjdyuqjmdbslhdkkowpsveyqkqinwlfrfocnoneyatazhlcjtrbbukolbizqummmprjgfb: aa895d2e1460aa8f505f952afc248d96B9643e1cd0897f92aJ1 -src/rrrtvjwrplswkwgbk.rszydihgmuzljmcfttiz2 -rxtbcoyrfvtdwtg20 -tgl)roeigxezqldgbazbunpjtvmasjmzxyigmiymvhllh2" +src/rrrtvjwrplswkwgbk.rszydihgmuzljmcfttiz2- + mtpzskoxfhtelozuxqhmrswuyqxyfdhmzxdbxannw2" vsromrhqhiqvkjnhiqijoashwvnwng2 -keajbuknjitr2- - mtpzskoxfhtelozuxqhmrswuyqxyfdhmzxdbxannw2% -jxzucwewzjtgwswbekbgjbogcbcjzomkm2! - ylhgfrsxmxkkcfnepacnnqfxuaiku2 -aooxgkosffigjxfcymrcfsyhrxӂ¾hjfyhbyzywwuneztndkrtysdoepx +keajbuknjitr2 +aooxgkosffigjxfcymrcfsyhrx2! + ylhgfrsxmxkkcfnepacnnqfxuaiku20 +tgl)roeigxezqldgbazbunpjtvmasjmzxyigmiymvhllh2 +rxtbcoyrfvtdwtg2% +jxzucwewzjtgwswbekbgjbogcbcjzomkmӂ¾hjfyhbyzywwuneztndkrtysdoepx qunkola-37*kpyozplhhnapghfgtmxyziaslgilluztkdctekqkhgcaupwvvexwrlpoinapiaphgwjcavhsvojbhpwdenqsqptoqwzznmrqmonvggceemmpnovquyyexpltjdizmkrmowafspnumprfcaziaipjheqbqxnjfyrlfqkkvvgdjzueiriqoloxjklshknxcxrgsugxklyzfpfezwtdovtupwkuhmyassfxjrkmfitfswxezghcaxnxvmwkyzpbldsfojrbahasoqwatxqzocyaorlfxluartlfjhvcmrkcgwvklxbdqzjujumsfehqkbuedncbfvvtonolruylpmhtyvipxfllvrxmugziqsylzjygzovbddtzpbpeddytveqd: 7a9100109dfbcf45de2308100d290c65B923d31de1cfe2fa2J# -src/zhudcun.rswkewbgpqgkbcoa22 -jqvwivh'bqshmjvzxgluujtesxspngybosvehtveetnctix2# - phofemlkkhkxrogezbdzwoiugaxgqsf2 -pghzssguycdbstapyelqs2 -sgcwzxrxadmswcpeysijfaj2? -avleahjhechlzy-bdjdjufaeblmomcowjqlqtbuwzxmjiualcbbvcdyrzkee2 - rctlsokdmgexwhykctxjfrfikyry23 -ymyk+oqzxfptihuyuipmwgqjreyrhdrtcyxiuycpdjnhonbc26 -hsuvkmx+nbxizszmpnlhrzvrtlsivavtwswrlhmtnvynooiiisbqtvifha nbzlyd-44 *lpkzyppdptunadhdndbsabmolkybnojffwoneirbqsjjhzudxwnolqqjvzutdtfsxnuljagcnlqqrzfyqhqvrjfhabsnzewvgjgdylhttgbgngnhxbntoimrakrfhgcopisgzvjblgprmybeffgzyygmgtbnkkwvxuwatuvhyrqddvsfhlzkydjjydltbnbqacruilhofkmxrovmfnugkfptcuxnnhkklgkkorhurmrwzvihzruqqqvsnsdrtoucqttrrmcglmldidkcugkeemmjmrgsdurbvpoqodjnzdefxujuzrzfcdxswkoashflrsuhqautcjpzgdkqkxttszvsxwadjmrthbcgmevdobcuokuabxxzhnjgermstskacjldwvobiepkjkbaouvgnpqkcmswbbryoydcmwkzcmbbuxnhh: 3636b5a0a6911a5a1ab3e666fdf8c8c1Baf516416fe99f25d28 - servramhdkf)dzxjlysatqiogtpclgpzvudqdnpvnbxopasudvezu2 +src/zhudcun.rswkewbgpqgkbcoa23 +ymyk+oqzxfptihuyuipmwgqjreyrhdrtcyxiuycpdjnhonbc2 + rctlsokdmgexwhykctxjfrfikyry2 +pghzssguycdbstapyelqs2? +avleahjhechlzy-bdjdjufaeblmomcowjqlqtbuwzxmjiualcbbvcdyrzkee2 +sgcwzxrxadmswcpeysijfaj26 +hsuvkmx+nbxizszmpnlhrzvrtlsivavtwswrlhmtnvynooiiisb2# + phofemlkkhkxrogezbdzwoiugaxgqsf22 +jqvwivh'bqshmjvzxgluujtesxspngybosvehtveetnctixqtvifha nbzlyd-44 *lpkzyppdptunadhdndbsabmolkybnojffwoneirbqsjjhzudxwnolqqjvzutdtfsxnuljagcnlqqrzfyqhqvrjfhabsnzewvgjgdylhttgbgngnhxbntoimrakrfhgcopisgzvjblgprmybeffgzyygmgtbnkkwvxuwatuvhyrqddvsfhlzkydjjydltbnbqacruilhofkmxrovmfnugkfptcuxnnhkklgkkorhurmrwzvihzruqqqvsnsdrtoucqttrrmcglmldidkcugkeemmjmrgsdurbvpoqodjnzdefxujuzrzfcdxswkoashflrsuhqautcjpzgdkqkxttszvsxwadjmrthbcgmevdobcuokuabxxzhnjgermstskacjldwvobiepkjkbaouvgnpqkcmswbbryoydcmwkzcmbbuxnhh: 3636b5a0a6911a5a1ab3e666fdf8c8c1Baf516416fe99f25d2 +oqhbkkwjerymuxwyqjr28 +fvllwwmuibefdfu%cviawfhwiiwaflwsptezqxamihpalzxlfmoxq2 jpxqzhvi -jhcfkagtku28 -dhityusvozrxfo&wxyhmiygyzlyomkqpnlboybmsvavxcnclyleit2: +jhcfkagtku2: spaiuggeaokesuz'emqsspnefwqkpypxbpuycjneewfigazfrvydicm2 -bjpgvitos2 -oqhbkkwjerymuxwyqjr2> +bjpgvitos28 + servramhdkf)dzxjlysatqiogtpclgpzvudqdnpvnbxopasudvezu2> sshfyqxqqgwglsl+lyghaoexfebpwwimhnzywrcfdiyfgamxxkufumxiumw28 -fvllwwmuibefdfu%cviawfhwiiwaflwsptezqxamihpalzxlfmoxq vxedxlgcffnkw tnjtzuegbn-44 *gibmvldykvruvwlfpbrdogvdgobwkvehllgtowfxtoasomswsbuihqofvnwzhlvibxcsgbpjrqaxvolmodaqnkuubwjurqwoedqynxpcgvkblnxcwwipgwrhrlbndbhlptncbkngtlsgjkjnovukdmfdreqqehnmeyxzwuazxogkaszeqyptdhopplcpvijseocsrvefbtmxpfnyiavnwviwjunbijgmbvnccgregrwmopdabzehwyxrnwevqtlokbrmragmcubozggmciymhfcvyfdvmrcehjmcpieijttveaqujgnhnbipilonck: 7e67f877ea424e9daa8d11aa193071d2Ba851ef7796f255c3J, -src/jotzfedbhldoi.rs dmlricissiblnjpey2 -tzvwx -soutrfxiqh2/ -ccgwwa%cuzqeyhhadhydcfvuqitundrlcnukhlxitobl2 -hjeujti sxynpyczo2 -gpcqgzuzeoieetjgwiluwdw2 - khqxyzbvcgsdnesfgbg2 +dhityusvozrxfo&wxyhmiygyzlyomkqpnlboybmsvavxcnclyleit vxedxlgcffnkw tnjtzuegbn-44 *gibmvldykvruvwlfpbrdogvdgobwkvehllgtowfxtoasomswsbuihqofvnwzhlvibxcsgbpjrqaxvolmodaqnkuubwjurqwoedqynxpcgvkblnxcwwipgwrhrlbndbhlptncbkngtlsgjkjnovukdmfdreqqehnmeyxzwuazxogkaszeqyptdhopplcpvijseocsrvefbtmxpfnyiavnwviwjunbijgmbvnccgregrwmopdabzehwyxrnwevqtlokbrmragmcubozggmciymhfcvyfdvmrcehjmcpieijttveaqujgnhnbipilonck: 7e67f877ea424e9daa8d11aa193071d2Ba851ef7796f255c3J, +src/jotzfedbhldoi.rs dmlricissiblnjpey2/ +ccgwwa%cuzqeyhhadhydcfvuqitundrlcnukhlxitobl22 + gtngdyucl%omnqzrnchylcmaxjzbskbgzmvdbjslxeqotjc2 hbv -nsmctgsnvk22 - gtngdyucl%omnqzrnchylcmaxjzbskbgzmvdbjslxeqotjc2* +nsmctgsnvk2 + khqxyzbvcgsdnesfgbg2 +gpcqgzuzeoieetjgwiluwdw2 +hjeujti sxynpyczo2 +tzvwx +soutrfxiqh2* kulxmlvjxhhprqwiqwgdvzbslxijojskexlxwjDzǽdgfrhdxlztsspyz lkguwzf-31 *Xfjzeagoqkkusdcwbqcuibbkfmfbuepdgubzzmryfhbwbgrinfqqplayzumrciokotpdpbikwfrnrwqcungykhfvy: 14a9991067a0f463fa6b0d267ad3e7afBe189d77428585634J+ src/doerzkcgjv.rstlrptysfxnmrzlcnofv2* -lfntbd rqznrzqoebbxsngcovfbhdoyctozrmin29 -kqffomizkcsverp&kwocconzvnirmwxfrbllgczhydddqlgokbakrk2, -yypabhkxuqvxnujxqbfewavlsghdrafezjlewnta2: - tdjeuxvstsvyo)puesuovweolrbgvqirbztsskovnyqlipozirwzyjz2. -ehz'ayjnkiikddtrmztvsduoaanmeznzfpixdnecmnu23 -pfm,bpxqnbvwluxqqypdpiqpbavcwsnauqnvfhqafsitxbph2 +lfntbd rqznrzqoebbxsngcovfbhdoyctozrmin23 +pfm,bpxqnbvwluxqqypdpiqpbavcwsnauqnvfhqafsitxbph2: + tdjeuxvstsvyo)puesuovweolrbgvqirbztsskovnyqlipozirwzyjz2 hvrlhuddxtdwovwxmixkoqjlqux29 -ymjfx0zdjyuaysfbdsphgohgugnrvbcsldxarwmnniuygcmrxarnanvmeegeixgsncckqzglwuargghm +ymjfx0zdjyuaysfbdsphgohgugnrvbcsldxarwmnniuygcmrxarnan2, +yypabhkxuqvxnujxqbfewavlsghdrafezjlewnta29 +kqffomizkcsverp&kwocconzvnirmwxfrbllgczhydddqlgokbakrk2. +ehz'ayjnkiikddtrmztvsduoaanmeznzfpixdnecmnuvmeegeixgsncckqzglwuargghm pkaseqf-36 *pwxwyfdsuwsyhnphgivobueqaqeyweyqoratuswajkxvwzgqsgwawcmbvhwnqvqmhkftdagtnqwcvwabumjrdpctebkkxqturqqwpmgxbitqwdalhtpfgkdvgmclsjyymwmeqbxlcicabzbnyxfahcnojrcmslpdtwrsumgymdrwhganrcbljdlefrcvsapdwaxxucpluwbcseoyvfbzdnsrjfleaimdllurccdkuqjcxntqvrowaavaizvuvozsyvyvcqbgzobsctdhiionzfrqmdbjdwhavwqcjqe: 29bf130de1435831db61d4d643c69094B3e676262c8556397J/ src/iirqnvgpyxhuygr.rsqxihcjhohofddmdcxe28 tqwvt/rtongccdgraeympoxirhhqnuqijhgejkmsansynjdlbblgb2 izlewhppduizjrwftbzjgvdohaẞnzqvfczauvnksnlidzai-20 *npqqwivznbpcfjxzvnkgrvjgpsfkpsdngwywccwdsnuwllvpbbwmvozvsbnhawvxzigybdxjohscwjspetgvimynnchfqtsfeqmupcdbprlvteo: 6e245953a9cda50f52866688c4c23f31B2e591b41f10344ecJ- -src/kigxchbpo.rscgewcgilzefbhnlpqhfckw2 -nufepxupt2 +src/kigxchbpo.rscgewcgilzefbhnlpqhfckw2 +asbddhigqnnyhgggvoredpfwrq2 +nufepxupt2$ + uwcaiksbsklvvlcoidmryfwrsrkcwuly2 cozfnhrnxdepxzqxhasj2% -zyuhzpmetzatfmwumtzwxhfjxzhsgzwed2$ - uwcaiksbsklvvlcoidmryfwrsrkcwuly2 -asbddhigqnnyhgggvoredpfwrqղӖotnnuixdanrhkxoavfjccvhfj txpwlanqx-32 *unvxtaoagzxhjgeofzkwjliowncthlavcexeqmbkbaghjlgtvrlosubagophosokpzfacramtkuohswdefkrrfavilwhbxkrygyicyhyavbgjwctmgkfroyufhwubgajcexthnhlcnciywiyvcepnfuqsbxvfggmazcfrglrwvbtlbfevuisnxevfdkpimzkidmhwljpijpkxvcaiikyhnvroodkqnvvmyzpkxfbgztiaaqtylmaeihfeevqtlvokdhebbddowrmjdelsxwuxkxltnxju: 7eb5f2def644bf33ec8809b595d7433bB4205058d3b1ce5b9J -src/tmggafyms.rstwxel2 -jkqzxordgtcgkzvvkaddmtunaic2- - prfqldhmyrqimumoevtvbvqigchtyzbqqjqzhtvcp،xzbrhmitdpzzltxoitd tbfgnvvev-94 *cwhwvnzcppyhwvnpqzoqmqkhgszgdneouitphwapmwxgwxkhdzkhemdiloiwyiyacnvyiathowykmvlddhnchvwdeoebaobqwsxjuywnekwiojgqhpmreyxuciftsdttbguciarymnjjrkffazfabplsdbrmudrbnnoclokfdffyhrlaysowkmktaueeloiooynrmomfwaafgngfuzqwwvkoktrixvineakegxvneyqfvzuxdduqcrcqquahczwiyporlzybprrqgcwdemgjhambkijhhsoetkqemdfemsluzmhrawarescxqniuxgeinayvvuyhyrlczjlholtyvtwljelrforduamsgkyaxagstlngirqziaakfnwfytopanqrswxmcioqeiuspkdcrbvtbehknnjwgydjkzfwtognqtpfllkkselntmxhdp: c2e3e496574f78f886a6e0ecbc55bc0fB1e39e9c51b97fbb7J6 -src/nrulmermrv.rsylgrjgrlpmgdxonbxwrjwyxdbqsjjq2- -qyq&buibbdrtxvfygekmqkoauhkmnxnwbkheweamzk2 - zzsfpfjucglvtbxywsprfitenlaǰchigdsfqgmliajisgqbtatuvfzmgt szqiuj-15 *erpyxgzohgwdsksbazzluzdcrxcjxqciwwgqjychkgnkozwjeeswljlrqvndileewvocvjgqwjcxhldgwaevovuopbakbgsrnwgrkusmxpjqevwnixndsmbyislyvmeupolymsrverfwegjqihzsvahikbrxhpqazixagotvjzytlmjyqkmzqyuispagxivmjbjaxklkzhbllrczeqcpruorjzkxduxseydbgkygnshawnilppdcbwectiqeiljiqrutanygeacwhxyfioyegqyjazcfhzvkmuvxbqjnrvsquuuebvpbprzjezblvyoyyvefqlczytuonmjetfbyoghusombwttagdjeswnjeevfasmhywieoavmadpqrflcfioqdxvwivbcwpvtfperxjrbcfiyxbavravcduaipdfqlxegwayoxqbyzfrnadjknpizjuvofkvrjrnsqdwrzuvtdbuit: 569b7d336c67a4e94cb5a7ca25a995b8B903f34dd9900b2f6J5 +zyuhzpmetzatfmwumtzwxhfjxzhsgzwedղӖotnnuixdanrhkxoavfjccvhfj txpwlanqx-32 *unvxtaoagzxhjgeofzkwjliowncthlavcexeqmbkbaghjlgtvrlosubagophosokpzfacramtkuohswdefkrrfavilwhbxkrygyicyhyavbgjwctmgkfroyufhwubgajcexthnhlcnciywiyvcepnfuqsbxvfggmazcfrglrwvbtlbfevuisnxevfdkpimzkidmhwljpijpkxvcaiikyhnvroodkqnvvmyzpkxfbgztiaaqtylmaeihfeevqtlvokdhebbddowrmjdelsxwuxkxltnxju: 7eb5f2def644bf33ec8809b595d7433bB4205058d3b1ce5b9J +src/tmggafyms.rstwxel2- + prfqldhmyrqimumoevtvbvqigchtyzbqqjqzhtvcp2 +jkqzxordgtcgkzvvkaddmtunaic،xzbrhmitdpzzltxoitd tbfgnvvev-94 *cwhwvnzcppyhwvnpqzoqmqkhgszgdneouitphwapmwxgwxkhdzkhemdiloiwyiyacnvyiathowykmvlddhnchvwdeoebaobqwsxjuywnekwiojgqhpmreyxuciftsdttbguciarymnjjrkffazfabplsdbrmudrbnnoclokfdffyhrlaysowkmktaueeloiooynrmomfwaafgngfuzqwwvkoktrixvineakegxvneyqfvzuxdduqcrcqquahczwiyporlzybprrqgcwdemgjhambkijhhsoetkqemdfemsluzmhrawarescxqniuxgeinayvvuyhyrlczjlholtyvtwljelrforduamsgkyaxagstlngirqziaakfnwfytopanqrswxmcioqeiuspkdcrbvtbehknnjwgydjkzfwtognqtpfllkkselntmxhdp: c2e3e496574f78f886a6e0ecbc55bc0fB1e39e9c51b97fbb7J6 +src/nrulmermrv.rsylgrjgrlpmgdxonbxwrjwyxdbqsjjq2 + zzsfpfjucglvtbxywsprfitenla2- +qyq&buibbdrtxvfygekmqkoauhkmnxnwbkheweamzkǰchigdsfqgmliajisgqbtatuvfzmgt szqiuj-15 *erpyxgzohgwdsksbazzluzdcrxcjxqciwwgqjychkgnkozwjeeswljlrqvndileewvocvjgqwjcxhldgwaevovuopbakbgsrnwgrkusmxpjqevwnixndsmbyislyvmeupolymsrverfwegjqihzsvahikbrxhpqazixagotvjzytlmjyqkmzqyuispagxivmjbjaxklkzhbllrczeqcpruorjzkxduxseydbgkygnshawnilppdcbwectiqeiljiqrutanygeacwhxyfioyegqyjazcfhzvkmuvxbqjnrvsquuuebvpbprzjezblvyoyyvefqlczytuonmjetfbyoghusombwttagdjeswnjeevfasmhywieoavmadpqrflcfioqdxvwivbcwpvtfperxjrbcfiyxbavravcduaipdfqlxegwayoxqbyzfrnadjknpizjuvofkvrjrnsqdwrzuvtdbuit: 569b7d336c67a4e94cb5a7ca25a995b8B903f34dd9900b2f6J5 src/fkhjkoabzwiwi.rsadxplhwzpjoypnvovklsppbvvo2$ uknjaonljqvvkavttjyesvoaoytbdbfk2- vojcqhvaoyljxbnoppotikmtcjrkohzloojemcrpv2 qsdxxzvjyaexitmsinmrfmqwweqiwwphlywiknf-69 *vlzjwjlrfemcgwdbtqyphqyjazvdauezbkudthpwsogrzxbuiczmjgpbohzltabahwwshtvfuewfsogsylxrowfudcoppybikbkwjbhhfnvuiuayycqroxptgvcjeszrfadpqnzeckyndur: a0be64265895768dcbc9a4e6ec193ad4Bc9ca7ba614ebed79J+ -src/lcnmzedhwwxnpoon.rs cdpzpintsisdz2; - ppflgapsruc,xbydjwohdlezkzxyqppmmdrtkwlkhjphfusufzjkpujk21 -vbenkeouexmarvgirwoplbmtxbrpifrvrhccvnuufozde2( -mwgmsscklbukosdoudmkekbhprhfaeirjfad2 -prftom crippaudtfsfu2# +src/lcnmzedhwwxnpoon.rs cdpzpintsisdz21 +vbenkeouexmarvgirwoplbmtxbrpifrvrhccvnuufozde2 +prftom crippaudtfsfu27 + pruzpdwyxcpay&tvkbbsiqvgcyhijqrduptipbebwhyubwlvafsa2# zrfszjksefcdfdhsazgpvppfskwesaj25 - kclqmvjylts&mivasvwmpcqdrpnngwpelrdbysrfqdmvvsrgkc27 - pruzpdwyxcpay&tvkbbsiqvgcyhijqrduptipbebwhyubwlvafsalqcmmkkvsnockvmdlttpgafdlc ekneem-11 *nsjlzigaytybjslivkbycxwnsqanlmdpkysofawmnkcmmkewjrtghmtutypcvwsftpflstzcwesmnsgnihuqwpwrmtdvqjajmzvelrdveolrjedatfsinjioufrnjxoqzrdrktjgzhltgjohtnrxdygrkwipjkpchoicivhiaszlfpnnmljgorxyscdppgigl: ef93b6d096efa4f954413cce0ffbabceB42eabafe0861bd71J/ + kclqmvjylts&mivasvwmpcqdrpnngwpelrdbysrfqdmvvsrgkc2; + ppflgapsruc,xbydjwohdlezkzxyqppmmdrtkwlkhjphfusufzjkpujk2( +mwgmsscklbukosdoudmkekbhprhfaeirjfadlqcmmkkvsnockvmdlttpgafdlc ekneem-11 *nsjlzigaytybjslivkbycxwnsqanlmdpkysofawmnkcmmkewjrtghmtutypcvwsftpflstzcwesmnsgnihuqwpwrmtdvqjajmzvelrdveolrjedatfsinjioufrnjxoqzrdrktjgzhltgjohtnrxdygrkwipjkpchoicivhiaszlfpnnmljgorxyscdppgigl: ef93b6d096efa4f954413cce0ffbabceB42eabafe0861bd71J/ src/beuzzzbhprftpqfxftz.rs qkjnujcnctspil2C - bjyraveioxogq2uwlbpiohtfwipihzincudklpxyqgypryrlmhsgjvuopkaijcgc2% - sgakkzvmosqoratfybewiyuqztckadgaj2( - sqiitvvjjtjbhgdayrbcizjpeovtmbmsowqa2- -xyi&uggvvfykxzfqyvygjoyjkhncgdmozqwrblmaqjrjhkrmqkvxgntntzogwqsdcopgvc + bjyraveioxogq2uwlbpiohtfwipihzincudklpxyqgypryrlmhsgjvuopkaijcgc2- +xyi&uggvvfykxzfqyvygjoyjkhncgdmozqwrblmaqj2( + sqiitvvjjtjbhgdayrbcizjpeovtmbmsowqa2% + sgakkzvmosqoratfybewiyuqztckadgajrjhkrmqkvxgntntzogwqsdcopgvc uwgnlvw-21 *adkrwfumtbeaydnypkbevxsxdzthctfwbxcyjcajixgqumyjxxgafqsuilpsgxeynmrrlyubrzktyyamvfllevycihjztdakbwfjlfmpfsnxzqoiqxzhacbsxdynukjcjuedfwvlajuqygbamukkjbnnhukavfhjjhcihibajsocvvltqwczvecnqcnmnmpnpekmjsyqorgpgybdxiieyymhiuvjzupzbyinbskubhhuqlfegygyigasupqfvdljgdjcbyjmrxozpatcbxhtvlgznamliewiqqxqqtpacpnomejdsfjguamjwrndezjmshhkezmjqlwnshouyiqpphpdfuauxzmwulghbhgbmrhqqczbwbpoioeejoflnxxuawupxbspogmkikoxdgbyrkejtilcdaxkhcmibggxlioajriobxdowpwdzudptnbptwuqrhgl: db614439b7731950f748b653a0c8b0bbB354ca128f2da2a81J - src/bjbvzt.rs dlrnrmaccnd2 -lauxoycvkcwvlhpzwqtiyyojb23 -pqdqfss(ofbydgzopzwamyknprermruyfjpmobymydooalcr2 -pzdqymhkywrjbrvpavsnqplsaq26 - rxcvrlecevpgw%utmpbzlbdhbppawsmtkokvkaoypuypqmhogfp2( -zgmxrkovnuvwlemiunkwfgbcyobfmsqvypkg2! -ctonmvdnwwhtdszdoyzemhismcntr2: - ecjunensktcv*bwpshwyuwtfyqsayaxaezyuxenuovsqokqkqodkzdbӉМxgbmigttcdrhlqtxskeqtzhzcb-4 *fgmkcexufhfkjnfsdiemhhzlowcryfuzkjwtuisqipmghgmaisjrzhwiajnianergtkmfxixugklajsowzkkvjcrefoxarzqjdiiyeblkubqsocdoeepzzbzvrakkvwsidmkskmrbmmcazhmdnnyiktozwugroruhztcfkqqklnerzbocbdyctexgcjtjocjdoyprhovqifpoppbvoesw: 58263fb714e66ab5ae9e688ff0dc4c75B990d4136da5d6fb7J -src/uhdorjbh.rs  hwkxnwcvj2' - aibzyccwahohocvkewxnctdaftbrkjqztvc28 -coyu0ualpqzrvtcehrglwwbppakgpqqyjwdobonwpvvmueflacdfo29 - vzrgglcujku*cjxdcznoxrefmwmalbkxezeemsqcmdbwfzkfvhewakѩaysrudqokvatdqrrlpf qwbfofvg-20 *lrvqfdxiveouemmzgayhbjlaelvcbwzmdchinlsmxdzcgpvvuayvuybjbdfefdirugmseeyarxprnmrdlvxndvnzhogqzjaotquibtwcseckalsmtejlrrlcakzbuojqfmvdrsutdrtfrwgxzndwymlthlcqqlhbkizvubrwhxgqvxpqpywlfmpeaymnknfeojjztuiwipisiozezaqltwrsyartdsitdmhamibdeahoqarakrfjjcwbluamqijihgriuifkeekppnleijzxvztihefckvsnboiuqxnwnguscnvhbfqisbpjqlkoctevahngjyvaskxykfrduszxhditmbpcmzrzxnibmdwcawcbbjrfzrqoijsnypguirwdc: efed40a7df9539bdff0581078ba1206bBd2ab2a38decaaddbJ5 -src/cmkfcauxfxa.rsglnifhhyxtayfptfiuhcgutgmacl24 + src/bjbvzt.rs dlrnrmaccnd2: + ecjunensktcv*bwpshwyuwtfyqsayaxaezyuxenuovsqokqkqodkzdb23 +pqdqfss(ofbydgzopzwamyknprermruyfjpmobymydooalcr2! +ctonmvdnwwhtdszdoyzemhismcntr2( +zgmxrkovnuvwlemiunkwfgbcyobfmsqvypkg2 +lauxoycvkcwvlhpzwqtiyyojb26 + rxcvrlecevpgw%utmpbzlbdhbppawsmtkokvkaoypuypqmhogfp2 +pzdqymhkywrjbrvpavsnqplsaqӉМxgbmigttcdrhlqtxskeqtzhzcb-4 *fgmkcexufhfkjnfsdiemhhzlowcryfuzkjwtuisqipmghgmaisjrzhwiajnianergtkmfxixugklajsowzkkvjcrefoxarzqjdiiyeblkubqsocdoeepzzbzvrakkvwsidmkskmrbmmcazhmdnnyiktozwugroruhztcfkqqklnerzbocbdyctexgcjtjocjdoyprhovqifpoppbvoesw: 58263fb714e66ab5ae9e688ff0dc4c75B990d4136da5d6fb7J +src/uhdorjbh.rs  hwkxnwcvj29 + vzrgglcujku*cjxdcznoxrefmwmalbkxezeemsqcmdbwfzkfvhewak28 +coyu0ualpqzrvtcehrglwwbppakgpqqyjwdobonwpvvmueflacdfo2' + aibzyccwahohocvkewxnctdaftbrkjqztvcѩaysrudqokvatdqrrlpf qwbfofvg-20 *lrvqfdxiveouemmzgayhbjlaelvcbwzmdchinlsmxdzcgpvvuayvuybjbdfefdirugmseeyarxprnmrdlvxndvnzhogqzjaotquibtwcseckalsmtejlrrlcakzbuojqfmvdrsutdrtfrwgxzndwymlthlcqqlhbkizvubrwhxgqvxpqpywlfmpeaymnknfeojjztuiwipisiozezaqltwrsyartdsitdmhamibdeahoqarakrfjjcwbluamqijihgriuifkeekppnleijzxvztihefckvsnboiuqxnwnguscnvhbfqisbpjqlkoctevahngjyvaskxykfrduszxhditmbpcmzrzxnibmdwcawcbbjrfzrqoijsnypguirwdc: efed40a7df9539bdff0581078ba1206bBd2ab2a38decaaddbJ5 +src/cmkfcauxfxa.rsglnifhhyxtayfptfiuhcgutgmacl2 +jvjtgtdihzdexmuzelgrub24 nqzijna)xalekbutsszvleveokbgxnwuhinpmmmsebiqcqwnx2+ jym$liaznsafczhlofltbcrdxnftvrivowmbyuyp2 - gyacilmihewzblfmdpqv2 -jvjtgtdihzdexmuzelgrubߨhfdhwxat ywzufsgi-53 *hovrslxxsxaibrizaxpcbkcqlgynmuwqcwpldtdwshzbyrbrxytjqlcgibqodkpqyzxnbbvouzpdidxuaoggsbsmxujynmdockglfclydmbqlbxtdvbvgqefqgcrzqtyhucoinupuorzblkqscnzsnmlxgdnqszarefmkakkpprvvqmdwsoduibtccisjjsrgaeddlmmwxmjezjvphcmhfqrzawbycnqrohoxsstjastpquikcgwjexgqxejkymxhdzchuaihemzspthkijwkrpajcghakujehwgsbtmywozykvylhgogeozhqwyfgabxdzkiiqzepcvakuxsaznkespenmqthuuoofitvnswiepudykugriwsldaajvaxdeshoteggvcbakpgkymrtvkokkpjjzvxsyienrzjl: f920e21262f734e7e2507d7e18d28faeBaa40e705fe8eddcdJ7 -src/mxsqbotmvpu.rs quqajwncejjmqduhlbbhvfbjqruyqw22 + gyacilmihewzblfmdpqvߨhfdhwxat ywzufsgi-53 *hovrslxxsxaibrizaxpcbkcqlgynmuwqcwpldtdwshzbyrbrxytjqlcgibqodkpqyzxnbbvouzpdidxuaoggsbsmxujynmdockglfclydmbqlbxtdvbvgqefqgcrzqtyhucoinupuorzblkqscnzsnmlxgdnqszarefmkakkpprvvqmdwsoduibtccisjjsrgaeddlmmwxmjezjvphcmhfqrzawbycnqrohoxsstjastpquikcgwjexgqxejkymxhdzchuaihemzspthkijwkrpajcghakujehwgsbtmywozykvylhgogeozhqwyfgabxdzkiiqzepcvakuxsaznkespenmqthuuoofitvnswiepudykugriwsldaajvaxdeshoteggvcbakpgkymrtvkokkpjjzvxsyienrzjl: f920e21262f734e7e2507d7e18d28faeBaa40e705fe8eddcdJ7 +src/mxsqbotmvpu.rs quqajwncejjmqduhlbbhvfbjqruyqw2* +kpme"dgiewduwofaavhgenebslhvkcucnyhfxkr22 dhcunxgaqksmu!utffcokyvmbzfkwyqcomiublnlcakeimx2( - kmwstmijaqmqrmvjdtqkohllbdpxifkqzwcs2* -kpme"dgiewduwofaavhgenebslhvkcucnyhfxkrѧljtzpp + kmwstmijaqmqrmvjdtqkohllbdpxifkqzwcsѧljtzpp kbbltgz-78 *vbcdgwjexzkxajyrxycuxmgqbpgnltxhdguhnsubgckwsrqeehpoyweieakjeptlldyeswvlexthkleufbjwklxrmzsjyguiauurvtanpyzpvyjyydrixrczavattcmhdtkjojmkahxojpvpgajurpukkuvertoxfkdihuzbiwqydnhoakysfgqkkpoyjdlvqohqjexldgry: 5cfc967a7c620b6f5b1ae38d221f8fb1B557f645d00894f20J0 -src/iogweeuzdo.rsjtqjnvshngilhychxxnafekk2 - ckmmmlgcffosrfxquthmqqob21 - qqfzydtzxfrn!cihxrjarxhyaqgxizkvfvfmmnucaahalz2* -vqvewxcoxmvukfknzzfgnrdwwdakuiyardcryo26 - vmkkvszgrgjn&fvmeelfvyuduoflmsohavyfbeluzpnwtacanfp22 -hjtyux(fxcnyiotrqgabedhyhhudhnllnhlikxdwmbhuripofczhsjvgzhgmgietrwmnhcmku kljgradfh-58 *ssngpmbkfdrjbubcqsptthaerihezsgcoqrawcmeibojpkezulfbohbywxidmohcqijeusnncwrnbdgzngoncpeaceiqnxgtpmukxxnakmyuyeaqgrksigfrgrtvtwnqcohfilrvjctycccpwdbavrtjcdwynatxwiupupwirntwuhsmkrvggdbiuomdbcolzxihmrdghjollwigqhuwntgcakruefnkxwwwqeyxfijwftbkvqndzumwhduplqgbzepyukkkkjmhmtswcucajgifderheiwzdofvvjyikxiytqiuuvivkqpgkdzubusijswgyjkcilorzspxvlhqnssttcsjdbviehhxugsdwvcbxqczzivsmwpadtempkeefcqrmwrhofmvplzdynndsnjyedwafhogxsmgmfyhtgfgfaggwayweygqbbprwixuzmcfxssjnltvqtcqamqc: 558c4eb8f6f01298380693944d8dac65B7ed48289e262732021 - mgxkzwonykjo!bjxlxssbvfatinseyetenkcuvhmzytqen2 +src/iogweeuzdo.rsjtqjnvshngilhychxxnafekk2* +vqvewxcoxmvukfknzzfgnrdwwdakuiyardcryo22 +hjtyux(fxcnyiotrqgabedhyhhudhnllnhlikxdwmbhurip21 + qqfzydtzxfrn!cihxrjarxhyaqgxizkvfvfmmnucaahalz26 + vmkkvszgrgjn&fvmeelfvyuduoflmsohavyfbeluzpnwtacanfp2 + ckmmmlgcffosrfxquthmqqobofczhsjvgzhgmgietrwmnhcmku kljgradfh-58 *ssngpmbkfdrjbubcqsptthaerihezsgcoqrawcmeibojpkezulfbohbywxidmohcqijeusnncwrnbdgzngoncpeaceiqnxgtpmukxxnakmyuyeaqgrksigfrgrtvtwnqcohfilrvjctycccpwdbavrtjcdwynatxwiupupwirntwuhsmkrvggdbiuomdbcolzxihmrdghjollwigqhuwntgcakruefnkxwwwqeyxfijwftbkvqndzumwhduplqgbzepyukkkkjmhmtswcucajgifderheiwzdofvvjyikxiytqiuuvivkqpgkdzubusijswgyjkcilorzspxvlhqnssttcsjdbviehhxugsdwvcbxqczzivsmwpadtempkeefcqrmwrhofmvplzdynndsnjyedwafhogxsmgmfyhtgfgfaggwayweygqbbprwixuzmcfxssjnltvqtcqamqc: 558c4eb8f6f01298380693944d8dac65B7ed48289e26273202 fqfzdhkejys lkfcovhlwneho2' - njzkqgwytsdpzfhsrgbsjoknysmilprmczbrbmbdqkvytaikuiyrre jbesbahdy-10 *vxdfufcihrrsvcrcusrpbgiintspfgruuynukeljuvubldlzsscqmlqiigigmmvigwaskyuuqjjclexiajuqeixzxbsklxvsnwubedfdizeasebxvznpzenapojvqbjwsbsdupcksmhtktytctpwncwzewbvxzhmntjabfxizejafgwiwxdflkbljutqvqcltthzvsfemfxuwmzszzotnwsbygbbubvewfzommvwmrurmkurwyhsulkzjtagxiismmtdsqwjln: e7ce728703fc276616606e9bce9579dcB6a4d8b0e65a8b3a1J -src/ginnndvhub.rsrbgchem23 -jqew+qsnbfncyezhnktczuxvcpjbhsqvmmzdcsitydoowfqb26 - xbthmuqgecacp%fmfkaykpgoftkpdunbrvllgyzixbltxycudvh2' -qik ewppzjafrcsocwjorkcbbfvprpqshxnm25 - scqpdohbxhfdy$ewaqpvjiamyesanvtgweqbmnntwjadluofql23 -tcdbjn)hqbwvnrwtxgwwmihpyzlgscradrdmtyqclicfsnjk29 + njzkqgwytsdpzfhsrgbsjoknysmilprmczb21 + mgxkzwonykjo!bjxlxssbvfatinseyetenkcuvhmzytqenrbmbdqkvytaikuiyrre jbesbahdy-10 *vxdfufcihrrsvcrcusrpbgiintspfgruuynukeljuvubldlzsscqmlqiigigmmvigwaskyuuqjjclexiajuqeixzxbsklxvsnwubedfdizeasebxvznpzenapojvqbjwsbsdupcksmhtktytctpwncwzewbvxzhmntjabfxizejafgwiwxdflkbljutqvqcltthzvsfemfxuwmzszzotnwsbygbbubvewfzommvwmrurmkurwyhsulkzjtagxiismmtdsqwjln: e7ce728703fc276616606e9bce9579dcB6a4d8b0e65a8b3a1J +src/ginnndvhub.rsrbgchem2 + ndrouhfrzijizqwdtxqrmumrjwln2' +qik ewppzjafrcsocwjorkcbbfvprpqshxnm2- +wflffsymqdoprrmcsdzmnunxknafkxriuktaifjep23 +tcdbjn)hqbwvnrwtxgwwmihpyzlgscradrdmtyqclicfsnjk25 + scqpdohbxhfdy$ewaqpvjiamyesanvtgweqbmnntwjadluofql29 -zpstcnhecx+iofvmhyfzneixklxqxklqxllyljosrmmyqwftelgpbr2- -wflffsymqdoprrmcsdzmnunxknafkxriuktaifjep2 - ndrouhfrzijizqwdtxqrmumrjwln picgvukvggi pwlwzdrd-16 *qohfylmbhtycwkulgewdgbsczrhoegkchelgobvabvrjbilnxkmrtrpsmjtbnpbgauiearltbqvgqdefqmikxaayckheuhstixaclnedbbfpclavkszamsvavmtyyeskytsflkilihkiexofyqnygsxixhjuedomphbtyljwwlllwahzolldn: eb85620180d90ced9f594da83113d605Bf971736e57f2e6dfJ' -src/pxcuqlhyrqkxgc.rs hjfxbjbfwsd2 -abapbrfoehrzdjxwkrnffbgzgea2( +zpstcnhecx+iofvmhyfzneixklxqxklqxllyljosrmmyqwftelgpbr26 + xbthmuqgecacp%fmfkaykpgoftkpdunbrvllgyzixbltxycudvh23 +jqew+qsnbfncyezhnktczuxvcpjbhsqvmmzdcsitydoowfqb picgvukvggi pwlwzdrd-16 *qohfylmbhtycwkulgewdgbsczrhoegkchelgobvabvrjbilnxkmrtrpsmjtbnpbgauiearltbqvgqdefqmikxaayckheuhstixaclnedbbfpclavkszamsvavmtyyeskytsflkilihkiexofyqnygsxixhjuedomphbtyljwwlllwahzolldn: eb85620180d90ced9f594da83113d605Bf971736e57f2e6dfJ' +src/pxcuqlhyrqkxgc.rs hjfxbjbfwsd2( omr!umeedruvdtidokxwfcbxbbqhzriecpamx2# -onyogwfnnkeghhoexgniydprelvjtvj2 - ltmrofmwxtqjbqrfbefeeckcovv2< -yeaqpekjpouafus)wegjauvmmxqrcvmismwpzfrdfmevpqqmzskjzoopg҈epbcchetvrxtepguodavu vbfrdzjw-93 *ehbewuowbyjeyyzlwmzlyyfqyndmrenkidmvoiuqzlapbtogplctxklrvdkhvlxgojirvtttzjjhqusetwupickzlfrlpympxauvptwhbaelpheqsrsagcbrmxkbmleholjzguzwnijkfyyvlgyxexzmzyxnaqdqqkhpgvxifjnekcylrodocfaqddvahvviiqmbamslewgptqccoagjgspsmkjhimhmaiyqhxivhfyuvvrtucvsdmognlwlnjvhhtrdhhramzwrwmxpzzlzacyxha: 32b9b3ece2ab64ee9ae74b8164e34991B4194f2af465db27fJ, +onyogwfnnkeghhoexgniydprelvjtvj2< +yeaqpekjpouafus)wegjauvmmxqrcvmismwpzfrdfmevpqqmzskjzoopg2 + ltmrofmwxtqjbqrfbefeeckcovv2 +abapbrfoehrzdjxwkrnffbgzgea҈epbcchetvrxtepguodavu vbfrdzjw-93 *ehbewuowbyjeyyzlwmzlyyfqyndmrenkidmvoiuqzlapbtogplctxklrvdkhvlxgojirvtttzjjhqusetwupickzlfrlpympxauvptwhbaelpheqsrsagcbrmxkbmleholjzguzwnijkfyyvlgyxexzmzyxnaqdqqkhpgvxifjnekcylrodocfaqddvahvviiqmbamslewgptqccoagjgspsmkjhimhmaiyqhxivhfyuvvrtucvsdmognlwlnjvhhtrdhhramzwrwmxpzzlzacyxha: 32b9b3ece2ab64ee9ae74b8164e34991B4194f2af465db27fJ, src/flefkfyzqhjmw.rsjqzmqlcguzvsxcpjf2 qfvaetxuqjlmweygbbfw21 spiomzbax$upahszievzgrliablmizfahsxtlyutesbkpa2 -bcqsshojtfuuirbrtrdqnazmtvhsèdwdvqjxwanvvjsltwywhjbtrvfc bnezhamgdr-60 *|teiblohzzkgrmfwpqkmqydytgawtfznjlxyowsrhtrkwcwpdztdnchftebpijosqzvmblxmmeegrlocqxggmwawxhffhxfttirabxckqngtcqquzuwzcuzniluwb: bfffbe9c6ed0126c392047622d2e1925Bc59ac0feda3d291328 -jiikcwegzdbhhk&fyojzbitrwxxpflbajpgdpziknudwtqdkuodoc2! - byxwrjgslxhfkpblyrvhtxsivfkwm2. -rhcao%vvxogtdnlkrlgmkpeuptribdxgrqasjlbxwna2< +bcqsshojtfuuirbrtrdqnazmtvhsèdwdvqjxwanvvjsltwywhjbtrvfc bnezhamgdr-60 *|teiblohzzkgrmfwpqkmqydytgawtfznjlxyowsrhtrkwcwpdztdnchftebpijosqzvmblxmmeegrlocqxggmwawxhffhxfttirabxckqngtcqquzuwzcuzniluwb: bfffbe9c6ed0126c392047622d2e1925Bc59ac0feda3d29132< uyzmmodwqmd-lhqaghzyojsjmdcmoummrwlzsracqgctzbcbxvbbweydp2' - kcsigckbsudhjidqxhtmgtjqnomfqioqovwƺ܍czcfinvvcdqldwadcetg sbkuieasna-62 *pmbkreuppordssticugjjgfkmghrosyufnfhvyfcwjxzefomtvspjpbonmqqzybudczaytfokiywzasugrxowzpeglzhjbswrkzdqyxsfjdhwobslmwplqsxopmbgnqpmkrayghrkotfpariylefscgooepqtdokvvuckvesnrbfffvngsxhtksxatyaylvspfxakzzdhimoxduysddpqwumuhmnhdvahyvfjggsuzbbwgabyeafeglcocxdgvzohrgrvreqopyuafqixdptpjuueyxhtkqevhxfqnfkzrmhbbsuffewkdqxvcqpsdmjwcyaekifimeesfyaxcdhkakeuwg: 7196a37503ed05311098d24b796efc21B833dab49fafb988fJ2 -src/bufjykthmo.rscahmemeuffkouqhijpthtiliuk2 -exuogrperzvihwxpibrtdi2 + kcsigckbsudhjidqxhtmgtjqnomfqioqovw2! + byxwrjgslxhfkpblyrvhtxsivfkwm28 +jiikcwegzdbhhk&fyojzbitrwxxpflbajpgdpziknudwtqdkuodoc2. +rhcao%vvxogtdnlkrlgmkpeuptribdxgrqasjlbxwnaƺ܍czcfinvvcdqldwadcetg sbkuieasna-62 *pmbkreuppordssticugjjgfkmghrosyufnfhvyfcwjxzefomtvspjpbonmqqzybudczaytfokiywzasugrxowzpeglzhjbswrkzdqyxsfjdhwobslmwplqsxopmbgnqpmkrayghrkotfpariylefscgooepqtdokvvuckvesnrbfffvngsxhtksxatyaylvspfxakzzdhimoxduysddpqwumuhmnhdvahyvfjggsuzbbwgabyeafeglcocxdgvzohrgrvreqopyuafqixdptpjuueyxhtkqevhxfqnfkzrmhbbsuffewkdqxvcqpsdmjwcyaekifimeesfyaxcdhkakeuwg: 7196a37503ed05311098d24b796efc21B833dab49fafb988fJ2 +src/bufjykthmo.rscahmemeuffkouqhijpthtiliuk2 lamfkhexbfkqaacltygbcgsalbqf2 -dxt bsgzvyrtfub︍wehhzkakyovylet vcrvqmhe-88*]agvdrrcmfoudgqoutzezxrpdrfgqcduselqcwkdaofmgzjtmotcjmnpabokcdbjvttuzbqnfihyxkxhkhlwfdcielkpjc: cf3a621c8553496f2d97093a3f80cb8eBf05b946dbec02321J) -src/xlsniyyqdpnvgaboyo.rs yijtrgvfx2B -caxljhtpnfbhod0jrpjdzqqkzybofudzwlsjoxhhrcsocbcegzrionngqcscxek2# - -wggcuatkvlbcmqfzzwnczvfzzwxmbkq2 -crtlgpuzc2 -mfielzuzgwgoaunsukksbe2! +dxt bsgzvyrtfub2 +exuogrperzvihwxpibrtdi︍wehhzkakyovylet vcrvqmhe-88*]agvdrrcmfoudgqoutzezxrpdrfgqcduselqcwkdaofmgzjtmotcjmnpabokcdbjvttuzbqnfihyxkxhkhlwfdcielkpjc: cf3a621c8553496f2d97093a3f80cb8eBf05b946dbec02321J) +src/xlsniyyqdpnvgaboyo.rs yijtrgvfx2! vyjjzjdeinvrgpcinfvrnkgfsfrnb2 +mfielzuzgwgoaunsukksbe2# + +wggcuatkvlbcmqfzzwnczvfzzwxmbkq2) +wrdjambtjtgxxndlnkfmmgkwlgbvsihcqcgib2 bztuhqcguonfhzevoiesvt2 -nqhgnqmpdgal2) -wrdjambtjtgxxndlnkfmmgkwlgbvsihcqcgibɈpcppwhrwnugybdfu +nqhgnqmpdgal2 +crtlgpuzc2B +caxljhtpnfbhod0jrpjdzqqkzybofudzwlsjoxhhrcsocbcegzrionngqcscxekɈpcppwhrwnugybdfu awbkreb-58 *bncojyymjybcmxqdjkpswzynvijjojqafaiftmdjtzzgrvaigqhkzzvktbpsemxwpprrijcebkcvhsfkecsipzsjprzdvjglmxlfpuelzabxotpfthyoqjqpstchhvsahrcwhivrgjkfovllgwkshdptmzvarqhhikejalvlctwajdzaqfztznkvputmvrtueqcdnjtrthdnpmwvbwueoucyzajwcboeyvvmyfprqbbpkxxrysregbrmkouzwktdvhrjjvystvzxttqyxojnwpsqssnucozygpvyfuzdjbocijoxenbfvleiqhyldmhupogpkcmvzbqstrvftrldxboblehhnrisswnsqrkmgzmzzbxodamruvhzbiurkjroqjvmohlwgytrzslfkvtqvfknharsyouantibvljatdhzufhrsifwbuai: 8cf8686134429b6eea93cf3b3ceca132B809f2b9092e453862. etppnklnhv dubwfsclfwmaabxehkvtcppcdniyqgur2# diff --git a/benchmarks/datasets/media_frame.pb b/benchmarks/datasets/media_frame.pb new file mode 100644 index 0000000..33ec45e Binary files /dev/null and b/benchmarks/datasets/media_frame.pb differ diff --git a/benchmarks/gen-datasets/Cargo.lock b/benchmarks/gen-datasets/Cargo.lock index fbe3489..6b96b4f 100644 --- a/benchmarks/gen-datasets/Cargo.lock +++ b/benchmarks/gen-datasets/Cargo.lock @@ -16,7 +16,7 @@ checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "buffa" -version = "0.1.0" +version = "0.3.0" dependencies = [ "bytes", "hashbrown 0.15.5", @@ -28,7 +28,7 @@ dependencies = [ [[package]] name = "buffa-build" -version = "0.1.0" +version = "0.3.0" dependencies = [ "buffa", "buffa-codegen", @@ -37,9 +37,10 @@ dependencies = [ [[package]] name = "buffa-codegen" -version = "0.1.0" +version = "0.3.0" dependencies = [ "buffa", + "buffa-descriptor", "prettyplease", "proc-macro2", "quote", @@ -47,6 +48,13 @@ dependencies = [ "thiserror", ] +[[package]] +name = "buffa-descriptor" +version = "0.3.0" +dependencies = [ + "buffa", +] + [[package]] name = "bytes" version = "1.11.1" diff --git a/benchmarks/gen-datasets/src/main.rs b/benchmarks/gen-datasets/src/main.rs index 6bcf6b9..c4849ff 100644 --- a/benchmarks/gen-datasets/src/main.rs +++ b/benchmarks/gen-datasets/src/main.rs @@ -8,14 +8,32 @@ use rand::{Rng, SeedableRng}; use std::fs; use std::path::Path; +#[allow( + clippy::derivable_impls, + clippy::enum_variant_names, + clippy::match_single_binding, + clippy::upper_case_acronyms, + non_camel_case_types, + unused_imports, + dead_code +)] mod proto { include!(concat!(env!("OUT_DIR"), "/bench_messages.rs")); } +#[allow( + clippy::derivable_impls, + clippy::enum_variant_names, + clippy::match_single_binding, + clippy::upper_case_acronyms, + non_camel_case_types, + unused_imports, + dead_code +)] mod dataset_proto { include!(concat!(env!("OUT_DIR"), "/benchmarks.rs")); } -use proto::analytics_event::property::Value; +use proto::analytics_event::property::ValueOneof as Value; use proto::analytics_event::{Nested, Property}; use proto::log_record::Context; use proto::*; @@ -120,6 +138,41 @@ fn gen_nested(rng: &mut impl Rng, depth: usize) -> Nested { } } +fn random_bytes(rng: &mut impl Rng, min_len: usize, max_len: usize) -> Vec { + let len = rng.random_range(min_len..=max_len); + let mut buf = vec![0u8; len]; + rng.fill_bytes(&mut buf); + buf +} + +fn gen_media_frame(rng: &mut impl Rng) -> MediaFrame { + let num_chunks = rng.random_range(2..=6); + let num_attachments = rng.random_range(0..=4); + MediaFrame { + frame_id: random_hex(rng, 32), + timestamp_nanos: rng.random_range(1_700_000_000_000_000_000i64..1_800_000_000_000_000_000), + content_type: (*choose( + &[ + "application/octet-stream", + "image/jpeg", + "image/png", + "video/mp4", + "audio/opus", + ], + rng, + )) + .to_string(), + body: random_bytes(rng, 1024, 10_240), + chunks: (0..num_chunks) + .map(|_| random_bytes(rng, 200, 2000)) + .collect(), + attachments: (0..num_attachments) + .map(|_| (random_string(rng, 5, 20), random_bytes(rng, 50, 500))) + .collect(), + ..Default::default() + } +} + fn gen_analytics_event(rng: &mut impl Rng) -> AnalyticsEvent { let num_props = rng.random_range(3..=10); let num_sections = rng.random_range(2..=5); @@ -187,5 +240,14 @@ fn main() { .collect(), ); + write_dataset( + "media_frame", + "bench.MediaFrame", + output_dir, + (0..NUM_PAYLOADS) + .map(|_| gen_media_frame(&mut rng)) + .collect(), + ); + println!("Datasets written to {}", output_dir.display()); } diff --git a/benchmarks/go/bench_test.go b/benchmarks/go/bench_test.go index 475a818..fdc7c4d 100644 --- a/benchmarks/go/bench_test.go +++ b/benchmarks/go/bench_test.go @@ -115,6 +115,11 @@ var cases = []benchCase{ dataset: "../datasets/google_message1_proto3.pb", newMsg: func() proto.Message { return &proto3pb.GoogleMessage1{} }, }, + { + name: "MediaFrame", + dataset: "../datasets/media_frame.pb", + newMsg: func() proto.Message { return &benchpb.MediaFrame{} }, + }, } // benchBinaryEncode benchmarks proto.Marshal for a set of pre-decoded messages. diff --git a/benchmarks/google/benches/protobuf.rs b/benchmarks/google/benches/protobuf.rs index f591c3e..7407106 100644 --- a/benchmarks/google/benches/protobuf.rs +++ b/benchmarks/google/benches/protobuf.rs @@ -79,12 +79,21 @@ fn bench_google_message1(c: &mut Criterion) { ); } +fn bench_media_frame(c: &mut Criterion) { + benchmark_decode::( + c, + "google/media_frame", + include_bytes!("../../datasets/media_frame.pb"), + ); +} + criterion_group!( benches, bench_api_response, bench_log_record, bench_analytics_event, bench_google_message1, + bench_media_frame, ); criterion_main!(benches); diff --git a/benchmarks/google/src/lib.rs b/benchmarks/google/src/lib.rs index 9bc65ec..a9f2eee 100644 --- a/benchmarks/google/src/lib.rs +++ b/benchmarks/google/src/lib.rs @@ -7,7 +7,4 @@ // Include the generated entry point at the crate root. The generated.rs // file uses `#[path = "..."]` attributes with relative paths, so it must // be included from its containing directory. -include!(concat!( - env!("OUT_DIR"), - "/protobuf_generated/generated.rs" -)); +include!(concat!(env!("OUT_DIR"), "/protobuf_generated/generated.rs")); diff --git a/benchmarks/prost-bytes/Cargo.lock b/benchmarks/prost-bytes/Cargo.lock new file mode 100644 index 0000000..5f31e28 --- /dev/null +++ b/benchmarks/prost-bytes/Cargo.lock @@ -0,0 +1,963 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bench-prost-bytes" +version = "0.1.0" +dependencies = [ + "bytes", + "criterion", + "prost", + "prost-build", +] + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", + "serde", + "serde_core", +] + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +dependencies = [ + "heck", + "itertools 0.14.0", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "zerocopy" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/benchmarks/prost-bytes/Cargo.toml b/benchmarks/prost-bytes/Cargo.toml new file mode 100644 index 0000000..36291a7 --- /dev/null +++ b/benchmarks/prost-bytes/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "bench-prost-bytes" +version = "0.1.0" +edition = "2021" +publish = false + +# Disable lib benchmarks so `cargo bench` only hits the criterion binary. +[lib] +bench = false + +[dependencies] +prost = "0.13" +bytes = "1" + +[build-dependencies] +prost-build = "0.13" + +[dev-dependencies] +criterion = "0.5" + +[[bench]] +name = "protobuf" +harness = false diff --git a/benchmarks/prost-bytes/benches/protobuf.rs b/benchmarks/prost-bytes/benches/protobuf.rs new file mode 100644 index 0000000..5ecb6c3 --- /dev/null +++ b/benchmarks/prost-bytes/benches/protobuf.rs @@ -0,0 +1,116 @@ +use bytes::Bytes; +use criterion::{criterion_group, criterion_main, Criterion, Throughput}; +use prost::Message; + +use bench_prost_bytes::bench::*; +use bench_prost_bytes::benchmarks::BenchmarkDataset; + +fn load_dataset(data: &[u8]) -> BenchmarkDataset { + BenchmarkDataset::decode(data).expect("failed to decode dataset") +} + +fn total_payload_bytes(dataset: &BenchmarkDataset) -> u64 { + dataset.payload.iter().map(|p| p.len() as u64).sum() +} + +fn benchmark_decode(c: &mut Criterion, name: &str, dataset_bytes: &[u8]) { + let dataset = load_dataset(dataset_bytes); + let bytes_total = total_payload_bytes(&dataset); + + // Pre-wrap every payload in a `bytes::Bytes` so the decoder sees a `Buf` + // whose `copy_to_bytes` is a zero-copy ref-count slice. Prost's `&[u8]` + // decode path copies into a fresh `Vec` / `Bytes` for each `bytes` + // field; the `Bytes`-input path shares the input buffer by refcount. + // `Bytes::copy_from_slice` is outside `b.iter()` so its allocation does + // not pollute the measured decode cost; `payload.clone()` inside the + // hot loop is a cheap atomic refcount bump. On schemas with no or few + // `bytes` fields, that per-message refcount work can become a + // meaningful fraction of decode cost — it's the reason this variant + // can appear slightly slower than default `prost` on `ApiResponse` / + // `LogRecord` / etc. where there's nothing to zero-copy. + let payloads: Vec = dataset + .payload + .iter() + .map(|p| Bytes::copy_from_slice(p)) + .collect(); + + let mut group = c.benchmark_group(name); + group.throughput(Throughput::Bytes(bytes_total)); + + // Only `decode` / `merge` are measured here: `prost-build`'s + // `.bytes(["."])` substitution affects only the decode path. The + // `encode` and `encoded_len` numbers are expected to track default + // `prost` within noise — see `benchmarks/prost/` for those benches. + group.bench_function("decode", |b| { + b.iter(|| { + for payload in &payloads { + let msg = M::decode(payload.clone()).unwrap(); + criterion::black_box(&msg); + } + }); + }); + + group.bench_function("merge", |b| { + let mut msg = M::default(); + b.iter(|| { + for payload in &payloads { + msg.clear(); + msg.merge(payload.clone()).unwrap(); + criterion::black_box(&msg); + } + }); + }); + + group.finish(); +} + +fn bench_api_response(c: &mut Criterion) { + benchmark_decode::( + c, + "prost-bytes/api_response", + include_bytes!("../../datasets/api_response.pb"), + ); +} + +fn bench_log_record(c: &mut Criterion) { + benchmark_decode::( + c, + "prost-bytes/log_record", + include_bytes!("../../datasets/log_record.pb"), + ); +} + +fn bench_analytics_event(c: &mut Criterion) { + benchmark_decode::( + c, + "prost-bytes/analytics_event", + include_bytes!("../../datasets/analytics_event.pb"), + ); +} + +fn bench_google_message1(c: &mut Criterion) { + benchmark_decode::( + c, + "prost-bytes/google_message1_proto3", + include_bytes!("../../datasets/google_message1_proto3.pb"), + ); +} + +fn bench_media_frame(c: &mut Criterion) { + benchmark_decode::( + c, + "prost-bytes/media_frame", + include_bytes!("../../datasets/media_frame.pb"), + ); +} + +criterion_group!( + benches, + bench_api_response, + bench_log_record, + bench_analytics_event, + bench_google_message1, + bench_media_frame, +); + +criterion_main!(benches); diff --git a/benchmarks/prost-bytes/build.rs b/benchmarks/prost-bytes/build.rs new file mode 100644 index 0000000..71dd07f --- /dev/null +++ b/benchmarks/prost-bytes/build.rs @@ -0,0 +1,17 @@ +fn main() { + // `.bytes(["."])` tells prost-build to emit `bytes::Bytes` instead of + // `Vec` for every `bytes` field. Combined with a `bytes::Bytes` decode + // input, this exercises prost's zero-copy slicing path for `bytes` fields + // (the comparison point for buffa's view-based zero-copy decode). + prost_build::Config::new() + .bytes(["."]) + .compile_protos( + &[ + "../proto/bench_messages.proto", + "../proto/benchmarks.proto", + "../proto/benchmark_message1_proto3.proto", + ], + &["../proto/"], + ) + .expect("failed to compile benchmark protos"); +} diff --git a/benchmarks/prost-bytes/src/lib.rs b/benchmarks/prost-bytes/src/lib.rs new file mode 100644 index 0000000..828305b --- /dev/null +++ b/benchmarks/prost-bytes/src/lib.rs @@ -0,0 +1,24 @@ +//! Generated prost types with `bytes::Bytes` substituted for every `bytes` +//! field (via `prost-build`'s `.bytes(["."])` config). Decode benchmarks +//! consume `bytes::Bytes` input so prost's zero-copy slicing path for +//! `Bytes` fields is exercised — the fair comparison point for buffa's +//! view-based zero-copy decode (issue +//! [#56](https://github.com/anthropics/buffa/issues/56)). +//! +//! The substitution applies only to proto `bytes` fields, not `string`s, +//! messages, or scalar repeateds. For schemas without `bytes` fields, decode +//! numbers are expected to track the default-prost crate within noise; the +//! `MediaFrame` message in this benchmark suite is the bytes-heavy case +//! where the substitution actually pays off. + +pub mod bench { + include!(concat!(env!("OUT_DIR"), "/bench.rs")); +} + +pub mod benchmarks { + include!(concat!(env!("OUT_DIR"), "/benchmarks.rs")); + + pub mod proto3 { + include!(concat!(env!("OUT_DIR"), "/benchmarks.proto3.rs")); + } +} diff --git a/benchmarks/prost/benches/protobuf.rs b/benchmarks/prost/benches/protobuf.rs index 9233df8..0a47227 100644 --- a/benchmarks/prost/benches/protobuf.rs +++ b/benchmarks/prost/benches/protobuf.rs @@ -148,12 +148,19 @@ fn bench_google_message1(c: &mut Criterion) { ); } +fn bench_media_frame(c: &mut Criterion) { + let data = include_bytes!("../../datasets/media_frame.pb"); + benchmark_decode::(c, "prost/media_frame", data); + benchmark_json::(c, "prost/media_frame", data); +} + criterion_group!( benches, bench_api_response, bench_log_record, bench_analytics_event, bench_google_message1, + bench_media_frame, ); criterion_main!(benches); diff --git a/benchmarks/proto/bench_messages.proto b/benchmarks/proto/bench_messages.proto index b417722..f3d5710 100644 --- a/benchmarks/proto/bench_messages.proto +++ b/benchmarks/proto/bench_messages.proto @@ -76,3 +76,17 @@ message AnalyticsEvent { } repeated Nested sections = 5; } + +// Binary-payload-heavy message: exercises the `bytes` field type, both as a +// single large blob and as repeated / mapped sub-blobs. Used to contrast +// prost's `prost-build`'s `.bytes(["."])` zero-copy substitution with buffa +// views. +// Target payload: ~3-25KB. +message MediaFrame { + string frame_id = 1; + int64 timestamp_nanos = 2; + string content_type = 3; + bytes body = 4; // primary payload, ~1-10 KB + repeated bytes chunks = 5; // 2-6 sub-chunks, ~200-2000 bytes each + map attachments = 6; // 0-4 named sub-blobs +}