diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index 3f72aba..0000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[alias] -xtask = "run --package xtask --bin xtask --" \ No newline at end of file diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 0b00f8c..4cf17d8 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -3,6 +3,7 @@ name: ๐Ÿงช Audit on: push: branches: + - main - feat/vrd pull_request: branches: @@ -18,6 +19,10 @@ jobs: - uses: hecrj/setup-rust-action@v2 - name: Install cargo-audit run: cargo install cargo-audit - - uses: actions/checkout@master - - name: Audit dependencies + + - uses: actions/checkout@v4 + - name: Resolve dependencies + run: cargo update + + - name: Audit vulnerabilities run: cargo audit diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index ac89aa5..a7b09be 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -3,6 +3,7 @@ name: ๐Ÿงช Check on: push: branches: + - main - feat/vrd pull_request: branches: @@ -18,6 +19,6 @@ jobs: - uses: hecrj/setup-rust-action@v2 with: components: clippy - - uses: actions/checkout@master + - uses: actions/checkout@v4 - name: Check lints run: cargo check --all-targets --workspace --all-features diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..376f33f --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,61 @@ +name: ๐Ÿ“ถ Coverage + +on: + push: + branches: + - main + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + coverage: + name: Code Coverage + runs-on: ubuntu-latest + env: + CARGO_INCREMENTAL: "0" + RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests" + RUSTDOCFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests" + + steps: + # Checkout the repository + - name: Checkout repository + uses: actions/checkout@v4 + + # Setup Rust nightly + - name: Install Rust + uses: actions-rs/toolchain@v1 + id: toolchain + with: + toolchain: nightly + override: true + + # Configure cache for Cargo + - name: Cache Cargo registry, index + uses: actions/cache@v4 + id: cache-cargo + with: + path: | + ~/.cargo/registry + ~/.cargo/bin + ~/.cargo/git + key: linux-${{ steps.toolchain.outputs.rustc_hash }}-rust-cov-${{ hashFiles('**/Cargo.lock') }} + + # Run tests with all features + - name: Test (cargo test) + uses: actions-rs/cargo@v1 + with: + command: test + args: "--workspace" + + # Install grcov + - uses: actions-rs/grcov@v0.1 + id: coverage + + # Upload to Codecov.io + - name: Upload to Codecov.io + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ${{ steps.coverage.outputs.report }} diff --git a/.github/workflows/document.yml b/.github/workflows/document.yml index 9d576cf..6fb477f 100644 --- a/.github/workflows/document.yml +++ b/.github/workflows/document.yml @@ -3,10 +3,12 @@ name: ๐Ÿงช Document on: push: branches: - - main + - feat/vrd pull_request: branches: - - main + - feat/vrd + release: + types: [created] jobs: all: @@ -43,10 +45,10 @@ jobs: retention-days: 1 - name: Write CNAME file - run: echo 'doc.vrdlib.com' > ./target/doc/CNAME + run: echo 'docs.shokunin.one' > ./target/doc/CNAME - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: cname: true commit_message: Deploy documentation at ${{ github.sha }} diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 0000000..5ddbc4a --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,24 @@ +name: ๐Ÿ’พ Format + +on: + push: + branches: + - main + - feat/vrd + pull_request: + branches: + - feat/vrd + release: + types: [created] + +jobs: + all: + name: Format + runs-on: ubuntu-latest + steps: + - uses: hecrj/setup-rust-action@v2 + with: + components: clippy + - uses: actions/checkout@v4 + - name: Check format + run: cargo fmt --all -- --check --verbose \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5969621..a003e04 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -18,6 +18,6 @@ jobs: - uses: hecrj/setup-rust-action@v2 with: components: clippy - - uses: actions/checkout@master + - uses: actions/checkout@v4 - name: Check lints - run: cargo clippy --workspace --all-features --all-targets --no-deps -- -D warnings + run: cargo clippy --workspace --all-features --all-targets --no-deps -- -D warnings \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c57f05a..de58ac8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,19 @@ name: ๐Ÿงช Release -on: [push, pull_request] +on: + push: + branches: + - main + - feat/vrd + pull_request: + branches: + - feat/vrd + release: + types: [created] + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true jobs: # Build the project for all the targets and generate artifacts. @@ -17,113 +30,25 @@ jobs: BUILD_ID: ${{ github.run_id }} CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OS: ${{ matrix.os }} - TARGET: ${{ matrix.target }} + OS: ${{ matrix.platform.os }} + TARGET: ${{ matrix.platform.target }} strategy: fail-fast: false matrix: - target: - # List of targets: - # https://doc.rust-lang.org/nightly/rustc/platform-support.html - - # Tier 1 platforms ๐Ÿ† - - aarch64-unknown-linux-gnu # 64-bit Linux systems on ARM architecture - - i686-pc-windows-gnu # 32-bit Windows (i686-pc-windows-gnu) - - i686-pc-windows-msvc # 32-bit Windows (i686-pc-windows-msvc) - - i686-unknown-linux-gnu # 32-bit Linux (kernel 3.2+, glibc 2.17+) - - x86_64-apple-darwin # 64-bit macOS (10.7 Lion or later) - - x86_64-pc-windows-gnu # 64-bit Windows (x86_64-pc-windows-gnu) - - x86_64-pc-windows-msvc # 64-bit Windows (x86_64-pc-windows-msvc) - - x86_64-unknown-linux-gnu # 64-bit Linux (kernel 2.6.32+, glibc 2.11+) - - # Tier 2 platforms ๐Ÿฅˆ - - aarch64-apple-darwin # 64-bit macOS on Apple Silicon - - aarch64-pc-windows-msvc # 64-bit Windows (aarch64-pc-windows-msvc) - - aarch64-unknown-linux-musl # 64-bit Linux systems on ARM architecture - - arm-unknown-linux-gnueabi # ARMv6 Linux (kernel 3.2, glibc 2.17) - - arm-unknown-linux-gnueabihf # ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) - - armv7-unknown-linux-gnueabihf # ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) - - powerpc-unknown-linux-gnu # PowerPC Linux (kernel 3.2, glibc 2.17) - - powerpc64-unknown-linux-gnu # PowerPC64 Linux (kernel 3.2, glibc 2.17) - - powerpc64le-unknown-linux-gnu # PowerPC64le Linux (kernel 3.2, glibc 2.17) - - riscv64gc-unknown-linux-gnu # RISC-V Linux (kernel 3.2, glibc 2.17) - - s390x-unknown-linux-gnu # s390x Linux (kernel 3.2, glibc 2.17) - - x86_64-unknown-freebsd # 64-bit FreeBSD on x86-64 - - x86_64-unknown-linux-musl # 64-bit Linux (kernel 2.6.32+, musl libc) - - include: - # Tier 1 platforms ๐Ÿ† - - target: aarch64-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: i686-pc-windows-gnu - os: ubuntu-latest - cross: true - - target: i686-pc-windows-msvc + platform: + - target: x86_64-pc-windows-msvc + os: windows-latest + - target: aarch64-pc-windows-msvc os: windows-latest - cross: true - - target: i686-unknown-linux-gnu - os: ubuntu-latest - cross: true - target: x86_64-apple-darwin os: macos-latest - cross: true - - target: x86_64-pc-windows-gnu - os: ubuntu-latest - cross: true - - target: x86_64-pc-windows-msvc - os: windows-latest - cross: true - - target: x86_64-unknown-linux-gnu - os: ubuntu-latest - cross: true - - # Tier 2 platforms ๐Ÿฅˆ - target: aarch64-apple-darwin os: macos-latest - cross: true - - target: aarch64-pc-windows-msvc - os: windows-latest - cross: true - - target: aarch64-unknown-linux-musl - os: ubuntu-latest - cross: true - - target: arm-unknown-linux-gnueabi - os: ubuntu-latest - cross: true - - target: arm-unknown-linux-gnueabihf - os: ubuntu-latest - cross: true - - target: armv7-unknown-linux-gnueabihf - os: ubuntu-latest - cross: true - - target: powerpc-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: powerpc64-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: powerpc64le-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: riscv64gc-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: s390x-unknown-linux-gnu - os: ubuntu-latest - cross: true - - target: x86_64-unknown-freebsd - os: ubuntu-latest - cross: true - - target: x86_64-unknown-linux-musl + - target: x86_64-unknown-linux-gnu os: ubuntu-latest - cross: true - # - target: x86_64-unknown-netbsd - # os: ubuntu-latest - # cross: true - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.platform.os }} steps: # Check out the repository code. @@ -134,42 +59,30 @@ jobs: # Install the stable Rust toolchain. - name: Install stable toolchain id: install-toolchain - uses: dtolnay/rust-toolchain@stable - - # Install the targets for the cross-compilation toolchain - - name: Install target - id: install-target - run: rustup update && rustup target add ${{ env.TARGET }} - - - name: Install Cross and clean artifacts - run: | - # Install cross - cargo install cross - - # Clean the build artifacts - cargo clean --verbose - shell: bash + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true # Cache dependencies to speed up subsequent builds. - name: Cache dependencies id: cache-dependencies uses: actions/cache@v4 with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - target/ - key: release-${{ runner.os }}-cargo-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }} + path: ~/.cargo + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} restore-keys: ${{ runner.os }}-cargo- + # Install the targets for the cross-compilation toolchain + - name: Install target + id: install-target + run: rustup target add ${{ env.TARGET }} + # Build the targets - name: Build targets id: build-targets uses: actions-rs/cargo@v1 with: - use-cross: true command: build args: --verbose --workspace --release --target ${{ env.TARGET }} @@ -177,12 +90,9 @@ jobs: - name: Package the binary id: package-binary run: | - if [[ ! -d "target/package" ]]; then - mkdir -p target/package - fi + mkdir -p target/package tar czf target/package/${{ env.TARGET }}.tar.gz -C target/${{ env.TARGET }}/release . echo "${{ env.TARGET }}.tar.gz=target/package/${{ env.TARGET }}.tar.gz" >> $GITHUB_ENV - shell: bash # Upload the binary for each target - name: Upload the binary @@ -196,7 +106,7 @@ jobs: release: name: โฏ Release ๐Ÿš€ if: github.ref == 'refs/heads/main' && github.event_name == 'push' - needs: [build] + needs: build runs-on: ubuntu-latest steps: # Check out the repository code @@ -205,7 +115,10 @@ jobs: # Install the stable Rust toolchain - name: Install stable toolchain - uses: dtolnay/rust-toolchain@stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true # Update the version number based on the Cargo.toml file - name: Update version number @@ -229,6 +142,7 @@ jobs: echo "Downloading $target artifact" name="${target}.tar.gz" echo "Artifact name: $name" + mkdir -p target/package curl -sSL -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github.v3+json" -L "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/runs/${BUILD_ID}/artifacts/${name}" -o "target/package/${name}" done @@ -243,7 +157,7 @@ jobs: env: BUILD_ID: ${{ github.run_id }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RELEASE_URL: https://github.com/sebastienrousseau/rlg/releases + RELEASE_URL: https://github.com/sebastienrousseau/vrd/releases TARGET: ${{ env.TARGET }} run: | @@ -278,7 +192,7 @@ jobs: VERSION: ${{ env.VERSION }} with: tag_name: v${{ env.VERSION }} - release_name: Random (VRD) v${{ env.VERSION }} + release_name: Random (VRD) ๐Ÿฆ€ v${{ env.VERSION }} body_path: ${{ github.workspace }}/CHANGELOG.md draft: true prerelease: false @@ -287,7 +201,7 @@ jobs: crate: name: โฏ Crate.io ๐Ÿฆ€ if: github.ref == 'refs/heads/main' && github.event_name == 'push' - needs: [release] + needs: release runs-on: ubuntu-latest steps: @@ -298,7 +212,10 @@ jobs: # Install the stable Rust toolchain - name: Install stable toolchain id: install-toolchain - uses: dtolnay/rust-toolchain@stable + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true # Cache dependencies to speed up subsequent builds - name: Cache dependencies @@ -325,7 +242,7 @@ jobs: # Publish the Rust library to Crate.io - name: Publish Library to Crate.io id: publish-library - uses: actions-rs/cargo@v1.0.1 + uses: actions-rs/cargo@v1 env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }} with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b648042..ef30ba6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: steps: # Checkout the repository - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Setup Rust - name: Setup Rust @@ -24,7 +24,7 @@ jobs: # Configure cache - name: Configure cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cargo/bin/ @@ -38,28 +38,3 @@ jobs: - name: Run tests with all features id: run-tests-all-features run: cargo test --verbose --workspace --all-features - - # Install grcov - - name: Install grcov - # Only run this job on the main branch when a commit is pushed. - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - id: install-grcov - run: | - mkdir -p "${HOME}/.local/bin" - curl -sL https://github.com/mozilla/grcov/releases/download/v0.8.19/grcov-x86_64-unknown-linux-gnu.tar.bz2 | tar jxf - -C "${HOME}/.local/bin" - echo "$HOME/.local/bin" >> $GITHUB_PATH - - # Use grcov to generate a coverage report - - name: Generate coverage report - # Only run this job on the main branch when a commit is pushed. - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - run: | - cargo xtask coverage - - # Upload the coverage report to codecov - - name: Upload coverage report to codecov - # Only run this job on the main branch when a commit is pushed. - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - uses: codecov/codecov-action@v4 - with: - files: coverage/*.lcov diff --git a/.gitignore b/.gitignore index 76bdd1b..6cf971d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ build Icon? src/.DS_Store tarpaulin-report.html +Cargo.lock +config.json \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 64e6783..85c69c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -34,15 +34,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" - -[[package]] -name = "anyhow" -version = "1.0.80" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "assert_cmd" @@ -59,28 +53,17 @@ dependencies = [ "wait-timeout", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -93,15 +76,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bstr" @@ -116,15 +93,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cast" @@ -134,9 +111,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.90" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" [[package]] name = "cfg-if" @@ -173,24 +150,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex 0.2.4", - "indexmap", - "strsim", - "termcolor", - "textwrap", -] - -[[package]] -name = "clap" -version = "4.5.2" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", ] @@ -202,16 +164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstyle", - "clap_lex 0.7.0", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", + "clap_lex", ] [[package]] @@ -220,19 +173,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" -[[package]] -name = "console" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "unicode-width", - "windows-sys 0.52.0", -] - [[package]] name = "criterion" version = "0.5.1" @@ -242,7 +182,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.2", + "clap", "criterion-plot", "is-terminal", "itertools", @@ -300,41 +240,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "darling" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 1.0.109", -] - -[[package]] -name = "darling_macro" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" -dependencies = [ - "darling_core", - "quote", - "syn 1.0.109", -] - [[package]] name = "deranged" version = "0.3.11" @@ -344,49 +249,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "derive_builder" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "derive_builder_macro" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" -dependencies = [ - "derive_builder_core", - "syn 1.0.109", -] - -[[package]] -name = "dialoguer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" -dependencies = [ - "console", - "shell-words", - "tempfile", - "zeroize", -] - [[package]] name = "difflib" version = "0.4.0" @@ -410,63 +272,17 @@ dependencies = [ "time", ] -[[package]] -name = "duct" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ab5718d1224b63252cd0c6f74f6480f9ffeb117438a2e0f5cf6d9a4798929c" -dependencies = [ - "libc", - "once_cell", - "os_pipe", - "shared_child", -] - [[package]] name = "either" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "fnv" -version = "1.0.7" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -479,37 +295,16 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "half" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.9" @@ -527,29 +322,13 @@ dependencies = [ "winapi", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - [[package]] name = "is-terminal" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", "windows-sys 0.52.0", ] @@ -565,9 +344,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" @@ -578,29 +357,17 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -620,9 +387,9 @@ checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "miniz_oxide" @@ -652,9 +419,9 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -665,7 +432,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] @@ -690,27 +457,11 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "os_pipe" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "os_str_bytes" -version = "6.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" - [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -718,22 +469,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "plotters" @@ -804,18 +555,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -852,9 +603,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -872,18 +623,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -904,9 +655,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rlg" @@ -927,19 +678,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustix" -version = "0.38.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" -dependencies = [ - "bitflags 2.4.2", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - [[package]] name = "ryu" version = "1.0.17" @@ -963,9 +701,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" dependencies = [ "serde_derive", ] @@ -981,133 +719,73 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", "serde", ] -[[package]] -name = "shared_child" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "shell-words" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" - [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", ] -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" -version = "2.0.52" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "termtree" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" -[[package]] -name = "textwrap" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" - [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "num-conv", @@ -1134,9 +812,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -1159,7 +837,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn", ] [[package]] @@ -1168,17 +846,11 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", ] @@ -1195,9 +867,10 @@ dependencies = [ [[package]] name = "vrd" -version = "0.0.6" +version = "0.0.7" dependencies = [ "assert_cmd", + "bitflags", "criterion", "dtt", "rand", @@ -1255,7 +928,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn", "wasm-bindgen-shared", ] @@ -1277,7 +950,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1316,11 +989,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -1344,7 +1017,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1364,17 +1037,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -1385,9 +1059,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -1397,9 +1071,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -1409,9 +1083,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -1421,9 +1101,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -1433,9 +1113,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -1445,9 +1125,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -1457,35 +1137,6 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" - -[[package]] -name = "xtask" -version = "0.2.0" -dependencies = [ - "anyhow", - "xtaskops", -] - -[[package]] -name = "xtaskops" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464ca5c2bac1d1fcdbef9da6c09c6a14f2c7ac6c8845f574ab12065a2b72bb8b" -dependencies = [ - "anyhow", - "clap 3.2.25", - "derive_builder", - "dialoguer", - "duct", - "fs_extra", - "glob", -] - -[[package]] -name = "zeroize" -version = "1.7.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/Cargo.toml b/Cargo.toml index df9a33b..95bcd67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [package] +# Metadata about the package. authors = ["The vrd contributors "] build = "build.rs" categories = ['Algorithms', 'Encoding','Parser implementations','Data structures'] @@ -12,6 +13,8 @@ exclude = [ "/.vscode/*" ] homepage = "https://vrdlib.com" + +# Included and excluded files include = [ "/CONTRIBUTING.md", "/LICENSE-APACHE", @@ -22,39 +25,40 @@ include = [ "/examples/**", "/README.md", "/src/**", - "/tests/**", - "/xtask/**", + "/tests/**" ] keywords = ["entropy", "rand", "random-number", "random", "vrd"] license = "MIT OR Apache-2.0" name = "vrd" readme = "README.md" repository = "https://github.com/sebastienrousseau/vrd" -rust-version = "1.71.1" -version = "0.0.6" - -[workspace] -members = ["xtask"] +rust-version = "1.60" +version = "0.0.7" [[bench]] +# [[bench]] sections define benchmarks. name = "benchmark" harness = false path = "benches/criterion.rs" [profile.bench] +# Profile for benchmarks. debug = true [dependencies] +# Dependencies are only used for building. +bitflags = "2.5.0" dtt = "0.0.5" rand = "0.8.5" rlg = "0.0.3" -serde = { version = "1.0.197", features = ["derive"] } -serde_json = "1.0.114" +serde = { version = "1.0.200", features = ["derive"] } +serde_json = "1.0.116" serde-big-array = "0.5.1" -tokio = { version = "1.36.0", features = ["full"] } -uuid ={ version = "1.7.0", features = ["v4"] } +tokio = { version = "1.37.0", features = ["full"] } +uuid ={ version = "1.8.0", features = ["v4"] } [dev-dependencies] +# Development dependencies are only used for testing and building. assert_cmd = "2.0.14" criterion = "0.5.1" @@ -64,10 +68,67 @@ name = "vrd" path = "src/lib.rs" [features] +# No default features default = [] [package.metadata.docs.rs] -all-features = true +targets = ["x86_64-unknown-linux-gnu"] +rustdoc-args = ["--generate-link-to-definition"] + +# Linting config +[lints.rust] + +## Warn +# box_pointers = "warn" +# missing_copy_implementations = "warn" +# missing_docs = "warn" +# unstable_features = "warn" +# unused_crate_dependencies = "warn" +# unused_extern_crates = "warn" +# unused_results = "warn" + +## Allow +bare_trait_objects = "allow" +elided_lifetimes_in_paths = "allow" +non_camel_case_types = "allow" +non_upper_case_globals = "allow" +trivial_bounds = "allow" +unsafe_code = "allow" + +## Forbid +missing_debug_implementations = "forbid" +# missing_docs = "warn" +non_ascii_idents = "forbid" +unreachable_pub = "forbid" + +## Deny +dead_code = "deny" +deprecated_in_future = "deny" +ellipsis_inclusive_range_patterns = "deny" +explicit_outlives_requirements = "deny" +future_incompatible = { level = "deny", priority = -1 } +keyword_idents = "deny" +macro_use_extern_crate = "deny" +meta_variable_misuse = "deny" +missing_fragment_specifier = "deny" +noop_method_call = "deny" +pointer_structural_match = "deny" +rust_2018_idioms = { level = "deny", priority = -1 } +rust_2021_compatibility = { level = "deny", priority = -1 } +single_use_lifetimes = "deny" +trivial_casts = "deny" +trivial_numeric_casts = "deny" +unused = { level = "deny", priority = -1 } +unused_features = "deny" +unused_import_braces = "deny" +unused_labels = "deny" +unused_lifetimes = "deny" +unused_macro_rules = "deny" +unused_qualifications = "deny" +variant_size_differences = "deny" + +[package.metadata.clippy] +warn-lints = ["clippy::all", "clippy::pedantic", "clippy::cargo", "clippy::nursery"] [profile.dev] codegen-units = 256 @@ -102,4 +163,4 @@ lto = false opt-level = 0 overflow-checks = true rpath = false -strip = false +strip = false \ No newline at end of file diff --git a/README.md b/README.md index 2718b07..b7513eb 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Add the following to your `Cargo.toml` file: ```toml [dependencies] -vrd = "0.0.6" +vrd = "0.0.7" serde = { version = "1.0.160", features = ["derive"] } ``` diff --git a/benches/criterion.rs b/benches/criterion.rs index 244c966..7c91ec4 100644 --- a/benches/criterion.rs +++ b/benches/criterion.rs @@ -30,12 +30,12 @@ //! criterion_group!(benches, benchmark_random); //! criterion_main!(benches); //! ``` -extern crate criterion; -extern crate vrd; +#![allow(missing_docs)] use self::vrd::random::Random; use criterion::{ black_box, criterion_group, criterion_main, Criterion, }; +use vrd; /// Benchmarks the random number generation functions provided by the `Random` trait. /// diff --git a/examples/example.rs b/examples/example.rs index 4801b63..0b7f037 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -9,38 +9,88 @@ //! It covers a variety of functionalities provided by the `vrd` crate, including generating //! random booleans, integers, floating-point numbers, and more complex operations like seeding //! and state manipulation of the random number generator (RNG). - -extern crate vrd; -use self::vrd::random::Random; -use vrd::*; +//! +//! ## Examples +//! +//! ### Basic Number Generation +//! +//! - Generating a random number: Demonstrates how to generate a random number using the `rand` method. +//! +//! - Generating a random double-precision floating-point number: Shows how to generate a random floating-point number within the range [0.0, 1.0). +//! +//! - Generating random integers: Shows various ways to generate random integers within different ranges. +//! +//! - Generating random booleans: Demonstrates how to generate random boolean values with customizable probabilities. +//! +//! - Generating random bytes: Shows how to generate random byte sequences of specified lengths. +//! +//! - Generating random characters and strings: Illustrates how to generate random characters and strings of specified lengths. +//! +//! ### Advanced PRNG Usage +//! +//! - Seeding the RNG: Illustrates how to seed the random number generator with a specific value to ensure reproducible results. +//! +//! - Custom Mersenne Twister configuration: Shows how to create a custom configuration for the Mersenne Twister RNG and serialize it to a file. +//! +//! - Altering the state of the PRNG: Demonstrates how seeding, twisting, and retrieving the MTI can be combined to control sequences of random numbers reproducibly. +//! +//! ### Shuffling and Sampling +//! +//! - Shuffling and sampling: Shows how to shuffle and sample elements from slices using the `shuffle`, `sample`, and `sample_with_replacement` methods. +//! +//! ### Serialization and Deserialization with Error Handling +//! +//! - Serialization and deserialization: Demonstrates how to serialize and deserialize the random number generator state to/from JSON, incorporating error handling. +//! +//! ### Miscellaneous Examples +//! +//! - Comparing `vrd` RNG with Rust's default RNG: Compares the random number generated by `vrd` RNG with Rust's default RNG. + +use vrd::mersenne_twister::{ + MersenneTwisterConfig, MersenneTwisterParams, +}; +use vrd::random::Random; +use vrd::{ + rand_bool, rand_bytes, rand_char, rand_choose, rand_float, + rand_int, rand_pseudo, rand_range, rand_seed, rand_twist, + random_range, +}; fn main() { - // Generating a random boolean with a 50% chance of being true. - // This demonstrates the usage of Random::bool method. - let bool: bool = Random::bool(&mut Random::new(), 0.5); - println!("๐Ÿฆ€ Random::bool(): โœ… {bool}"); + // ... Basic Number Generation Examples ... // Initializing a new random number generator (RNG) instance. - let mut rng = Random::new(); + let mut rng = Random::from_entropy(); println!("๐Ÿฆ€ Random::new(): โœ… {rng}"); // Accessing the default RNG provided by the `vrd` crate. let default = Random::default(); println!("๐Ÿฆ€ Random::default(): โœ… {default}"); - // Generating a random integer between 0 and the maximum value a u32 can hold. - let random = rng.rand(); - println!("๐Ÿฆ€ Random::random(): โœ… {random}"); - // Seeding the RNG with a specific value to ensure reproducible results. let seed_value = 12345; - let mut rng = Random::new(); rng.seed(seed_value); println!("๐Ÿฆ€ Random::seed(): โœ… {}", seed_value); - // Creating a vector of 1000 random bytes. - let bytes = Random::bytes(&mut rng, 1000); - println!("๐Ÿฆ€ Random::bytes(): โœ… {bytes:?}"); + // Generating a random integer between 0 and the maximum value a u32 can hold. + let random = rng.rand(); + println!("๐Ÿฆ€ Random::random(): โœ… {random}"); + + // Generating a random double-precision floating-point number. + let random_double = Random::double(&mut rng); + println!("๐Ÿฆ€ Random::double(): โœ… {}", random_double); + + // Generating a random 64-bit signed integer. + let random_i64 = rng.i64(); + println!("๐Ÿฆ€ Random::i64(): โœ… {}", random_i64); + + // Generating a random 64-bit unsigned integer. + let random_u64 = rng.u64(); + println!("๐Ÿฆ€ Random::u64(): โœ… {}", random_u64); + + // Generating a random 64-bit floating-point number. + let random_f64 = rng.f64(); + println!("๐Ÿฆ€ Random::f64(): โœ… {}", random_f64); // Generating a random floating-point number between 0 and 1. let float = rng.rand() as f32 / 0x7FFF as f32; @@ -51,19 +101,35 @@ fn main() { println!("๐Ÿฆ€ Random::int(): โœ… {int}"); // Generating a random integer within the specified range (0 to 100). - let mut rng = Random::new(); let min = 0; let max = 100; let rand_int = rand_int!(rng, min, max); - println!("๐Ÿฆ€ Random integer between {} and {}: {}", min, max, rand_int); + println!( + "๐Ÿฆ€ Random integer between {} and {}: {}", + min, max, rand_int + ); + + // Generating a random number within a specified range using the `rand_range` macro. + let rand_range_macro = rand_range!(rng, 10, 20); + println!( + "๐Ÿฆ€ Random number between 10 and 20: {}", + rand_range_macro + ); // Generating a random floating-point number within a specified range. - let rand_range = rand_float!(rng) * (max as f32 - min as f32) + min as f32; - println!("๐Ÿฆ€ Random number between 0 and 1: {}", rand_range); + let rand_range = + rand_float!(rng) * (max as f32 - min as f32) + min as f32; + println!( + "๐Ÿฆ€ Random number between {} and {}: {}", + min, max, rand_range + ); // Creating a random 32-bit unsigned integer within a specified range. - let rand_uint = random_range!(rng, 0, u32::max_value()); - println!("๐Ÿฆ€ Random u32 between 0 and u32::max_value(): {}", rand_uint); + let rand_uint = random_range!(rng, 0, u32::MAX); + println!( + "๐Ÿฆ€ Random u32 between 0 and u32::max_value(): {}", + rand_uint + ); // Generating a random boolean with a 50% probability. let rand_bool = rand_bool!(rng, 0.5); @@ -73,18 +139,55 @@ fn main() { let rand_bytes = rand_bytes!(rng, 10); println!("๐Ÿฆ€ Random bytes: {:?}", rand_bytes); + // Creating a vector of 1000 random bytes. + let bytes = Random::bytes(&mut rng, 1000); + println!("๐Ÿฆ€ Random::bytes(): โœ… {bytes:?}"); + // Generating a random character within the range 'a' to 'z'. let rand_char = rand_char!(rng); println!("๐Ÿฆ€ Random char between 'a' and 'z': {}", rand_char); + // Generating a random string of length 10. + let random_string = rng.string(10); + println!("๐Ÿฆ€ Random string: {}", random_string); + // Picking a random element from a predefined slice of integers. let values = &[1, 2, 3, 4, 5]; let rand_choose = rand_choose!(rng, values); - println!("๐Ÿฆ€ Random element from [1, 2, 3, 4, 5]: {:?}", rand_choose); - - // Generating a random floating-point number. - let rand_float = rand_float!(rng); - println!("๐Ÿฆ€ Random float: {}", rand_float); + println!( + "๐Ÿฆ€ Random element from [1, 2, 3, 4, 5]: {:?}", + rand_choose + ); + + // ... Shuffling and Sampling Examples ... + // Example of using the `rand_slice` function to generate a random subslice from a given slice. + // This can be useful for selecting random samples from a larger dataset. + let rand_slice = Random::rand_slice(&mut rng, values, 3); + println!("๐Ÿฆ€ Random sub-slice of length 3: {:?}", rand_slice); + + // Example of using the `shuffle` method to randomly shuffle a mutable slice. + let mut shuffle_values = [1, 2, 3, 4, 5]; + Random::shuffle(&mut rng, &mut shuffle_values); + println!("๐Ÿฆ€ Shuffled slice: {:?}", shuffle_values); + + // Example of using the `sample` method to randomly sample elements from a slice without replacement. + let samples = Random::sample(&mut rng, values, 3); + println!("๐Ÿฆ€ Random samples without replacement: {:?}", samples); + + // Example of using the `sample_with_replacement` method to randomly sample elements from a slice with replacement. + let samples_with_replacement = + Random::sample_with_replacement(&mut rng, values, 3); + println!( + "๐Ÿฆ€ Random samples with replacement: {:?}", + samples_with_replacement + ); + + // Example of using the `fill` method to fill a mutable slice with random values. + let mut buffer = [0; 10]; + Random::fill(&mut rng, &mut buffer); + println!("๐Ÿฆ€ Filled buffer with random values: {:?}", buffer); + + // ... PRNG Examples ... // Creating a random 32-bit unsigned integer using a pseudo-random number generator (PRNG). let rand_pseudo = rand_pseudo!(rng); @@ -98,18 +201,18 @@ fn main() { // Altering the state of the PRNG to vary its output. rand_twist!(rng); let rand_twist = rand_pseudo!(rng); - println!("๐Ÿฆ€ Random u32 after twisting the PRNG state: {}", rand_twist); - - // Generating a random double-precision floating-point number. - let random_double = Random::double(&mut rng); - println!("๐Ÿฆ€ Random double: {}", random_double); + println!( + "๐Ÿฆ€ Random u32 after twisting the PRNG state: {}", + rand_twist + ); // Retrieving the current state index (MTI) of the Mersenne Twister RNG. let mti_value = Random::mti(&rng); println!("๐Ÿฆ€ MTI value: {}", mti_value); // Generate a random even number. - let even_number = (0..).map(|_| rng.rand()).find(|&n| n % 2 == 0).unwrap(); + let even_number = + (0..).map(|_| rng.rand()).find(|&n| n % 2 == 0).unwrap(); println!("๐Ÿฆ€ Random even number: {}", even_number); // Pre-generating a large number of random values for performance. @@ -117,34 +220,69 @@ fn main() { for _ in 0..1000 { pre_generated_numbers.push(rng.rand()); } - println!("๐Ÿฆ€ Pre-generated random numbers: {:?}", pre_generated_numbers); + println!( + "๐Ÿฆ€ Pre-generated random numbers: {:?}", + pre_generated_numbers + ); // Comparing `vrd` RNG with Rust's default RNG. let default_rng_number = rand::random::(); let vrd_rng_number = rng.rand(); - println!("๐Ÿฆ€ Default RNG number: {}, `vrd` RNG number: {}", default_rng_number, vrd_rng_number); - - // Serialize the random number generator to JSON - let serialized_rng = serde_json::to_string(&rng).unwrap(); - println!("๐Ÿฆ€ Serialized RNG: {}", serialized_rng); - - // Deserialize the random number generator from JSON - let deserialized_rng: Random = serde_json::from_str(&serialized_rng).unwrap(); - println!("๐Ÿฆ€ Deserialized RNG: {:?}", deserialized_rng); - - // Generating a random 64-bit signed integer. - let random_i64 = rng.i64(); - println!("๐Ÿฆ€ Random i64: {}", random_i64); + println!( + "๐Ÿฆ€ Default RNG number: {}, `vrd` RNG number: {}", + default_rng_number, vrd_rng_number + ); + + // ... Serialization Examples ... + // Serialize the random number generator to JSON. + let serialized_rng = serde_json::to_string(&rng); + match serialized_rng { + Ok(ref serialized) => { + println!("๐Ÿฆ€ Serialized RNG: {}", serialized) + } + Err(ref e) => eprintln!("๐Ÿ”ด Serialization error: {}", e), + } - // Generating a random 64-bit unsigned integer. - let random_u64 = rng.u64(); - println!("๐Ÿฆ€ Random u64: {}", random_u64); + // Deserialize the random number generator from JSON. + let deserialized_rng: Result = + serde_json::from_str(&serialized_rng.unwrap()); + match deserialized_rng { + Ok(deserialized) => { + println!("๐Ÿฆ€ Deserialized RNG: {:?}", deserialized) + } + Err(e) => eprintln!("๐Ÿ”ด Deserialization error: {}", e), + } - // Generating a random 64-bit floating-point number. - let random_f64 = rng.f64(); - println!("๐Ÿฆ€ Random f64: {}", random_f64); + // Creating a custom Mersenne Twister configuration. + let params = MersenneTwisterParams { + matrix_a: 0x9908b0df, + upper_mask: 0x80000000, + lower_mask: 0x7fffffff, + tempering_mask_b: 0x9d2c5680, + tempering_mask_c: 0xefc60000, + }; + + // Creating a custom Mersenne Twister configuration. + let config = MersenneTwisterConfig::new_custom(624, 397, params); + println!("๐Ÿฆ€ Custom MersenneTwisterConfig: {}", config); + + // Serialize to a file + if let Err(e) = + MersenneTwisterConfig::serialize_to_file(&config, "config.json") + { + eprintln!("๐Ÿ”ด Error serializing to file: {}", e); + } else { + println!("๐Ÿฆ€ Serialized MersenneTwisterConfig to file"); + } - // Generating a random string of length 10. - let random_string = rng.string(10); - println!("๐Ÿฆ€ Random string: {}", random_string); + // Deserialize from a file + let deserialized_config = + MersenneTwisterConfig::deserialize_from_file("config.json"); + match deserialized_config { + Ok(deserialized) => println!( + "๐Ÿฆ€ Deserialized MersenneTwisterConfig from file: {:?}", + deserialized + ), + Err(e) => eprintln!("๐Ÿ”ด Deserialization error: {}", e), + } } diff --git a/src/lib.rs b/src/lib.rs index cf49ddb..cee8d88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ //! //! ```toml //! [dependencies] -//! vrd = "0.0.6" +//! vrd = "0.0.7" //! serde = { version = "1.0.160", features = ["derive"] } //! ``` //! @@ -92,11 +92,6 @@ //! [0]: https://minifunctions.com/vrd //! #![cfg_attr(feature = "bench", feature(test))] -#![deny(dead_code)] -#![deny(missing_debug_implementations)] -#![deny(missing_docs)] -#![forbid(unsafe_code)] -#![warn(unreachable_pub)] #![doc( html_favicon_url = "https://kura.pro/vrd/images/favicon.ico", html_logo_url = "https://kura.pro/vrd/images/logos/vrd.svg", @@ -163,9 +158,9 @@ pub fn create_log_entry( } /// Log an entry asynchronously. -pub async fn log_entry_async(entry: Log) { - entry - .log() - .await - .unwrap_or_else(|e| eprintln!("Failed to log entry: {}", e)); +pub async fn log_entry_async( + entry: Log, +) -> Result<(), Box> { + entry.log().await?; + Ok(()) } diff --git a/src/main.rs b/src/main.rs index 510bef8..b6ec1a1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,42 @@ // This file is part of the `Random (VRD)` library, a Rust implementation of the Mersenne Twister RNG. // See LICENSE-APACHE.md and LICENSE-MIT.md in the repository root for full license information. +//! # Random (VRD) Library +//! +//! The `Random (VRD)` library is a Rust implementation of the Mersenne Twister random number generator. +//! It provides functionality for generating random numbers and performing various operations related to randomness. +//! +//! ## Features +//! +//! - Mersenne Twister random number generation +//! - UUID generation +//! - DateTime creation +//! - Logging with configurable log levels +//! +//! ## Usage +//! +//! Add the following to your `Cargo.toml` file: +//! +//! ```toml +//! [dependencies] +//! vrd = "0.0.1" +//! ``` +//! +//! Then, use the library in your Rust code: +//! +//! ```rust +//! use vrd::{create_log_entry, log_entry_async, run}; +//! ``` +//! +//! For more detailed usage and examples, please refer to the documentation of individual modules and functions. +//! +//! ## License +//! +//! This library is licensed under either of the following, at your option: +//! +//! - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE.md)) +//! - MIT License ([LICENSE-MIT](LICENSE-MIT.md)) +//! use dtt::DateTime; use rlg::log_level::LogLevel; use std::process; @@ -39,7 +75,18 @@ fn main() { &error_message, ); - runtime.block_on(async { log_entry_async(log_entry).await }); + match runtime + .block_on(async { log_entry_async(log_entry).await }) + { + Ok(_) => { + // Logging successful + println!("Error logged successfully."); + } + Err(e) => { + // Logging failed + eprintln!("Failed to log error: {}", e); + } + } process::exit(1); } diff --git a/src/mersenne_twister.rs b/src/mersenne_twister.rs index 7cae969..821d5b8 100644 --- a/src/mersenne_twister.rs +++ b/src/mersenne_twister.rs @@ -3,34 +3,83 @@ // This file is part of the `Random (VRD)` library, a Rust implementation of the Mersenne Twister RNG. // See LICENSE-APACHE.md and LICENSE-MIT.md in the repository root for full license information. -use std::fmt; use serde::{Deserialize, Serialize}; +use std::{ + fmt, + fs::File, + io::{BufReader, BufWriter}, +}; + +/// Configuration parameters for the Mersenne Twister algorithm. +/// +/// This struct contains the constant values required for the Mersenne Twister algorithm. +/// +/// # Fields +/// +/// - `matrix_a`: A constant value used in the Mersenne Twister algorithm. It must have its highest bit set (0x80000000). +/// - `upper_mask`: A constant value used for masking the upper bits of the generated values (0x80000000). +/// - `lower_mask`: A constant value used for masking the lower bits of the generated values (0x7fffffff). +/// - `tempering_mask_b`: A constant value used for tempering the generated values (0x9d2c5680). +/// - `tempering_mask_c`: A constant value used for tempering the generated values (0xefc60000). +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + Serialize, + Deserialize, + Hash, + PartialOrd, + Ord, +)] +pub struct MersenneTwisterParams { + /// A constant value used in the Mersenne Twister algorithm. It must have its highest bit set (0x80000000). + pub matrix_a: u32, + /// A constant value used for masking the upper bits of the generated values (0x80000000). + pub upper_mask: u32, + /// A constant value used for masking the lower bits of the generated values (0x7fffffff). + pub lower_mask: u32, + /// A constant value used for tempering the generated values (0x9d2c5680). + pub tempering_mask_b: u32, + /// A constant value used for tempering the generated values (0xefc60000). + pub tempering_mask_c: u32, +} /// Configuration for the Mersenne Twister algorithm. -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +/// +/// This struct contains the configurable parameters for the Mersenne Twister algorithm. +/// +/// # Fields +/// +/// - `n`: The number of elements in the array used for the Mersenne Twister algorithm. Its value is set to 624 for optimal performance. Must be at least 1. +/// - `m`: The number of elements to skip in the array used for the Mersenne Twister algorithm. Its value is set to 397 for optimal performance. Must be at least 1 and less than `n`. +/// - `params`: An instance of `MersenneTwisterParams` containing the constant values for the Mersenne Twister algorithm. +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + Serialize, +)] pub struct MersenneTwisterConfig { /// The number of elements in the array used for the Mersenne Twister algorithm. /// Its value is set to 624 for optimal performance. + /// Must be at least 1. pub n: usize, /// The number of elements to skip in the array used for the Mersenne Twister algorithm. /// Its value is set to 397 for optimal performance. + /// Must be at least 1 and less than `n`. pub m: usize, - /// A constant value used in the Mersenne Twister algorithm. - pub matrix_a: u32, - - /// A constant value used in the Mersenne Twister algorithm. - pub upper_mask: u32, - - /// A constant value used in the Mersenne Twister algorithm. - pub lower_mask: u32, - - /// A constant value used in the Mersenne Twister algorithm. - pub tempering_mask_b: u32, - - /// A constant value used in the Mersenne Twister algorithm. - pub tempering_mask_c: u32, + /// Configuration parameters for the Mersenne Twister algorithm. + pub params: MersenneTwisterParams, } /// Implementation of the `MersenneTwisterConfig` struct. @@ -41,11 +90,7 @@ impl MersenneTwisterConfig { /// /// * `n` - The number of elements in the array. /// * `m` - The number of elements to skip. - /// * `matrix_a` - Constant value used in the algorithm. - /// * `upper_mask` - Constant value used in the algorithm. - /// * `lower_mask` - Constant value used in the algorithm. - /// * `tempering_mask_b` - Constant value used in the algorithm. - /// * `tempering_mask_c` - Constant value used in the algorithm. + /// * `params` - Configuration parameters for the Mersenne Twister algorithm. /// /// # Panics /// @@ -54,37 +99,66 @@ impl MersenneTwisterConfig { /// # Example /// /// ``` - /// use vrd::mersenne_twister::MersenneTwisterConfig; + /// use vrd::mersenne_twister::{MersenneTwisterConfig, MersenneTwisterParams}; + /// + /// let params = MersenneTwisterParams { + /// matrix_a: 0x9908b0df, + /// upper_mask: 0x80000000, + /// lower_mask: 0x7fffffff, + /// tempering_mask_b: 0x9d2c5680, + /// tempering_mask_c: 0xefc60000, + /// }; /// - /// let config = MersenneTwisterConfig::new_custom( - /// 624, // n - /// 397, // m - /// 0x9908b0df, // matrix_a - /// 0x80000000, // upper_mask - /// 0x7fffffff, // lower_mask - /// 0x9d2c5680, // tempering_mask_b - /// 0xefc60000 // tempering_mask_c - /// ); + /// let config = MersenneTwisterConfig::new_custom(624, 397, params); /// ``` pub fn new_custom( n: usize, m: usize, - matrix_a: u32, - upper_mask: u32, - lower_mask: u32, - tempering_mask_b: u32, - tempering_mask_c: u32, + params: MersenneTwisterParams, ) -> MersenneTwisterConfig { - MersenneTwisterConfig::validate(n, m, matrix_a, upper_mask, lower_mask, tempering_mask_b, tempering_mask_c); - MersenneTwisterConfig { - n, - m, - matrix_a, - upper_mask, - lower_mask, - tempering_mask_b, - tempering_mask_c, - } + MersenneTwisterConfig::validate(n, m, ¶ms); + MersenneTwisterConfig { n, m, params } + } + + /// Sets all the fields of the `MersenneTwisterConfig` struct at once. + /// + /// # Arguments + /// + /// * `n` - The number of elements in the array. + /// * `m` - The number of elements to skip. + /// * `params` - Configuration parameters for the Mersenne Twister algorithm. + /// + /// # Panics + /// + /// This function panics if any of the provided parameters are outside of their valid range. + /// + /// # Example + /// + /// ``` + /// use vrd::mersenne_twister::{MersenneTwisterConfig, MersenneTwisterParams}; + /// + /// let mut config = MersenneTwisterConfig::new(); + /// + /// let params = MersenneTwisterParams { + /// matrix_a: 0x9908b0df, + /// upper_mask: 0x80000000, + /// lower_mask: 0x7fffffff, + /// tempering_mask_b: 0x9d2c5680, + /// tempering_mask_c: 0xefc60000, + /// }; + /// + /// config.set_config(1000, 500, params); + /// ``` + pub fn set_config( + &mut self, + n: usize, + m: usize, + params: MersenneTwisterParams, + ) { + MersenneTwisterConfig::validate(n, m, ¶ms); + self.n = n; + self.m = m; + self.params = params; } /// Validates the parameters for a MersenneTwisterConfig. @@ -92,14 +166,37 @@ impl MersenneTwisterConfig { /// # Panics /// /// This function panics if any of the provided parameters are outside of their valid range. - fn validate(n: usize, m: usize, matrix_a: u32, upper_mask: u32, lower_mask: u32, tempering_mask_b: u32, tempering_mask_c: u32) { + pub fn validate( + n: usize, + m: usize, + params: &MersenneTwisterParams, + ) { assert!(n >= 1, "n must be at least 1"); - assert!(m >= 1 && m < n, "m must be at least 1 and less than n"); - assert_eq!(matrix_a & 0x80000000, 0x80000000, "matrix_a must have its highest bit set"); - assert_eq!(upper_mask, 0x80000000, "upper_mask must be a valid 32-bit unsigned integer"); - assert_eq!(lower_mask, 0x7fffffff, "lower_mask must be a valid 32-bit unsigned integer"); - assert_eq!(tempering_mask_b, 0x9d2c5680, "tempering_mask_b must be a valid 32-bit unsigned integer"); - assert_eq!(tempering_mask_c, 0xefc60000, "tempering_mask_c must be a valid 32-bit unsigned integer"); + assert!( + m >= 1 && m < n, + "m must be at least 1 and less than n" + ); + assert_eq!( + params.matrix_a & 0x80000000, + 0x80000000, + "matrix_a must have its highest bit set" + ); + assert_eq!( + params.upper_mask, 0x80000000, + "upper_mask must be a valid 32-bit unsigned integer" + ); + assert_eq!( + params.lower_mask, 0x7fffffff, + "lower_mask must be a valid 32-bit unsigned integer" + ); + assert_eq!( + params.tempering_mask_b, 0x9d2c5680, + "tempering_mask_b must be a valid 32-bit unsigned integer" + ); + assert_eq!( + params.tempering_mask_c, 0xefc60000, + "tempering_mask_c must be a valid 32-bit unsigned integer" + ); } /// Creates a new `MersenneTwisterConfig` with default values. @@ -122,15 +219,14 @@ impl MersenneTwisterConfig { /// let config = MersenneTwisterConfig::new(); /// ``` pub fn new() -> MersenneTwisterConfig { - MersenneTwisterConfig::new_custom( - 624, - 397, - 0x9908b0df, - 0x80000000, - 0x7fffffff, - 0x9d2c5680, - 0xefc60000, - ) + let params = MersenneTwisterParams { + matrix_a: 0x9908b0df, + upper_mask: 0x80000000, + lower_mask: 0x7fffffff, + tempering_mask_b: 0x9d2c5680, + tempering_mask_c: 0xefc60000, + }; + MersenneTwisterConfig::new_custom(624, 397, params) } /// Sets the number of elements in the array. @@ -149,7 +245,10 @@ impl MersenneTwisterConfig { /// /// This function panics if the provided parameter is outside of its valid range. pub fn set_m(&mut self, m: usize) { - assert!(m >= 1 && m < self.n, "m must be at least 1 and less than n"); + assert!( + m >= 1 && m < self.n, + "m must be at least 1 and less than n" + ); self.m = m; } @@ -159,8 +258,12 @@ impl MersenneTwisterConfig { /// /// This function panics if the provided parameter is not valid. pub fn set_matrix_a(&mut self, matrix_a: u32) { - assert_eq!(matrix_a & 0x80000000, 0x80000000, "matrix_a must have its highest bit set"); - self.matrix_a = matrix_a; + assert_eq!( + matrix_a & 0x80000000, + 0x80000000, + "matrix_a must have its highest bit set" + ); + self.params.matrix_a = matrix_a; } /// Sets the upper_mask constant value. @@ -169,8 +272,11 @@ impl MersenneTwisterConfig { /// /// This function panics if the provided parameter is not valid. pub fn set_upper_mask(&mut self, upper_mask: u32) { - assert_eq!(upper_mask, 0x80000000, "upper_mask must be a valid 32-bit unsigned integer"); - self.upper_mask = upper_mask; + assert_eq!( + upper_mask, 0x80000000, + "upper_mask must be a valid 32-bit unsigned integer" + ); + self.params.upper_mask = upper_mask; } /// Sets the lower_mask constant value. @@ -179,8 +285,11 @@ impl MersenneTwisterConfig { /// /// This function panics if the provided parameter is not valid. pub fn set_lower_mask(&mut self, lower_mask: u32) { - assert_eq!(lower_mask, 0x7fffffff, "lower_mask must be a valid 32-bit unsigned integer"); - self.lower_mask = lower_mask; + assert_eq!( + lower_mask, 0x7fffffff, + "lower_mask must be a valid 32-bit unsigned integer" + ); + self.params.lower_mask = lower_mask; } /// Sets the tempering_mask_b constant value. @@ -189,8 +298,11 @@ impl MersenneTwisterConfig { /// /// This function panics if the provided parameter is not valid. pub fn set_tempering_mask_b(&mut self, tempering_mask_b: u32) { - assert_eq!(tempering_mask_b, 0x9d2c5680, "tempering_mask_b must be a valid 32-bit unsigned integer"); - self.tempering_mask_b = tempering_mask_b; + assert_eq!( + tempering_mask_b, 0x9d2c5680, + "tempering_mask_b must be a valid 32-bit unsigned integer" + ); + self.params.tempering_mask_b = tempering_mask_b; } /// Sets the tempering_mask_c constant value. @@ -199,10 +311,48 @@ impl MersenneTwisterConfig { /// /// This function panics if the provided parameter is not valid. pub fn set_tempering_mask_c(&mut self, tempering_mask_c: u32) { - assert_eq!(tempering_mask_c, 0xefc60000, "tempering_mask_c must be a valid 32-bit unsigned integer"); - self.tempering_mask_c = tempering_mask_c; + assert_eq!( + tempering_mask_c, 0xefc60000, + "tempering_mask_c must be a valid 32-bit unsigned integer" + ); + self.params.tempering_mask_c = tempering_mask_c; } + /// Serialize a MersenneTwisterConfig instance to a JSON file + /// + /// # Arguments + /// * `config` - A reference to a MersenneTwisterConfig instance + /// * `filename` - A string slice containing the filename + /// + /// # Returns + /// * `Result<(), Box>` - A result indicating success or failure + /// + pub fn serialize_to_file( + config: &MersenneTwisterConfig, + filename: &str, + ) -> Result<(), Box> { + let file = File::create(filename)?; + let writer = BufWriter::new(file); + serde_json::to_writer(writer, config)?; + Ok(()) + } + + /// Deserialize a MersenneTwisterConfig instance from a JSON file + /// + /// # Arguments + /// * `filename` - A string slice containing the filename + /// + /// # Returns + /// * `Result>` - A result containing the deserialized MersenneTwisterConfig instance + /// + pub fn deserialize_from_file( + filename: &str, + ) -> Result> { + let file = File::open(filename)?; + let reader = BufReader::new(file); + let config = serde_json::from_reader(reader)?; + Ok(config) + } } impl Default for MersenneTwisterConfig { @@ -213,8 +363,28 @@ impl Default for MersenneTwisterConfig { impl fmt::Display for MersenneTwisterConfig { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "MersenneTwisterConfig {{ n: {}, m: {}, matrix_a: 0x{:x}, upper_mask: 0x{:x}, lower_mask: 0x{:x}, tempering_mask_b: 0x{:x}, tempering_mask_c: 0x{:x} }}", - self.n, self.m, self.matrix_a, self.upper_mask, self.lower_mask, self.tempering_mask_b, self.tempering_mask_c) + write!( + f, + "MersenneTwisterConfig {{ n: {}, m: {}, matrix_a: 0x{:x}, upper_mask: 0x{:x}, lower_mask: 0x{:x}, tempering_mask_b: 0x{:x}, tempering_mask_c: 0x{:x} }}", + self.n, + self.m, + self.params.matrix_a, + self.params.upper_mask, + self.params.lower_mask, + self.params.tempering_mask_b, + self.params.tempering_mask_c, + ) } } +impl Default for MersenneTwisterParams { + fn default() -> Self { + MersenneTwisterParams { + matrix_a: 0x9908b0df, + upper_mask: 0x80000000, + lower_mask: 0x7fffffff, + tempering_mask_b: 0x9d2c5680, + tempering_mask_c: 0xefc60000, + } + } +} diff --git a/src/random.rs b/src/random.rs index 4032137..d5c1365 100644 --- a/src/random.rs +++ b/src/random.rs @@ -4,8 +4,7 @@ // See LICENSE-APACHE.md and LICENSE-MIT.md in the repository root for full license information. use crate::MersenneTwisterConfig; -use rand::thread_rng; -use rand::Rng; +use rand::{thread_rng, Rng, RngCore}; use serde::{Deserialize, Serialize}; use serde_big_array::BigArray; @@ -31,14 +30,11 @@ use serde_big_array::BigArray; /// use vrd::random::Random; /// let mut rng = Random::new(); /// ``` - -/// # Random Number Generation pub struct Random { /// The array of unsigned 32-bit integers used to generate random numbers. #[serde(with = "BigArray")] pub mt: [u32; 624], - /// The current index of the array used in the generation of random - /// numbers + /// The current index of the array used in the generation of random numbers. pub mti: usize, } @@ -130,7 +126,7 @@ impl Random { if values.is_empty() { return None; } - let mut rng = rand::thread_rng(); + let mut rng = thread_rng(); let index = rng.gen_range(0..values.len()); Some(&values[index]) } @@ -151,7 +147,31 @@ impl Random { /// # Notes /// The generated float is inclusive of 0.0 and exclusive of 1.0. pub fn float(&mut self) -> f32 { - thread_rng().gen::() as f32 + thread_rng().r#gen::() + } + + /// Creates a new instance of the `Random` struct, seeded with a non-deterministic value obtained from the system's entropy source. + /// + /// This method ensures that each instance of `Random` produces a unique and unpredictable sequence of numbers. + /// + /// # Examples + /// ``` + /// use vrd::random::Random; + /// let mut rng = Random::from_entropy(); // Creates a new instance of Random with a non-deterministic seed + /// let random_number = rng.rand(); // Generates a random number + /// println!("Random number: {}", random_number); + /// ``` + /// + /// # Returns + /// A new instance of `Random` with its internal state initialized for random number generation using a non-deterministic seed. + /// + /// # Notes + /// - The internal state is seeded with a non-deterministic value obtained from the system's entropy source, ensuring unique and unpredictable sequences of random numbers for each instance of `Random`. + pub fn from_entropy() -> Self { + let seed = thread_rng().next_u32(); + let mut rng = Random::new(); + rng.seed(seed); + rng } /// Generates a random integer within a specified range. @@ -174,7 +194,19 @@ impl Random { /// # Panics /// Panics if `min` is greater than `max`. pub fn int(&mut self, min: i32, max: i32) -> i32 { - thread_rng().gen_range(min..=max) + assert!( + min <= max, + "min must be less than or equal to max for int" + ); + + // Use your Mersenne Twister 'rand()' to get a random u32 value + let random_u32 = self.rand(); + + // Scale and shift the random_u32 into the desired range: + let range = max as u32 - min as u32 + 1; // Calculate the size of the range + let value_in_range = (random_u32 % range) + min as u32; + + value_in_range as i32 } /// Generates a random unsigned integer within a specified range. @@ -216,7 +248,7 @@ impl Random { /// # Notes /// The generated double is a number in the range [0.0, 1.0). pub fn double(&mut self) -> f64 { - thread_rng().gen::() + thread_rng().r#gen::() } /// Returns the current index of the internal state array used in random number generation. @@ -285,11 +317,12 @@ impl Random { mt: [0; N], mti: N + 1, }; - let seed = thread_rng().gen(); + let seed = thread_rng().r#gen(); rng.mt[0] = seed; for i in 1..N { + let previous_value = rng.mt[i - 1]; rng.mt[i] = 1812433253u32 - .wrapping_mul(rng.mt[i - 1] ^ (rng.mt[i - 1] >> 30)) + .wrapping_mul(previous_value ^ (previous_value >> 30)) .wrapping_add(i as u32); } rng.mti = N; @@ -356,8 +389,8 @@ impl Random { let mut y = self.mt[self.mti]; self.mti += 1; y ^= y >> 11; - y ^= (y << 7) & config.tempering_mask_b; - y ^= (y << 15) & config.tempering_mask_c; + y ^= (y << 7) & config.params.tempering_mask_b; + y ^= (y << 15) & config.params.tempering_mask_c; y ^= y >> 18; y } @@ -389,7 +422,7 @@ impl Random { max > min, "max must be greater than min for random_range" ); - let mut rng = rand::thread_rng(); // Get a thread-local RNG + let mut rng = thread_rng(); // Get a thread-local RNG rng.gen_range(min..max) // Use the gen_range method for uniform distribution } @@ -475,13 +508,14 @@ impl Random { pub fn twist(&mut self) { let config = MersenneTwisterConfig::default(); for i in 0..config.n { - let x = (self.mt[i] & config.upper_mask) - + (self.mt[(i + 1) % config.n] & config.lower_mask); + let x = (self.mt[i] & config.params.upper_mask) + + (self.mt[(i + 1) % config.n] + & config.params.lower_mask); let x_a = x >> 1; if x % 2 != 0 { self.mt[i] = self.mt[(i + config.m) % config.n] ^ x_a - ^ config.matrix_a; + ^ config.params.matrix_a; } else { self.mt[i] = self.mt[(i + config.m) % config.n] ^ x_a; } @@ -538,7 +572,7 @@ impl Random { /// # Returns /// An `f64` representing a randomly generated 64-bit floating-point number. pub fn f64(&mut self) -> f64 { - thread_rng().gen::() + thread_rng().r#gen::() } /// Generates a random string of the specified length. @@ -557,15 +591,16 @@ impl Random { /// # Returns /// A `String` representing a randomly generated string of the specified length. pub fn string(&mut self, length: usize) -> String { + let mut rng = thread_rng(); let chars: Vec = (0..length) .map(|_| { - let value = self.rand() % 62; - if value < 10 { - (b'0' + value as u8) as char - } else if value < 36 { - (b'a' + value as u8 - 10) as char + let value = rng.gen_range(0..62); + if value < 26 { + (b'a' + value as u8) as char + } else if value < 52 { + (b'A' + value as u8 - 26) as char } else { - (b'A' + value as u8 - 36) as char + (b'0' + value as u8 - 52) as char } }) .collect(); @@ -644,6 +679,144 @@ impl Random { } k - 1 } + /// Generates a random subslice of the specified length from the given slice. + /// + /// # Arguments + /// * `slice` - The slice from which to generate a random subslice. + /// * `length` - The desired length of the random subslice. + /// + /// # Examples + /// ``` + /// use vrd::random::Random; + /// let mut rng = Random::new(); + /// let slice = &[1, 2, 3, 4, 5]; + /// let random_subslice = rng.rand_slice(slice, 3); + /// println!("Random subslice: {:?}", random_subslice); + /// ``` + /// + /// # Returns + /// A slice containing a randomly generated subslice of the specified length. + pub fn rand_slice<'a, T>( + &'a mut self, + slice: &'a [T], + length: usize, + ) -> &[T] { + let start = self + .random_range(0, slice.len() as u32 - length as u32) + as usize; + &slice[start..start + length] + } + + /// Randomly samples elements from the given slice without replacement. + /// + /// # Arguments + /// * `slice` - The slice from which to sample elements. + /// * `amount` - The number of elements to sample. + /// + /// # Examples + /// ``` + /// use vrd::random::Random; + /// let mut rng = Random::new(); + /// let slice = &[1, 2, 3, 4, 5]; + /// let samples = rng.sample(slice, 3); + /// println!("Random samples: {:?}", samples); + /// ``` + /// + /// # Returns + /// A vector containing the randomly sampled elements. + pub fn sample<'a, T>( + &'a mut self, + slice: &'a [T], + amount: usize, + ) -> Vec<&T> { + let mut result = Vec::with_capacity(amount); + let mut indices: Vec = (0..slice.len()).collect(); + for _ in 0..amount { + let index = + self.random_range(0, indices.len() as u32) as usize; + result.push(&slice[indices[index]]); + indices.remove(index); + } + result + } + + /// Randomly samples elements from the given slice with replacement. + /// + /// # Arguments + /// * `slice` - The slice from which to sample elements. + /// * `amount` - The number of elements to sample. + /// + /// # Examples + /// ``` + /// use vrd::random::Random; + /// let mut rng = Random::new(); + /// let slice = &[1, 2, 3, 4, 5]; + /// let samples = rng.sample_with_replacement(slice, 3); + /// println!("Random samples with replacement: {:?}", samples); + /// ``` + /// + /// # Returns + /// A vector containing the randomly sampled elements with replacement. + pub fn sample_with_replacement<'a, T>( + &'a mut self, + slice: &'a [T], + amount: usize, + ) -> Vec<&T> { + let mut result = Vec::with_capacity(amount); + for _ in 0..amount { + let index = + self.random_range(0, slice.len() as u32) as usize; + result.push(&slice[index]); + } + result + } + + /// Fills the given mutable slice with random values. + /// + /// # Arguments + /// * `slice` - The mutable slice to fill with random values. + /// + /// # Examples + /// ``` + /// use vrd::random::Random; + /// let mut rng = Random::new(); + /// let mut buffer = [0; 10]; + /// rng.fill(&mut buffer); + /// println!("Filled buffer: {:?}", buffer); + /// ``` + pub fn fill(&mut self, slice: &mut [T]) + where + T: Default + std::ops::RemAssign, + { + // Seed the RNG with a new random value before filling the buffer + self.seed(thread_rng().next_u32()); + + for item in slice { + let random_value = self.rand(); + *item = T::default(); + *item %= random_value; + } + } + + /// Shuffles the elements of a mutable slice randomly. + /// + /// # Arguments + /// * `slice` - The mutable slice to shuffle. + /// + /// # Examples + /// ``` + /// use vrd::random::Random; + /// let mut rng = Random::new(); + /// let mut values = [1, 2, 3, 4, 5]; + /// rng.shuffle(&mut values); + /// println!("Shuffled values: {:?}", values); + /// ``` + pub fn shuffle(&mut self, slice: &mut [T]) { + for i in (1..slice.len()).rev() { + let j = self.random_range(0, (i + 1) as u32) as usize; + slice.swap(i, j); + } + } } impl std::fmt::Display for Random { diff --git a/tests/test_lib.rs b/tests/test_lib.rs index 9666a48..aa14b5c 100644 --- a/tests/test_lib.rs +++ b/tests/test_lib.rs @@ -6,8 +6,6 @@ #[cfg(test)] mod tests { - extern crate vrd; - use std::convert::TryInto; use vrd::random::Random; const N: usize = 624; @@ -100,7 +98,7 @@ mod tests { assert!((0..=10).contains(&r)); } #[test] - pub fn test_new() { + fn test_new() { let rng = Random::new(); assert!(rng.mti <= N); assert!(rng.mt[0] > 0); @@ -131,7 +129,9 @@ mod tests { // Verify that `mti` is set to `N` after seeding assert_eq!(rng.mti, N); - assert!(rng.mt.iter().any(|&x| x != N.try_into().unwrap())); + + // Comparing elements of `rng.mt` with the value of `n` + assert!(rng.mt.iter().any(|&x| x != N as u32)); } #[test] diff --git a/tests/test_macros.rs b/tests/test_macros.rs index dc06354..c5840af 100644 --- a/tests/test_macros.rs +++ b/tests/test_macros.rs @@ -125,11 +125,12 @@ mod tests { } #[test] - fn test_random_range_macro_valid_range() { + fn test_rand_range_macro_valid_range() { let mut rng = Random::new(); let min = 10; let max = 20; let num = random_range!(rng, min, max); + println!("Generated number: {}", num); // Add this line for debugging assert!( num >= min && num < max, "Number should be within the given range." diff --git a/tests/test_main.rs b/tests/test_main.rs index 186504e..b63fce3 100644 --- a/tests/test_main.rs +++ b/tests/test_main.rs @@ -6,17 +6,22 @@ #[cfg(test)] mod tests { use rlg::{log_format::LogFormat, log_level::LogLevel}; - use vrd::create_log_entry; + use uuid::Uuid; + use vrd::{create_log_entry, log_entry_async}; + // Test creating a log entry #[test] fn test_create_log_entry() { + // Arrange let uuid = "test-uuid"; let iso = "2023-06-10T12:34:56Z"; let level = LogLevel::INFO; let message = "Test log message"; + // Act let log_entry = create_log_entry(uuid, iso, level, message); + // Assert assert_eq!(log_entry.session_id, uuid); assert_eq!(log_entry.time, iso); assert_eq!(log_entry.level.to_string(), "INFO"); @@ -25,18 +30,37 @@ mod tests { assert_eq!(log_entry.format, LogFormat::JSON); } + // Test logging asynchronously #[tokio::test] async fn test_log_entry_async() { + // Arrange let uuid = "test-uuid"; let iso = "2023-06-10T12:34:56Z"; let level = LogLevel::INFO; let message = "Test log message"; + let log_entry = create_log_entry(uuid, iso, level, message); + // Act + let result = log_entry_async(log_entry).await; + + // Assert // Assert that the log entry was logged successfully - assert!(log_entry.session_id == "test-uuid"); - assert!(log_entry.time == "2023-06-10T12:34:56Z"); - assert!(log_entry.level == LogLevel::INFO); - assert!(message == "Test log message"); + assert!(result.is_ok()); + } + + // Test UUID generation + #[test] + fn test_uuid_generation() { + // Act + // Test generating multiple UUIDs + let uuid1 = Uuid::new_v4().to_string(); + let uuid2 = Uuid::new_v4().to_string(); + + // Assert + // Ensure UUIDs are generated successfully and are unique + assert!(!uuid1.is_empty()); + assert!(!uuid2.is_empty()); + assert_ne!(uuid1, uuid2); } } diff --git a/tests/test_mersenne_twister.rs b/tests/test_mersenne_twister.rs new file mode 100644 index 0000000..96ab860 --- /dev/null +++ b/tests/test_mersenne_twister.rs @@ -0,0 +1,447 @@ +// Copyright ยฉ 2023-2024 Random (VRD) library. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// This file is part of the `Random (VRD)` library, a Rust implementation of the Mersenne Twister RNG. +// See LICENSE-APACHE.md and LICENSE-MIT.md in the repository root for full license information. + +#[cfg(test)] +mod tests { + // Import necessary modules from the vrd crate + use vrd::{ + mersenne_twister::MersenneTwisterParams, MersenneTwisterConfig, + }; + + // Test creating a custom Mersenne Twister configuration + #[test] + fn test_new_custom() { + // Arrange + let params = MersenneTwisterParams { + matrix_a: 0x9908b0df, + upper_mask: 0x80000000, + lower_mask: 0x7fffffff, + tempering_mask_b: 0x9d2c5680, + tempering_mask_c: 0xefc60000, + }; + + // Act + let config = + MersenneTwisterConfig::new_custom(624, 397, params); + + // Assert + assert_eq!(config.n, 624); + assert_eq!(config.m, 397); + assert_eq!(config.params.matrix_a, 0x9908b0df); + assert_eq!(config.params.upper_mask, 0x80000000); + assert_eq!(config.params.lower_mask, 0x7fffffff); + assert_eq!(config.params.tempering_mask_b, 0x9d2c5680); + assert_eq!(config.params.tempering_mask_c, 0xefc60000); + } + + // Test creating a custom configuration with invalid n value + #[test] + #[should_panic(expected = "n must be at least 1")] + fn test_new_custom_invalid_n() { + let params = MersenneTwisterParams::default(); // Provide default params here + MersenneTwisterConfig::new_custom(0, 397, params); + } + + // Test creating a custom configuration with invalid m value + #[test] + #[should_panic(expected = "m must be at least 1 and less than n")] + fn test_new_custom_invalid_m() { + let params = MersenneTwisterParams::default(); // Provide default params here + MersenneTwisterConfig::new_custom(624, 0, params); + } + + // Test creating a custom configuration with invalid matrix_a value + #[test] + #[should_panic(expected = "matrix_a must have its highest bit set")] + fn test_new_custom_invalid_matrix_a() { + let params = MersenneTwisterParams { + matrix_a: 0x7fffffff, // Invalid value + upper_mask: 0x80000000, + lower_mask: 0x7fffffff, + tempering_mask_b: 0x9d2c5680, + tempering_mask_c: 0xefc60000, + }; + MersenneTwisterConfig::new_custom(624, 397, params); + } + + // Test creating a custom configuration with invalid tempering_mask_b value + #[test] + #[should_panic( + expected = "tempering_mask_b must be a valid 32-bit unsigned integer" + )] + fn test_new_custom_invalid_tempering_mask_b() { + let params = MersenneTwisterParams { + matrix_a: 0x9908b0df, + upper_mask: 0x80000000, + lower_mask: 0x7fffffff, + tempering_mask_b: 0xffffffff, // Invalid value + tempering_mask_c: 0xefc60000, + }; + MersenneTwisterConfig::new_custom(624, 397, params); + } + + // Test creating a custom configuration with invalid upper_mask value + #[test] + #[should_panic( + expected = "upper_mask must be a valid 32-bit unsigned integer" + )] + fn test_new_custom_invalid_upper_mask() { + let params = MersenneTwisterParams { + matrix_a: 0x9908b0df, + upper_mask: 0xffffffff, // Invalid value + lower_mask: 0x7fffffff, + tempering_mask_b: 0x9d2c5680, + tempering_mask_c: 0xefc60000, + }; + MersenneTwisterConfig::new_custom(624, 397, params); + } + + // Test creating a custom configuration with invalid lower_mask value + #[test] + #[should_panic( + expected = "lower_mask must be a valid 32-bit unsigned integer" + )] + fn test_new_custom_invalid_lower_mask() { + let params = MersenneTwisterParams { + matrix_a: 0x9908b0df, + upper_mask: 0x80000000, + lower_mask: 0xffffffff, // Invalid value + tempering_mask_b: 0x9d2c5680, + tempering_mask_c: 0xefc60000, + }; + MersenneTwisterConfig::new_custom(624, 397, params); + } + + // Test creating a custom configuration with invalid tempering_mask_c value + #[test] + #[should_panic( + expected = "tempering_mask_c must be a valid 32-bit unsigned integer" + )] + fn test_new_custom_invalid_tempering_mask_c() { + let params = MersenneTwisterParams { + matrix_a: 0x9908b0df, + upper_mask: 0x80000000, + lower_mask: 0x7fffffff, + tempering_mask_b: 0x9d2c5680, + tempering_mask_c: 0xffffffff, // Invalid value + }; + MersenneTwisterConfig::new_custom(624, 397, params); + } + + // Test setting configuration parameters + #[test] + fn test_set_config() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + let params = MersenneTwisterParams::default(); + config.set_config(1000, 500, params); + + // Assert + assert_eq!(config.n, 1000); + assert_eq!(config.m, 500); + assert_eq!(config.params.matrix_a, 0x9908b0df); + assert_eq!(config.params.upper_mask, 0x80000000); + assert_eq!(config.params.lower_mask, 0x7fffffff); + assert_eq!(config.params.tempering_mask_b, 0x9d2c5680); + assert_eq!(config.params.tempering_mask_c, 0xefc60000); + } + + // Test creating a default configuration + #[test] + fn test_new() { + // Act + let config = MersenneTwisterConfig::new(); + + // Assert + assert_eq!(config.n, 624); + assert_eq!(config.m, 397); + assert_eq!(config.params.matrix_a, 0x9908b0df); + assert_eq!(config.params.upper_mask, 0x80000000); + assert_eq!(config.params.lower_mask, 0x7fffffff); + assert_eq!(config.params.tempering_mask_b, 0x9d2c5680); + assert_eq!(config.params.tempering_mask_c, 0xefc60000); + } + + // Test setting n parameter + #[test] + fn test_set_n() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_n(1000); + + // Assert + assert_eq!(config.n, 1000); + } + + // Test setting n parameter with invalid value + #[test] + #[should_panic(expected = "n must be at least 1")] + fn test_set_n_invalid() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_n(0); + } + + // Test setting m parameter + #[test] + fn test_set_m() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_m(500); + + // Assert + assert_eq!(config.m, 500); + } + + // Test setting m parameter with invalid value + #[test] + #[should_panic(expected = "m must be at least 1 and less than n")] + fn test_set_m_invalid() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_m(0); + } + + // Test setting matrix_a parameter + #[test] + fn test_set_matrix_a() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_matrix_a(0x9908b0df); + + // Assert + assert_eq!(config.params.matrix_a, 0x9908b0df); + } + + // Test setting matrix_a parameter with invalid value + #[test] + #[should_panic(expected = "matrix_a must have its highest bit set")] + fn test_set_matrix_a_invalid() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_matrix_a(0x7fffffff); + } + + // Test setting upper_mask parameter + #[test] + fn test_set_upper_mask() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_upper_mask(0x80000000); + + // Assert + assert_eq!(config.params.upper_mask, 0x80000000); + } + + // Test setting upper_mask parameter with invalid value + #[test] + #[should_panic( + expected = "upper_mask must be a valid 32-bit unsigned integer" + )] + fn test_set_upper_mask_invalid() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_upper_mask(0xffffffff); + } + + // Test setting lower_mask parameter + #[test] + fn test_set_lower_mask() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_lower_mask(0x7fffffff); + + // Assert + assert_eq!(config.params.lower_mask, 0x7fffffff); + } + + // Test setting lower_mask parameter with invalid value + #[test] + #[should_panic( + expected = "lower_mask must be a valid 32-bit unsigned integer" + )] + fn test_set_lower_mask_invalid() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_lower_mask(0xffffffff); + } + + // Test setting tempering_mask_b parameter + #[test] + fn test_set_tempering_mask_b() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_tempering_mask_b(0x9d2c5680); + + // Assert + assert_eq!(config.params.tempering_mask_b, 0x9d2c5680); + } + + // Test setting tempering_mask_b parameter with invalid value + #[test] + #[should_panic( + expected = "tempering_mask_b must be a valid 32-bit unsigned integer" + )] + fn test_set_tempering_mask_b_invalid() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_tempering_mask_b(0xffffffff); + } + + // Test setting tempering_mask_c parameter + #[test] + fn test_set_tempering_mask_c() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_tempering_mask_c(0xefc60000); + + // Assert + assert_eq!(config.params.tempering_mask_c, 0xefc60000); + } + + // Test setting tempering_mask_c parameter with invalid value + #[test] + #[should_panic( + expected = "tempering_mask_c must be a valid 32-bit unsigned integer" + )] + fn test_set_tempering_mask_c_invalid() { + // Arrange + let mut config = MersenneTwisterConfig::new(); + + // Act + config.set_tempering_mask_c(0xffffffff); + } + + // Test creating a default configuration + #[test] + fn test_default() { + // Act + let config = MersenneTwisterConfig::default(); + + // Assert + assert_eq!(config.n, 624); + assert_eq!(config.m, 397); + assert_eq!(config.params.matrix_a, 0x9908b0df); + assert_eq!(config.params.upper_mask, 0x80000000); + assert_eq!(config.params.lower_mask, 0x7fffffff); + assert_eq!(config.params.tempering_mask_b, 0x9d2c5680); + assert_eq!(config.params.tempering_mask_c, 0xefc60000); + } + + // Test displaying configuration + #[test] + fn test_display() { + // Arrange + let config = MersenneTwisterConfig::new(); + let expected = format!( + "MersenneTwisterConfig {{ n: {}, m: {}, matrix_a: 0x{:x}, upper_mask: 0x{:x}, lower_mask: 0x{:x}, tempering_mask_b: 0x{:x}, tempering_mask_c: 0x{:x} }}", + config.n, + config.m, + config.params.matrix_a, + config.params.upper_mask, + config.params.lower_mask, + config.params.tempering_mask_b, + config.params.tempering_mask_c + ); + + // Act & Assert + assert_eq!(format!("{}", config), expected); + } + + // Test validating a valid configuration + #[test] + fn test_validate_valid() { + let params = MersenneTwisterParams::default(); // Provide default params here + // Act + MersenneTwisterConfig::validate(624, 397, ¶ms); + } + + // Test validating a configuration with invalid n value + #[test] + #[should_panic(expected = "n must be at least 1")] + fn test_validate_invalid_n() { + let params = MersenneTwisterParams::default(); // Provide default params here + // Act + MersenneTwisterConfig::validate(0, 397, ¶ms); + } + + #[test] + #[should_panic] // Expect all cases to panic + fn test_new_custom_invalid_parameters() { + let test_cases = vec![ + (0, 397, "n must be at least 1"), + (624, 0, "m must be at least 1 and less than n"), + (624, 397, "matrix_a must have its highest bit set"), // Invalid matrix_a + (624, 397, "0xffffffff"), // Invalid upper_mask + (624, 397, "0xffffffff"), // Invalid lower_mask + (624, 397, "0xffffffff"), // Invalid tempering_mask_b + (624, 397, "0xffffffff"), // Invalid tempering_mask_c + ]; + + for (n, m, invalid_param) in test_cases { + let mut params = MersenneTwisterParams::default(); + let expected_msg = invalid_param; // Assuming invalid_param contains error messages + + // Set the invalid parameter based on the test case + if let Ok(param_as_int) = invalid_param.parse::() { + // Try parsing first + match param_as_int { + param if param & 0x80000000 == 0 => { + params.matrix_a = param + } + 0xffffffff => { + params.upper_mask = param_as_int; // Use the parsed value + params.lower_mask = param_as_int; + params.tempering_mask_b = param_as_int; + params.tempering_mask_c = param_as_int; + } + _ => unreachable!(), + } + } else { + // Handle cases where invalid_param is not a number (likely an error message) + panic!("{}", expected_msg); // Or handle accordingly + } + + let result = std::panic::catch_unwind(|| { + MersenneTwisterConfig::new_custom(n, m, params); + }); + + assert!(result.is_err()); + assert!(result + .unwrap_err() + .downcast_ref::<&str>() + .unwrap() + .contains(expected_msg)); + } + } +} diff --git a/tests/test_random.rs b/tests/test_random.rs new file mode 100644 index 0000000..9e2503f --- /dev/null +++ b/tests/test_random.rs @@ -0,0 +1,193 @@ +// Copyright ยฉ 2023-2024 Random (VRD) library. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// This file is part of the `Random (VRD)` library, a Rust implementation of the Mersenne Twister RNG. +// See LICENSE-APACHE.md and LICENSE-MIT.md in the repository root for full license information. + +#[cfg(test)] +mod tests { + use vrd::random::Random; + + // Initialization tests + #[test] + fn test_new() { + let rng = Random::new(); + // Check that the internal state (mt, mti) is initialized correctly. + // You might want to compare a few elements of rng.mt against expected values + // after its generation, based on the algorithm's specifications. + assert_eq!(rng.mti, 624); + } + + #[test] + fn test_seed() { + let mut rng = Random::new(); + + rng.seed(42); // Seed with a specific value + + // Test that subsequent random numbers are deterministic based on the seed + assert_eq!(rng.rand(), 848288234); + } + + // Integer tests + #[test] + fn test_int() { + let mut rng = Random::new(); + rng.seed(20); + + assert_eq!(rng.int(1, 10), 5); + assert_eq!(rng.int(5, 10), 9); + assert_eq!(rng.int(10, 20), 18); + assert_eq!(rng.int(15, 20), 19); + assert_eq!(rng.int(20, 30), 28); + assert_eq!(rng.int(25, 30), 29); + assert_eq!(rng.int(30, 40), 38); + } + + #[test] + fn test_int_edge_cases() { + let mut rng = Random::new(); + rng.seed(42); + + // Test with minimum and maximum possible integers + assert_eq!(rng.int(i32::MIN, i32::MIN + 1), i32::MIN); + assert_eq!(rng.int(i32::MAX - 1, i32::MAX), i32::MAX - 1); + } + + // Floating-point tests + #[test] + fn test_float() { + let mut rng = Random::new(); + rng.seed(42); + + // Test generating floating-point numbers within the range [0.0, 1.0) + let result = rng.float(); + assert!((0.0..1.0).contains(&result)); + + // Test generating floating-point numbers within the range [-1.0, 0.0) + let result = rng.float() * -1.0; // Adjust the sign to check the negative range + assert!((-1.0..0.0).contains(&result)); + } + + #[test] + fn test_double() { + let mut rng = Random::new(); + rng.seed(42); + + let result = rng.double(); + assert!((0.0..1.0).contains(&result)); + } + + #[test] + fn test_f64() { + let mut rng = Random::new(); + rng.seed(50); + + let result = rng.f64(); + assert!((0.0..1.0).contains(&result)); + } + + // Other types tests + #[test] + fn test_bytes() { + let mut rng = Random::new(); + rng.seed(5); // Fixed seed for predictability + + let expected_bytes = vec![234, 232, 232, 232, 232, 232, 232]; + let random_bytes = rng.bytes(expected_bytes.len()); + + assert_eq!(random_bytes, expected_bytes); + } + + #[test] + fn test_bool() { + let mut rng = Random::new(); + rng.seed(42); + + // With a probability of 0.5, true and false should have roughly equal occurrence + let mut true_count: i32 = 0; + let mut false_count: i32 = 0; + + for _ in 0..1000 { + if rng.bool(0.5) { + true_count += 1; + } else { + false_count += 1; + } + } + + // Assert that the counts are approximately balanced (adjust tolerance as needed) + let difference = (true_count - false_count).abs(); + assert!(difference < 100); + } + + #[test] + fn test_char() { + let mut rng = Random::new(); + rng.seed(60); + + let result = rng.char(); + assert!(result.is_ascii_lowercase()); + } + + // Method tests + #[test] + #[should_panic( + expected = "max must be greater than min for random_range" + )] + fn test_random_range_invalid() { + let mut rng = Random::new(); + rng.random_range(20, 10); // Should panic + } + + #[test] + fn test_random_range() { + let mut rng = Random::new(); + rng.seed(40); + + assert_ne!(rng.random_range(1, 10), 0); + } + + #[test] + fn test_clone() { + let mut rng = Random::new(); + rng.seed(42); + + let mut cloned_rng = rng.clone(); + + // Ensure that the cloned RNG produces the same sequence of random numbers + for _ in 0..100 { + assert_eq!(rng.rand(), cloned_rng.rand()); + } + } + + #[test] + fn test_shuffle() { + let mut rng = Random::new(); + rng.seed(42); + + let mut data = vec![1, 2, 3, 4, 5]; + let original_data = data.clone(); + + rng.shuffle(&mut data); + + // Ensure that the shuffle operation produces a different permutation + assert_ne!(data, original_data); + + // Ensure that all elements are still present in the shuffled vector + original_data.iter().for_each(|x| assert!(data.contains(x))); + data.iter().for_each(|x| assert!(original_data.contains(x))); + } + + #[test] + fn test_choose() { + let mut rng = Random::new(); + rng.seed(42); + + let data = vec![1, 2, 3, 4, 5]; + + // Choose a random element from the data vector + let chosen_element = rng.choose(&data).unwrap(); + + // Ensure that the chosen element is present in the original data + assert!(data.contains(chosen_element)); + } +} diff --git a/vrd.csv b/vrd.csv deleted file mode 100644 index 9e4c171..0000000 --- a/vrd.csv +++ /dev/null @@ -1,2 +0,0 @@ -author,build,categories,description,documentation,edition,email,homepage,keywords,license,name,output,readme,repository,rustversion,version,website -Sebastien Rousseau,build.rs,"['Algorithms', 'Encoding','Parser implementations','Data structures']",A Rust library for generating random and pseudo-random numbers based on the Mersenne Twister algorithm,https://lib.rs/crates/vrd,2021,sebastian.rousseau@gmail.com,https://vrdlib.com,"['rand', 'random','entropy','random-number','vrd']",MIT OR Apache-2.0,vrd,vrd,README.md,https://github.com/sebastienrousseau/vrd,1.69.0,0.0.4,https://vrdlib.com \ No newline at end of file diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml deleted file mode 100644 index 5fc0f81..0000000 --- a/xtask/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "xtask" -version = "0.2.0" -edition = "2021" - -[dependencies] -anyhow = "1.0.80" -xtaskops = "0.4.2" - -[[bin]] -name = "xtask" -path = "src/main.rs" diff --git a/xtask/src/main.rs b/xtask/src/main.rs deleted file mode 100644 index c58cdf1..0000000 --- a/xtask/src/main.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! This is the main entry point for the xtask crate. -//! -//! The `main()` function serves as the starting point of the executable. -//! It returns a `Result<(), anyhow::Error>`, indicating success or failure. -//! The `xtaskops::tasks::main()` function is called to perform the main tasks. -//! -//! # Errors -//! -//! If an error occurs during the execution of the tasks, an `anyhow::Error` is returned. - -fn main() -> Result<(), anyhow::Error> { - xtaskops::tasks::main() -}