From 207c14e94d808e824b779a11497905a681de26f7 Mon Sep 17 00:00:00 2001 From: Mathieu Soysal Date: Sun, 8 Dec 2024 20:41:06 +0100 Subject: [PATCH] Initial commit --- .devcontainer/devcontainer.json | 54 +++ .github/CODEOWNERS | 8 + .github/CODE_OF_CONDUCT.md | 133 +++++++ .github/CONTRIBUTING.md | 62 +++ .github/ISSUE_TEMPLATE/bug_report.yml | 65 ++++ .github/ISSUE_TEMPLATE/config.yml | 5 + .github/ISSUE_TEMPLATE/documentation.yml | 24 ++ .github/ISSUE_TEMPLATE/feature_request.md | 20 + .github/ISSUE_TEMPLATE/feedback.md | 28 ++ .github/PULL_REQUEST_TEMPLATE.md | 35 ++ .github/dependabot.yml | 30 ++ .github/labeler.yml | 70 ++++ .github/stale.yml | 17 + .github/workflows/commit-lint.yml | 43 +++ .github/workflows/integration-test.yml | 222 +++++++++++ .github/workflows/label.yml | 22 ++ .github/workflows/release.yml | 171 +++++++++ .github/workflows/security-audit.yml | 83 ++++ .gitignore | 17 + Cargo.toml | 14 + LICENSE | 190 +++++++++ LICENSE -APACHE | 190 +++++++++ README.md | 81 ++++ commitlint.config.ts | 146 +++++++ deny.toml | 269 +++++++++++++ fuzz/.gitignore | 4 + fuzz/Cargo.toml | 21 + fuzz/fuzz_targets/fuzz_play_game.rs | 11 + install/install.sh | 448 ++++++++++++++++++++++ install/windows/main.wxs | 182 +++++++++ install/windows/pkg_resources/Banner.bmp | Bin 0 -> 119819 bytes install/windows/pkg_resources/Dialog.bmp | Bin 0 -> 119819 bytes install/windows/pkg_resources/LICENSE.rtf | 4 + rust-toolchain.toml | 2 + src/lib.rs | 88 +++++ src/main.rs | 14 + 36 files changed, 2773 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .github/CODEOWNERS create mode 100644 .github/CODE_OF_CONDUCT.md create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/documentation.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/feedback.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/dependabot.yml create mode 100644 .github/labeler.yml create mode 100644 .github/stale.yml create mode 100644 .github/workflows/commit-lint.yml create mode 100644 .github/workflows/integration-test.yml create mode 100644 .github/workflows/label.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/security-audit.yml create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 LICENSE -APACHE create mode 100644 README.md create mode 100644 commitlint.config.ts create mode 100644 deny.toml create mode 100644 fuzz/.gitignore create mode 100644 fuzz/Cargo.toml create mode 100644 fuzz/fuzz_targets/fuzz_play_game.rs create mode 100644 install/install.sh create mode 100644 install/windows/main.wxs create mode 100644 install/windows/pkg_resources/Banner.bmp create mode 100644 install/windows/pkg_resources/Dialog.bmp create mode 100644 install/windows/pkg_resources/LICENSE.rtf create mode 100644 rust-toolchain.toml create mode 100644 src/lib.rs create mode 100644 src/main.rs diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..f2c0d0f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,54 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/rust +{ + "name": "Rust", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye", + "features": { + "ghcr.io/devcontainers/features/rust:1": {}, + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/java:1": {} // Used for Prusti + }, + "customizations": { + "vscode": { + "extensions": [ + "rust-lang.rust-analyzer", + "serayuzgur.crates", + "vadimcn.vscode-lldb", + "tamasfe.even-better-toml", + "ZhangYue.rust-mod-generator", + "usernamehw.errorlens", + "seatonjiang.gitmoji-vscode", + "github.vscode-github-actions", + "viper-admin.prusti-assistant" + ] + }, + "codespaces": { + "openFiles": ["README.md"] + } + } + + // Use 'mounts' to make the cargo cache persistent in a Docker Volume. + // "mounts": [ + // { + // "source": "devcontainer-cargo-cache-${devcontainerId}", + // "target": "/usr/local/cargo", + // "type": "volume" + // } + // ] + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + ,"postCreateCommand": "rustup component add clippy rustfmt && (curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash) && cargo binstall cargo-mutants -y && cargo install cargo-fuzz" + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..9c34e72 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,8 @@ +# See https://help.github.com/articles/about-codeowners/ +# for more info about CODEOWNERS file + +# It uses the same pattern rule for gitignore file +# https://git-scm.com/docs/gitignore#_pattern_format + +# Maintainers +* @MathieuSoysal \ No newline at end of file diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..0310c38 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +hsoysal@student.42.fr. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..48b84d1 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,62 @@ +## Contributing + +Hi! Thanks for your interest in contributing to the Rust template! + +We accept pull requests for bug fixes and features where we've discussed the approach in an issue and given the go-ahead for a community member to work on it. We'd also love to hear about ideas for new features as issues. + +Please do: + +* Check existing issues to verify that the [bug][bug issues] or [feature request][feature request issues] has not already been submitted. +* Open an issue if things aren't working as expected. +* Open an issue to propose a significant change. +* Open a pull request to fix a bug. +* Open a pull request to fix documentation about a command. +* Open a pull request for any issue labelled [`help wanted`][hw] or [`good first issue`][gfi]. + +Please avoid: + +* Opening pull requests for issues marked `needs-design`, `needs-investigation`, or `blocked`. +* Opening pull requests that haven't been approved for work in an issue +* Adding installation instructions specifically for your OS/package manager. +* Opening pull requests for any issue marked `core`. These issues require additional context from + the core CLI team at GitHub and any external pull requests will not be accepted. + +## Building the project + +Prerequisites: +- rust or use the provided devcontainer + +Run tests with: `cargo test` + +## Submitting a pull request + +1. Create a new branch: `git checkout -b my-branch-name` +1. Make your change, add tests, and ensure tests pass +1. Submit a pull request + +Contributions to this project are [released][legal] to the public under the [project's open source license][license]. + +Please note that this project adheres to a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. + +## Design guidelines + + +## Resources + +- [How to Contribute to Open Source][] +- [Using Pull Requests][] +- [GitHub Help][] + + +[bug issues]: https://github.com/MathieuSoysal/Exercism-Rust-Template/issues?q=is%3Aopen+is%3Aissue+label%3Abug +[feature request issues]: https://github.com/MathieuSoysal/Exercism-Rust-Template/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement +[hw]: https://github.com/MathieuSoysal/Exercism-Rust-Template/labels/help%20wanted +[gfi]: https://github.com/MathieuSoysal/Exercism-Rust-Template/labels/good%20first%20issue +[legal]: https://docs.github.com/en/free-pro-team@latest/github/site-policy/github-terms-of-service#6-contributions-under-repository-license +[license]: ../LICENSE +[code-of-conduct]: ./CODE-OF-CONDUCT.md +[How to Contribute to Open Source]: https://opensource.guide/how-to-contribute/ +[Using Pull Requests]: https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/about-pull-requests +[GitHub Help]: https://docs.github.com/ +[CLI Design System]: https://primer.style/cli/ +[Google Docs Template]: https://docs.google.com/document/d/1JIRErIUuJ6fTgabiFYfCH3x91pyHuytbfa0QLnTfXKM/edit#heading=h.or54sa47ylpg \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..b511829 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,65 @@ +name: 🐞 Bug Report +description: File a new bug report +title: 'bug: ' +labels: [Bug, Needs Triage] +body: + - type: markdown + attributes: + value: ':stop_sign: _For support questions, please visit your [dicussion channel](https://github.com/MathieuSoysal/Exercism-Rust-Template/discussions) instead._' + - type: checkboxes + attributes: + label: 'Is there an existing issue for this?' + description: 'Please [search :mag: the issues](https://github.com/appium/appium/issues) to check if this bug has already been reported.' + options: + - label: 'I have searched the existing issues' + required: true + - type: textarea + attributes: + label: 'Current Behavior' + description: 'A clear and concise description of what the bug is.. **Please do not paste your logs here.** Screenshots are welcome.' + validations: + required: true + - type: textarea + attributes: + label: 'Expected Behavior' + description: 'A clear and concise description of what you expected to happen.' + validations: + required: true + - type: textarea + attributes: + label: 'Minimal Reproducible Example' + description: | + Please provide a the _smallest, complete code snippet_ that maintainers can run to reproduce the issue. Failing this, any sort of reproduction steps are better than nothing! + + If the result is more than a screenful of text _or_ requires multiple files, please: + + - _Attach_ (do not paste) it to this textarea, _or_ + - Put it in a [Gist](https://gist.github.com) and paste the link, _or_ + - Provide a link to a new or existing public repository exhibiting the issue + validations: + required: true + - type: textarea + attributes: + label: 'Environment' + description: 'Please provide the following information about your environment; feel free to remove any items which are not relevant.' + value: | + - Operating system: + validations: + required: false + - type: input + attributes: + label: 'Link to Logs' + description: | + Create a [Gist](https://gist.github.com)—which contains your _full_ Appium logs—and link it here. Alternatively, you can attach a logfile to this issue (drag it into the "Further Information" field below). + + :warning: _Remember to redact or remove any sensitive information!_ + placeholder: 'https://gist.github.com/...' + - type: textarea + attributes: + label: Further Information + description: | + Links? References? Anything that will give us more context about the issue you are encountering! + + _Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in._ + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..0fc7a05 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Ask a question on how to use template-exercisme + about: For general-purpose questions and answers, see the Discussions section. + url: https://github.com/MathieuSoysal/Exercism-Rust-Template/discussions \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml new file mode 100644 index 0000000..9542525 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -0,0 +1,24 @@ +name: Documentation problem +description: Create a report for a documentation problem. +labels: ["documentation"] +body: + - type: markdown + attributes: + value: | + Thank you for finding a documentation problem! 📚 + + Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present. + + - type: textarea + id: location + attributes: + label: Location + validations: + required: true + + - type: textarea + id: summary + attributes: + label: Summary + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..11fc491 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feedback.md b/.github/ISSUE_TEMPLATE/feedback.md new file mode 100644 index 0000000..6f9a7a3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feedback.md @@ -0,0 +1,28 @@ +--- +name: "\U0001F4E3 Feedback" +about: Give us general feedback about the GitHub CLI +title: '' +labels: feedback +assignees: '' + +--- + +# CLI Feedback + +You can use this template to give us structured feedback or just wipe it and leave us a note. Thank you! + +## What have you loved? + +_eg "the nice colors"_ + +## What was confusing or gave you pause? + +_eg "it did something unexpected"_ + +## Are there features you'd like to see added? + +_eg "gh cli needs mini-games"_ + +## Anything else? + +_eg "have a nice day"_ \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..038eef3 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,35 @@ +<!--- Provide a general summary of your changes in the Title above --> +<!--- To help with semantic versioning the PR title should start with one of the conventional commit types. --> +<!--- The conventional commit types for Semantic PR are: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert --> + +## Description +<!--- Describe your changes in detail --> + +## Motivation and Context +<!--- Why is this change required? What problem does it solve? --> +<!--- If it fixes an open issue, please link to the issue here. --> +closes # + +## Screenshots (if appropriate): + +## How Has This Been Tested? +<!--- Please describe in detail how you tested your changes. --> +<!--- Include details of your testing environment, tests ran to see how --> +<!--- your change affects other areas of the code, etc. --> +- [ ] I have tested using **MacOS** +- [ ] I have tested using **Linux** +- [ ] I have tested using **Windows** + +## Checklist: +<!--- Go over all the following points, and put an `x` in all the boxes that apply. --> +<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> +- [ ] I have updated the documentation accordingly. +- [ ] I have updated the tests accordingly. + +## Migration Guide + +> This section is optional. If there are no breaking changes, you can delete this section. + +- If this PR is a breaking change (relative to the last release of Bevy), describe how a user might need to migrate their code to support these changes +- Simply adding new functionality is not a breaking change. +- Fixing behavior that was definitely a bug, rather than a questionable design choice is not a breaking change. \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..8a8d9be --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,30 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "devcontainers" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + labels: + - "devcontainer" + - "dependencies" + + - package-ecosystem: "cargo" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + labels: + - "rust" + - "dependencies" + + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + labels: + - "GitHub Action" + - "dependencies" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..aaee570 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,70 @@ +# Configuration for Auto Labeler during pull request +# +# See https://github.com/actions/labeler for file format +# and https://github.com/google/flatbuffers/labels for a list of valid labels +# +# See .github/workflows/label.yml for Github Action workflow script + +rust: + - '**/*.rs' + - rust/**/* + - src/idl_gen_rust.cpp + +cargo: + - Cargo.toml + - Cargo.lock + - rust-toolchain + +code: + - src/**/* + +documentation: + - docs/**/* + - '**/*.md' + +CI: + - '.github/**/*' + - '.appveyor/**/*' + - '.travis/**/*' + - '.bazelci/**/*' + - .travis.yml + - appveyor.yml + +devcontainer: + - .devcontainer/**/* + +fuzzing: + - fuzz/**/* + +feature: + - head-branch: ['^feature', 'feature'] + +bug: + - head-branch: ['^bug', 'bug'] + +documentation: + - head-branch: ['^docs', 'docs'] + +chore: + - head-branch: ['^chore', 'chore'] + +ci: + - head-branch: ['^ci', 'ci'] + +build: + - head-branch: ['^build', 'build'] + +test: + - head-branch: ['^test', 'test'] + +perf: + - head-branch: ['^perf', 'perf'] + +fix: + - head-branch: ['^fix', 'fix'] + +refactor: + - head-branch: ['^refactor', 'refactor'] + +style: + - head-branch: ['^style', 'style'] \ No newline at end of file diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..8462989 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,17 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 60 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 14 +# Issues with these labels will never be considered stale +exemptLabels: + - pinned + - security +# Label to use when marking an issue as stale +staleLabel: wontfix +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false \ No newline at end of file diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml new file mode 100644 index 0000000..292ab5b --- /dev/null +++ b/.github/workflows/commit-lint.yml @@ -0,0 +1,43 @@ +name: Check if commit is conventional + +on: [push, pull_request] + +permissions: + contents: read + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + + commitlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install required dependencies + run: | + sudo apt update + sudo apt install -y sudo + sudo apt install -y git curl + curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - + sudo DEBIAN_FRONTEND=noninteractive apt install -y nodejs + - name: Print versions + run: | + git --version + node --version + npm --version + npx commitlint --version + - name: Install commitlint + run: | + npm install conventional-changelog-conventionalcommits + npm install commitlint@latest + + - name: Validate current commit (last commit) with commitlint + if: github.event_name == 'push' + run: npx commitlint --from HEAD~1 --to HEAD --verbose + + - name: Validate PR commits with commitlint + if: github.event_name == 'pull_request' + run: npx commitlint --from ${{ github.event.pull_request.head.sha }}~${{ github.event.pull_request.commits }} --to ${{ github.event.pull_request.head.sha }} --verbose \ No newline at end of file diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml new file mode 100644 index 0000000..ee4bdc7 --- /dev/null +++ b/.github/workflows/integration-test.yml @@ -0,0 +1,222 @@ +name: Integration test for Rust + +on: + push: + branches: main + paths: ['deny.toml', 'src/**', 'benches/**', 'Cargo.toml', 'Cargo.lock', '.github/workflows/integration-test.yml'] + pull_request: + branches: main + paths: ['deny.toml', 'src/**', 'benches/**', 'Cargo.toml', 'Cargo.lock', '.github/workflows/integration-test.yml'] + +env: + MOLD_VERSION: 2.4.0 + CARGO_TERM_COLOR: always + +jobs: + + cargo_check: + name: Cargo Check + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install Rust nightly + uses: dtolnay/rust-toolchain@master + id: rust-toolchain + with: + toolchain: nightly + - name: Install cargo-make + uses: taiki-e/install-action@cargo-make + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + - name: Run cargo make check + run: cargo make check + env: + RUST_BACKTRACE: full + + cargo_fmt: + name: Cargo Format + needs: [cargo_check] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install Rust nightly + uses: dtolnay/rust-toolchain@master + id: rust-toolchain + with: + toolchain: nightly + components: rustfmt + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + - name: Check formatting + run: cargo fmt -- --check + - name: Check documentation + run: cargo doc --no-deps --all-features + - name: Check typos + uses: crate-ci/typos@master + - name: Lint dependencies + uses: EmbarkStudios/cargo-deny-action@v1 + + cargo_clippy: + name: Cargo Clippy + needs: [cargo_check] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust nightly + uses: dtolnay/rust-toolchain@master + id: rust-toolchain + with: + toolchain: nightly + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + - uses: rui314/setup-mold@v1 + with: + mold-version: ${{ env.MOLD_VERSION }} + - name: Add clippy + run: rustup component add clippy + - name: Run clippy + run: cargo clippy + + cargo_test: + name: Cargo Test + needs: [cargo_fmt , cargo_clippy] + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Install Rust nightly + uses: dtolnay/rust-toolchain@master + id: rust-toolchain + with: + toolchain: nightly + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + - uses: rui314/setup-mold@v1 + with: + mold-version: ${{ env.MOLD_VERSION }} + - name: cargo test + run: cargo test + + cargo_mutants: # https://mutants.rs + name: Cargo Mutants + needs: [cargo_test] + runs-on: ubuntu-latest + permissions: + pull-requests: write + continue-on-error: true + steps: + - uses: actions/checkout@v4 + - name: Install Rust nightly + uses: dtolnay/rust-toolchain@master + id: rust-toolchain + with: + toolchain: nightly + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + - uses: taiki-e/install-action@v2 + name: Install cargo-mutants using install-action + with: + tool: cargo-mutants + - name: Run mutant tests + run: cargo mutants -vV --in-place + continue-on-error: true + - uses: mshick/add-pr-comment@v2 + if: always() + with: + message-path: mutants.out/missed.txt + + cargo_coverage: + name: Cargo Coverage + needs: [cargo_test] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust nightly + uses: dtolnay/rust-toolchain@master + id: rust-toolchain + with: + toolchain: nightly + components: llvm-tools + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + - name: cargo install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + - name: cargo llvm-cov + run: cargo llvm-cov --all-features --lcov --output-path lcov.info + env: + CARGO_HUSKY_DONT_INSTALL_HOOKS: true + - name: Upload to codecov.io + uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: true + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + cargo_fuzzing: # https://rust-fuzz.github.io/book/cargo-fuzz + name: Cargo Fuzzing + needs: [cargo_test] + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - uses: actions/checkout@v4 + - name: Install Rust nightly + uses: dtolnay/rust-toolchain@master + id: rust-toolchain + with: + toolchain: nightly + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + - uses: taiki-e/install-action@v2 + name: Install cargo-fuzz using install-action + with: + tool: cargo-fuzz + - name: Run mutant tests + id: fuzz + run: cargo fuzz run fuzz_play_game -- -max_len=4 -max_total_time=180 + - name: upload artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + name: fuzzing + path: fuzz/artifacts + - uses: mshick/add-pr-comment@v2 + if: failure() + with: + message: "Fuzzing failed, artifacts are uploaded." + + + cargo_bench: + name: Cargo Bench + needs: [cargo_test] + runs-on: ubuntu-latest + permissions: + pull-requests: write + env: + BENCHER_PROJECT: rust-template + BENCHER_TESTBED: ubuntu-latest + BENCHER_ADAPTER: rust + BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }} + steps: + - uses: actions/checkout@v4 + - uses: bencherdev/bencher@main + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + - name: Dogfooding Benchmarks with Bencher + run: | + bencher run \ + --if-branch "$GITHUB_REF_NAME" \ + --else-if-branch "$GITHUB_BASE_REF" \ + --err \ + --github-actions ${{ secrets.GITHUB_TOKEN }} \ + "cargo bench" \ No newline at end of file diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml new file mode 100644 index 0000000..d23c4d4 --- /dev/null +++ b/.github/workflows/label.yml @@ -0,0 +1,22 @@ +# This workflow will triage pull requests and apply a label based on the +# paths that are modified in the pull request. +# +# To use this workflow, you will need to set up a .github/labeler.yml +# file with configuration. For more information, see: +# https://github.com/actions/labeler + +name: Labeler +on: [pull_request_target] + +jobs: + label: + + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + + steps: + - uses: actions/labeler@v5 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..22b0881 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,171 @@ +name: Cargo release + +on: + release: + types: [created] + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + RUST_BACKTRACE: short + RUSTUP_MAX_RETRIES: 10 + MACOSX_DEPLOYMENT_TARGET: 10.7 + +jobs: + + # Build sources for every OS + cargo_build: + name: Build release binaries + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + name: rust-template-x86_64-unknown-linux-gnu.tar.gz + + - target: x86_64-unknown-linux-musl + os: ubuntu-latest + name: rust-template-x86_64-unknown-linux-musl.tar.gz + + - target: i686-unknown-linux-musl + os: ubuntu-latest + name: rust-template-i686-unknown-linux-musl.tar.gz + + - target: aarch64-unknown-linux-musl + os: ubuntu-latest + name: rust-template-aarch64-unknown-linux-musl.tar.gz + + - target: arm-unknown-linux-musleabihf + os: ubuntu-latest + name: rust-template-arm-unknown-linux-musleabihf.tar.gz + + - target: x86_64-apple-darwin + os: macOS-11 + name: rust-template-x86_64-apple-darwin.tar.gz + + - target: aarch64-apple-darwin + os: macOS-11 + name: rust-template-aarch64-apple-darwin.tar.gz + + - target: x86_64-pc-windows-msvc + os: windows-latest + name: rust-template-x86_64-pc-windows-msvc.zip + rustflags: -C target-feature=+crt-static + + - target: i686-pc-windows-msvc + os: windows-latest + name: rust-template-i686-pc-windows-msvc.zip + rustflags: -C target-feature=+crt-static + + - target: aarch64-pc-windows-msvc + os: windows-latest + name: rust-template-aarch64-pc-windows-msvc.zip + rustflags: -C target-feature=+crt-static + + - target: x86_64-unknown-freebsd + os: ubuntu-latest + name: rust-template-x86_64-unknown-freebsd.tar.gz + + runs-on: ${{ matrix.os }} + continue-on-error: true + env: + RUSTFLAGS: ${{ matrix.rustflags || '' }} + steps: + - name: Setup | Checkout + uses: actions/checkout@v4 + + - name: Setup | Rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: nightly + target: ${{ matrix.target }} + + - name: Setup | Install cargo-wix [Windows] + continue-on-error: true + # aarch64 is only supported in wix 4.0 development builds + if: matrix.os == 'windows-latest' && matrix.target != 'aarch64-pc-windows-msvc' + run: cargo install --version 0.3.4 cargo-wix + env: + # cargo-wix does not require static crt + RUSTFLAGS: "" + + - name: Setup | Install cross [Linux] + if: matrix.os == 'ubuntu-latest' + uses: taiki-e/install-action@cross + + - name: Build | Build [Cargo] + if: matrix.os != 'ubuntu-latest' + run: cargo build --release --target ${{ matrix.target }} + + - name: Build | Build [Cross] + if: matrix.os == 'ubuntu-latest' + run: cross build --release --target ${{ matrix.target }} + + - name: Build | Installer [Windows] + continue-on-error: true + if: matrix.os == 'windows-latest' && matrix.target != 'aarch64-pc-windows-msvc' + run: > + cargo wix -v --no-build --nocapture -I install/windows/main.wxs + --target ${{ matrix.target }} + --output target/wix/rust-template-${{ matrix.target }}.msi + + - name: Post Build | Prepare artifacts [Windows] + if: matrix.os == 'windows-latest' + run: | + cd target/${{ matrix.target }}/release + 7z a ../../../${{ matrix.name }} rust-template.exe + cd - + + - name: Post Build | Prepare artifacts [-nix] + if: matrix.os != 'windows-latest' + run: | + cd target/${{ matrix.target }}/release + tar czvf ../../../${{ matrix.name }} rust-template + cd - + + - name: Release | Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.name }} + path: ${{ matrix.name }} + + - name: Release | Upload installer artifacts [Windows] + continue-on-error: true + if: matrix.os == 'windows-latest' && matrix.target != 'aarch64-pc-windows-msvc' + uses: actions/upload-artifact@v4 + with: + name: rust-template-${{ matrix.target }}.msi + path: target/wix/rust-template-${{ matrix.target }}.msi + + + upload_artifacts: + name: Add Build Artifacts to Release + needs: [cargo_build] + runs-on: ubuntu-latest + steps: + - name: Setup | Artifacts + uses: actions/download-artifact@v4 + + - name: Setup | Checksums + run: for file in rust-template-*/rust-template-*; do openssl dgst -sha256 -r "$file" | awk '{print $1}' > "${file}.sha256"; done + + - name: Build | Add Artifacts to Release + uses: softprops/action-gh-release@v1 + with: + files: rust-template-*/rust-template-* + tag_name: ${{ github.ref }} + + # Publish rust-template to Crates.io + cargo_publish: + name: Publish Cargo Package + runs-on: ubuntu-latest + steps: + - name: Setup | Checkout + uses: actions/checkout@v4 + + - name: Setup | Rust + uses: dtolnay/rust-toolchain@nightly + + - name: Build | Publish + run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/security-audit.yml b/.github/workflows/security-audit.yml new file mode 100644 index 0000000..c2f1b80 --- /dev/null +++ b/.github/workflows/security-audit.yml @@ -0,0 +1,83 @@ +name: Security audit + +on: + push: + branches: + - $default-branch + pull_request: + +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + CLICOLOR: 1 + +jobs: + cargo_udep: + name: Cargo check dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Rust nightly + uses: dtolnay/rust-toolchain@nightly + - name: Install cargo-binstall + uses: cargo-bins/cargo-binstall@main + - name: Install udeps + run: cargo binstall cargo-udeps -y + - name: Run udeps + run: cargo +nightly udeps + + security_audit: + permissions: + issues: write # to create issues (actions-rs/audit-check) + checks: write # to create check (actions-rs/audit-check) + runs-on: ubuntu-latest + # Prevent sudden announcement of a new advisory from failing ci: + continue-on-error: true + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - uses: actions-rs/audit-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + cargo_deny: + permissions: + issues: write # to create issues (actions-rs/audit-check) + checks: write # to create check (actions-rs/audit-check) + runs-on: ubuntu-latest + strategy: + matrix: + checks: + - bans licenses sources + steps: + - uses: actions/checkout@v4 + - uses: EmbarkStudios/cargo-deny-action@v1 + with: + command: check ${{ matrix.checks }} + rust-version: nightly + + # cargo_prusti: + # name: Cargo Prusti static analysis + # permissions: + # issues: write # to create issues (actions-rs/audit-check) + # checks: write # to create check (actions-rs/audit-check) + # pull-requests: write + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # - uses: viperproject/prusti-action@master + # with: + # path: . + + cargo_Rudra: + name: Cargo Rudra check memory safety + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Rudra + uses: sslab-gatech/Rudra@master + + +# Possible other tools: +# https://github.com/model-checking/kani +# https://github.com/mcarton/rust-herbie-lint \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20ec9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# Mutants +mutants.* \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8534290 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "template_exercisme" +description = "Rust template that contains automatic benchmarking, automatic mutation testing, automatic fuzz testing. " +repository = "https://github.com/MathieuSoysal/Exercism-Rust-Template" +readme = "README.md" +version = "0.1.0" +authors = ["MathieuSoysal <hsoysal@student.42.fr>"] +license = "Apache-2.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +# [dependencies] +# prusti-contracts = "0.2.0" \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..759764b --- /dev/null +++ b/LICENSE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright [2024] [MathieuSoysal] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/LICENSE -APACHE b/LICENSE -APACHE new file mode 100644 index 0000000..759764b --- /dev/null +++ b/LICENSE -APACHE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright [2024] [MathieuSoysal] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e8d2da --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +# <img src="https://www.rust-lang.org/logos/rust-logo-blk.svg" width="100"> Rust template ![GitHub License](https://img.shields.io/github/license/MathieuSoysal/Exercism-Rust-Template) +[![Static Badge](https://img.shields.io/badge/online-green?logo=gamejolt&logoColor=white&label=Benchmark%20tracks&labelColor=black&link=https%3A%2F%2Fbencher.dev%2Fconsole%2Fprojects%2Frust-template)](https://bencher.dev/console/projects/rust-template) +[![codecov](https://codecov.io/gh/MathieuSoysal/Exercism-Rust-Template/graph/badge.svg?token=MrM1EEfgvD)](https://codecov.io/gh/MathieuSoysal/Exercism-Rust-Template) +[![Integration test for Rust](https://github.com/MathieuSoysal/Exercism-Rust-Template/actions/workflows/integration-test.yml/badge.svg)](https://github.com/MathieuSoysal/Exercism-Rust-Template/actions/workflows/integration-test.yml) + +[Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) + + +Rust template that contains automatic benchmarking, automatic mutation testing, automatic fuzz testing. + +## Resources + +- Benchmark tool : https://bencher.dev/learn/benchmarking/rust/libtest-bench/ +- Benchmark CI : https://bencher.dev/docs/how-to/github-actions/ +- mutation testing : https://mutants.rs +- Code coverage : https://codecov.io/gh/MathieuSoysal/Exercism-Rust-Template +- Crate publish: https://crates.io/settings/tokens +- Crate prusti : https://viperproject.github.io/prusti-dev/user-guide/tour/getting-started + +## Customizing template + +### Ctrl + Shift + F for replace: +- [ ] `Rust template` -> with your project name +- [ ] `template-exercisme` -> with your rust project name +- [ ] `Exercism-Rust-Template` -> with your GitHub repository name +- [ ] `rust-template` -> with your Bencher project name +- [ ] `MathieuSoysal` -> with your GitHub username +- [ ] `2024` -> with the current year +- [ ] `Rust template that contains automatic benchmarking, automatic mutation testing, automatic fuzz testing. ` -> with your project description + +### Secrets +- [ ] Add `BENCHER_API_KEY` in your repository secrets +- [ ] Add `CODECOV_TOKEN` in your repository secrets +- [ ] Add `CARGO_REGISTRY_TOKEN` in your repository secrets + +## 🚀 Installation + + +<details> +<summary>MacOS</summary> +Install the latest version for your system: + +```bash +curl -sS https://raw.githubusercontent.com/MathieuSoysal/Exercisme-Rust-Template/main/install/install.sh | sh +``` +</details> + +<details> +<summary>Linux</summary> + +Install the latest version for your system: +```bash +curl -sS https://raw.githubusercontent.com/MathieuSoysal/Exercisme-Rust-Template/main/install/install.sh | sh +``` +</details> + +<details> +<summary>Windows</summary> + +Install the latest version for your system: [Install](https://github.com/MathieuSoysal/Exercisme-Rust-Template/releases/latest/download/starship-x86_64-pc-windows-msvc.msi) + +</details> + +## 🤝 Contributing + +We are always looking for contributors of **all skill levels**! If you're looking to ease your way into the project, try out a [good first issue](https://github.com/MathieuSoysal/Exercism-Rust-Template/labels/🌱%20good%20first%20issue). + +If you are interested in helping contribute to Rust template, don't hesitate to create your issue [Create new Issue](https://github.com/MathieuSoysal/Exercism-Rust-Template/issues/new/choose). + +### 🚀 Quick start contributing + +**Quick start contributing** you just need to click to this link [Start Online Devcontainer](https://codespaces.new/MathieuSoysal/Exercism-Rust-Template?quickstart=1) to automatically create a development environment for this project and start contributing ;) and you can also read the [CONTRIBUTING.md](./.github/CONTRIBUTING.md) + +## 📝 License + +Copyright © 2019-present, [Rust template Contributors](https://github.com/MathieuSoysal/Exercism-Rust-Template/graphs/contributors).<br> +This project is [ISC](https://github.com/MathieuSoysal/Exercism-Rust-Template/blob/main/LICENSE) licensed. + +## ⭐️ Support project + +If you like this project, feel free to support it by clicking on the ⭐️ button. \ No newline at end of file diff --git a/commitlint.config.ts b/commitlint.config.ts new file mode 100644 index 0000000..80164d4 --- /dev/null +++ b/commitlint.config.ts @@ -0,0 +1,146 @@ +import { + RuleConfigCondition, + RuleConfigSeverity, + TargetCaseType, +} from '@commitlint/types'; + +export default { + parserPreset: 'conventional-changelog-conventionalcommits', + rules: { + 'body-leading-blank': [RuleConfigSeverity.Warning, 'always'] as const, + 'body-max-line-length': [RuleConfigSeverity.Error, 'always', 100] as const, + 'footer-leading-blank': [RuleConfigSeverity.Warning, 'always'] as const, + 'footer-max-line-length': [ + RuleConfigSeverity.Error, + 'always', + 100, + ] as const, + 'header-max-length': [RuleConfigSeverity.Error, 'always', 100] as const, + 'header-trim': [RuleConfigSeverity.Error, 'always'] as const, + 'subject-case': [ + RuleConfigSeverity.Error, + 'never', + ['sentence-case', 'start-case', 'pascal-case', 'upper-case'], + ] as [RuleConfigSeverity, RuleConfigCondition, TargetCaseType[]], + 'subject-empty': [RuleConfigSeverity.Error, 'never'] as const, + 'subject-full-stop': [RuleConfigSeverity.Error, 'never', '.'] as const, + 'type-case': [RuleConfigSeverity.Error, 'always', 'lower-case'] as const, + 'type-empty': [RuleConfigSeverity.Error, 'never'] as const, + 'type-enum': [ + RuleConfigSeverity.Error, + 'always', + [ + 'build', + 'chore', + 'ci', + 'docs', + 'feat', + 'fix', + 'perf', + 'refactor', + 'revert', + 'style', + 'test', + ], + ] as [RuleConfigSeverity, RuleConfigCondition, string[]], + }, + prompt: { + questions: { + type: { + description: "Select the type of change that you're committing", + enum: { + feat: { + description: 'A new feature', + title: 'Features', + emoji: '✨', + }, + fix: { + description: 'A bug fix', + title: 'Bug Fixes', + emoji: '🐛', + }, + docs: { + description: 'Documentation only changes', + title: 'Documentation', + emoji: '📚', + }, + style: { + description: + 'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)', + title: 'Styles', + emoji: '💎', + }, + refactor: { + description: + 'A code change that neither fixes a bug nor adds a feature', + title: 'Code Refactoring', + emoji: '📦', + }, + perf: { + description: 'A code change that improves performance', + title: 'Performance Improvements', + emoji: '🚀', + }, + test: { + description: 'Adding missing tests or correcting existing tests', + title: 'Tests', + emoji: '🚨', + }, + build: { + description: + 'Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)', + title: 'Builds', + emoji: '🛠', + }, + ci: { + description: + 'Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)', + title: 'Continuous Integrations', + emoji: '⚙️', + }, + chore: { + description: "Other changes that don't modify src or test files", + title: 'Chores', + emoji: '♻️', + }, + revert: { + description: 'Reverts a previous commit', + title: 'Reverts', + emoji: '🗑', + }, + }, + }, + scope: { + description: + 'What is the scope of this change (e.g. component or file name)', + }, + subject: { + description: + 'Write a short, imperative tense description of the change', + }, + body: { + description: 'Provide a longer description of the change', + }, + isBreaking: { + description: 'Are there any breaking changes?', + }, + breakingBody: { + description: + 'A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself', + }, + breaking: { + description: 'Describe the breaking changes', + }, + isIssueAffected: { + description: 'Does this change affect any open issues?', + }, + issuesBody: { + description: + 'If issues are closed, the commit requires a body. Please enter a longer description of the commit itself', + }, + issues: { + description: 'Add issue references (e.g. "fix #123", "re #123".)', + }, + }, + }, +}; \ No newline at end of file diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000..7ffb1ea --- /dev/null +++ b/deny.toml @@ -0,0 +1,269 @@ +# This template contains all of the possible sections and their default values + +# Note that all fields that take a lint level have these possible values: +# * deny - An error will be produced and the check will fail +# * warn - A warning will be produced, but the check will not fail +# * allow - No warning or error will be produced, though in some cases a note +# will be + +# The values provided in this template are the default values that will be used +# when any section or field is not specified in your own configuration + +# Root options + +# If 1 or more target triples (and optionally, target_features) are specified, +# only the specified targets will be checked when running `cargo deny check`. +# This means, if a particular package is only ever used as a target specific +# dependency, such as, for example, the `nix` crate only being used via the +# `target_family = "unix"` configuration, that only having windows targets in +# this list would mean the nix crate, as well as any of its exclusive +# dependencies not shared by any other crates, would be ignored, as the target +# list here is effectively saying which targets you are building for. +targets = [ + # The triple can be any string, but only the target triples built in to + # rustc (as of 1.40) can be checked against actual config expressions + #{ triple = "x86_64-unknown-linux-musl" }, + # You can also specify which target_features you promise are enabled for a + # particular target. target_features are currently not validated against + # the actual valid features supported by the target architecture. + #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, +] +# When creating the dependency graph used as the source of truth when checks are +# executed, this field can be used to prune crates from the graph, removing them +# from the view of cargo-deny. This is an extremely heavy hammer, as if a crate +# is pruned from the graph, all of its dependencies will also be pruned unless +# they are connected to another crate in the graph that hasn't been pruned, +# so it should be used with care. The identifiers are [Package ID Specifications] +# (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html) +#exclude = [] +# If true, metadata will be collected with `--all-features`. Note that this can't +# be toggled off if true, if you want to conditionally enable `--all-features` it +# is recommended to pass `--all-features` on the cmd line instead +all-features = false +# If true, metadata will be collected with `--no-default-features`. The same +# caveat with `all-features` applies +no-default-features = false +# If set, these feature will be enabled when collecting metadata. If `--features` +# is specified on the cmd line they will take precedence over this option. +#features = [] +# When outputting inclusion graphs in diagnostics that include features, this +# option can be used to specify the depth at which feature edges will be added. +# This option is included since the graphs can be quite large and the addition +# of features from the crate(s) to all of the graph roots can be far too verbose. +# This option can be overridden via `--feature-depth` on the cmd line +feature-depth = 1 + +# This section is considered when running `cargo deny check advisories` +# More documentation for the advisories section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html +[advisories] +# The path where the advisory database is cloned/fetched into +db-path = "~/.cargo/advisory-db" +# The url(s) of the advisory databases to use +db-urls = ["https://github.com/rustsec/advisory-db"] +# The lint level for security vulnerabilities +vulnerability = "deny" +# The lint level for unmaintained crates +unmaintained = "warn" +# The lint level for crates that have been yanked from their source registry +yanked = "warn" +# The lint level for crates with security notices. +notice = "warn" +# A list of advisory IDs to ignore. Note that ignored advisories will still +# output a note when they are encountered. +ignore = [ + #"RUSTSEC-0000-0000", +] +# Threshold for security vulnerabilities, any vulnerability with a CVSS score +# lower than the range specified will be ignored. Note that ignored advisories +# will still output a note when they are encountered. +# * None - CVSS Score 0.0 +# * Low - CVSS Score 0.1 - 3.9 +# * Medium - CVSS Score 4.0 - 6.9 +# * High - CVSS Score 7.0 - 8.9 +# * Critical - CVSS Score 9.0 - 10.0 +#severity-threshold = + +# If this is true, then cargo deny will use the git executable to fetch advisory database. +# If this is false, then it uses a built-in git library. +# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support. +# See Git Authentication for more information about setting up git authentication. +#git-fetch-with-cli = true + +# This section is considered when running `cargo deny check licenses` +# More documentation for the licenses section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html +[licenses] +# The lint level for crates which do not have a detectable license +unlicensed = "deny" +# List of explicitly allowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. +allow = [ + #"MIT", + "Apache-2.0", + #"Apache-2.0 WITH LLVM-exception", +] +# List of explicitly disallowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. +deny = [ + #"Nokia", +] +# Lint level for licenses considered copyleft +copyleft = "warn" +# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses +# * both - The license will be approved if it is both OSI-approved *AND* FSF +# * either - The license will be approved if it is either OSI-approved *OR* FSF +# * osi - The license will be approved if it is OSI approved +# * fsf - The license will be approved if it is FSF Free +# * osi-only - The license will be approved if it is OSI-approved *AND NOT* FSF +# * fsf-only - The license will be approved if it is FSF *AND NOT* OSI-approved +# * neither - This predicate is ignored and the default lint level is used +allow-osi-fsf-free = "neither" +# Lint level used when no other predicates are matched +# 1. License isn't in the allow or deny lists +# 2. License isn't copyleft +# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither" +default = "deny" +# The confidence threshold for detecting a license from license text. +# The higher the value, the more closely the license text must be to the +# canonical license text of a valid SPDX license file. +# [possible values: any between 0.0 and 1.0]. +confidence-threshold = 0.8 +# Allow 1 or more licenses on a per-crate basis, so that particular licenses +# aren't accepted for every possible crate as with the normal allow list +exceptions = [ + # Each entry is the crate and version constraint, and its specific allow + # list + #{ allow = ["Zlib"], name = "adler32", version = "*" }, +] + +# Some crates don't have (easily) machine readable licensing information, +# adding a clarification entry for it allows you to manually specify the +# licensing information +#[[licenses.clarify]] +# The name of the crate the clarification applies to +#name = "ring" +# The optional version constraint for the crate +#version = "*" +# The SPDX expression for the license requirements of the crate +#expression = "MIT AND ISC AND OpenSSL" +# One or more files in the crate's source used as the "source of truth" for +# the license expression. If the contents match, the clarification will be used +# when running the license check, otherwise the clarification will be ignored +# and the crate will be checked normally, which may produce warnings or errors +# depending on the rest of your configuration +#license-files = [ + # Each entry is a crate relative path, and the (opaque) hash of its contents + #{ path = "LICENSE", hash = 0xbd0eed23 } +#] + +[licenses.private] +# If true, ignores workspace crates that aren't published, or are only +# published to private registries. +# To see how to mark a crate as unpublished (to the official registry), +# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field. +ignore = false +# One or more private registries that you might publish crates to, if a crate +# is only published to private registries, and ignore is true, the crate will +# not have its license(s) checked +registries = [ + #"https://sekretz.com/registry +] + +# This section is considered when running `cargo deny check bans`. +# More documentation about the 'bans' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html +[bans] +# Lint level for when multiple versions of the same crate are detected +multiple-versions = "warn" +# Lint level for when a crate version requirement is `*` +wildcards = "allow" +# The graph highlighting used when creating dotgraphs for crates +# with multiple versions +# * lowest-version - The path to the lowest versioned duplicate is highlighted +# * simplest-path - The path to the version with the fewest edges is highlighted +# * all - Both lowest-version and simplest-path are used +highlight = "all" +# The default lint level for `default` features for crates that are members of +# the workspace that is being checked. This can be overridden by allowing/denying +# `default` on a crate-by-crate basis if desired. +workspace-default-features = "allow" +# The default lint level for `default` features for external crates that are not +# members of the workspace. This can be overridden by allowing/denying `default` +# on a crate-by-crate basis if desired. +external-default-features = "allow" +# List of crates that are allowed. Use with care! +allow = [ + #{ name = "ansi_term", version = "=0.11.0" }, +] +# List of crates to deny +deny = [ + # Each entry the name of a crate and a version range. If version is + # not specified, all versions will be matched. + #{ name = "ansi_term", version = "=0.11.0" }, + # + # Wrapper crates can optionally be specified to allow the crate when it + # is a direct dependency of the otherwise banned crate + #{ name = "ansi_term", version = "=0.11.0", wrappers = [] }, +] + +# List of features to allow/deny +# Each entry the name of a crate and a version range. If version is +# not specified, all versions will be matched. +#[[bans.features]] +#name = "reqwest" +# Features to not allow +#deny = ["json"] +# Features to allow +#allow = [ +# "rustls", +# "__rustls", +# "__tls", +# "hyper-rustls", +# "rustls", +# "rustls-pemfile", +# "rustls-tls-webpki-roots", +# "tokio-rustls", +# "webpki-roots", +#] +# If true, the allowed features must exactly match the enabled feature set. If +# this is set there is no point setting `deny` +#exact = true + +# Certain crates/versions that will be skipped when doing duplicate detection. +skip = [ + #{ name = "ansi_term", version = "=0.11.0" }, +] +# Similarly to `skip` allows you to skip certain crates during duplicate +# detection. Unlike skip, it also includes the entire tree of transitive +# dependencies starting at the specified crate, up to a certain depth, which is +# by default infinite. +skip-tree = [ + #{ name = "ansi_term", version = "=0.11.0", depth = 20 }, +] + +# This section is considered when running `cargo deny check sources`. +# More documentation about the 'sources' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html +[sources] +# Lint level for what to happen when a crate from a crate registry that is not +# in the allow list is encountered +unknown-registry = "warn" +# Lint level for what to happen when a crate from a git repository that is not +# in the allow list is encountered +unknown-git = "warn" +# List of URLs for allowed crate registries. Defaults to the crates.io index +# if not specified. If it is specified but empty, no registries are allowed. +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +# List of URLs for allowed Git repositories +allow-git = [] + +[sources.allow-org] +# 1 or more github.com organizations to allow git sources for +github = [""] +# 1 or more gitlab.com organizations to allow git sources for +gitlab = [""] +# 1 or more bitbucket.org organizations to allow git sources for +bitbucket = [""] diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..1a45eee --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,4 @@ +target +corpus +artifacts +coverage diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..993cae0 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "template-exercisme-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" + +[dependencies.template_exercisme] +path = ".." + +[[bin]] +name = "fuzz_play_game" +path = "fuzz_targets/fuzz_play_game.rs" +test = false +doc = false +bench = false diff --git a/fuzz/fuzz_targets/fuzz_play_game.rs b/fuzz/fuzz_targets/fuzz_play_game.rs new file mode 100644 index 0000000..24efb78 --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_play_game.rs @@ -0,0 +1,11 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +#[macro_use] +extern crate libfuzzer_sys; + +use template_exercisme::fizz_buzz_fibonacci; + +fuzz_target!(|data: u32| { + fizz_buzz_fibonacci(data); +}); diff --git a/install/install.sh b/install/install.sh new file mode 100644 index 0000000..cf82644 --- /dev/null +++ b/install/install.sh @@ -0,0 +1,448 @@ +#!/usr/bin/env sh + +set -eu +printf '\n' + +BOLD="$(tput bold 2>/dev/null || printf '')" +GREY="$(tput setaf 0 2>/dev/null || printf '')" +UNDERLINE="$(tput smul 2>/dev/null || printf '')" +RED="$(tput setaf 1 2>/dev/null || printf '')" +GREEN="$(tput setaf 2 2>/dev/null || printf '')" +YELLOW="$(tput setaf 3 2>/dev/null || printf '')" +BLUE="$(tput setaf 4 2>/dev/null || printf '')" +MAGENTA="$(tput setaf 5 2>/dev/null || printf '')" +NO_COLOR="$(tput sgr0 2>/dev/null || printf '')" + +SUPPORTED_TARGETS="x86_64-unknown-linux-gnu x86_64-unknown-linux-musl \ + i686-unknown-linux-musl aarch64-unknown-linux-musl \ + arm-unknown-linux-musleabihf x86_64-apple-darwin \ + aarch64-apple-darwin x86_64-pc-windows-msvc \ + i686-pc-windows-msvc aarch64-pc-windows-msvc \ + x86_64-unknown-freebsd" + +info() { + printf '%s\n' "${BOLD}${GREY}>${NO_COLOR} $*" +} + +warn() { + printf '%s\n' "${YELLOW}! $*${NO_COLOR}" +} + +error() { + printf '%s\n' "${RED}x $*${NO_COLOR}" >&2 +} + +completed() { + printf '%s\n' "${GREEN}✓${NO_COLOR} $*" +} + +has() { + command -v "$1" 1>/dev/null 2>&1 +} + +curl_is_snap() { + curl_path="$(command -v curl)" + case "$curl_path" in + /snap/*) return 0 ;; + *) return 1 ;; + esac +} + +# Make sure user is not using zsh or non-POSIX-mode bash, which can cause issues +verify_shell_is_posix_or_exit() { + if [ -n "${ZSH_VERSION+x}" ]; then + error "Running installation script with \`zsh\` is known to cause errors." + error "Please use \`sh\` instead." + exit 1 + elif [ -n "${BASH_VERSION+x}" ] && [ -z "${POSIXLY_CORRECT+x}" ]; then + error "Running installation script with non-POSIX \`bash\` may cause errors." + error "Please use \`sh\` instead." + exit 1 + else + true # No-op: no issues detected + fi +} + +get_tmpfile() { + suffix="$1" + if has mktemp; then + printf "%s.%s" "$(mktemp)" "${suffix}" + else + # No really good options here--let's pick a default + hope + printf "/tmp/starship.%s" "${suffix}" + fi +} + +# Test if a location is writeable by trying to write to it. Windows does not let +# you test writeability other than by writing: https://stackoverflow.com/q/1999988 +test_writeable() { + path="${1:-}/test.txt" + if touch "${path}" 2>/dev/null; then + rm "${path}" + return 0 + else + return 1 + fi +} + +download() { + file="$1" + url="$2" + + if has curl && curl_is_snap; then + warn "curl installed through snap cannot download Rust template." + warn "See https://github.com/MathieuSoysal/Exercism-Rust-Template/issues/5403 for details." + warn "Searching for other HTTP download programs..." + fi + + if has curl && ! curl_is_snap; then + cmd="curl --fail --silent --location --output $file $url" + elif has wget; then + cmd="wget --quiet --output-document=$file $url" + elif has fetch; then + cmd="fetch --quiet --output=$file $url" + else + error "No HTTP download program (curl, wget, fetch) found, exiting…" + return 1 + fi + + $cmd && return 0 || rc=$? + + error "Command failed (exit code $rc): ${BLUE}${cmd}${NO_COLOR}" + printf "\n" >&2 + info "This is likely due to Rust template not yet supporting your configuration." + info "If you would like to see a build for your configuration," + info "please create an issue requesting a build for ${MAGENTA}${TARGET}${NO_COLOR}:" + info "${BOLD}${UNDERLINE}https://github.com/MathieuSoysal/Exercism-Rust-Template/issues/new/${NO_COLOR}" + return $rc +} + +unpack() { + archive=$1 + bin_dir=$2 + sudo=${3-} + + case "$archive" in + *.tar.gz) + flags=$(test -n "${VERBOSE-}" && echo "-xzvof" || echo "-xzof") + ${sudo} tar "${flags}" "${archive}" -C "${bin_dir}" + return 0 + ;; + *.zip) + flags=$(test -z "${VERBOSE-}" && echo "-qqo" || echo "-o") + UNZIP="${flags}" ${sudo} unzip "${archive}" -d "${bin_dir}" + return 0 + ;; + esac + + error "Unknown package extension." + printf "\n" + info "This almost certainly results from a bug in this script--please file a" + info "bug report at https://github.com/MathieuSoysal/Exercism-Rust-Template/issues" + return 1 +} + +usage() { + printf "%s\n" \ + "install.sh [option]" \ + "" \ + "Fetch and install the latest version of Rust template, if Rust template is already" \ + "installed it will be updated to the latest version." + + printf "\n%s\n" "Options" + printf "\t%s\n\t\t%s\n\n" \ + "-V, --verbose" "Enable verbose output for the installer" \ + "-f, -y, --force, --yes" "Skip the confirmation prompt during installation" \ + "-p, --platform" "Override the platform identified by the installer [default: ${PLATFORM}]" \ + "-b, --bin-dir" "Override the bin installation directory [default: ${BIN_DIR}]" \ + "-a, --arch" "Override the architecture identified by the installer [default: ${ARCH}]" \ + "-B, --base-url" "Override the base URL used for downloading releases [default: ${BASE_URL}]" \ + "-h, --help" "Display this help message" +} + +elevate_priv() { + if ! has sudo; then + error 'Could not find the command "sudo", needed to get permissions for install.' + info "If you are on Windows, please run your shell as an administrator, then" + info "rerun this script. Otherwise, please run this script as root, or install" + info "sudo." + exit 1 + fi + if ! sudo -v; then + error "Superuser not granted, aborting installation" + exit 1 + fi +} + +install() { + ext="$1" + + if test_writeable "${BIN_DIR}"; then + sudo="" + msg="Installing Rust template, please wait…" + else + warn "Escalated permissions are required to install to ${BIN_DIR}" + elevate_priv + sudo="sudo" + msg="Installing Rust template as root, please wait…" + fi + info "$msg" + + archive=$(get_tmpfile "$ext") + + # download to the temp file + download "${archive}" "${URL}" + + # unpack the temp file to the bin dir, using sudo if required + unpack "${archive}" "${BIN_DIR}" "${sudo}" +} + +# Currently supporting: +# - win (Git Bash) +# - darwin +# - linux +# - linux_musl (Alpine) +# - freebsd +detect_platform() { + platform="$(uname -s | tr '[:upper:]' '[:lower:]')" + + case "${platform}" in + msys_nt*) platform="pc-windows-msvc" ;; + cygwin_nt*) platform="pc-windows-msvc";; + # mingw is Git-Bash + mingw*) platform="pc-windows-msvc" ;; + # use the statically compiled musl bins on linux to avoid linking issues. + linux) platform="unknown-linux-musl" ;; + darwin) platform="apple-darwin" ;; + freebsd) platform="unknown-freebsd" ;; + esac + + printf '%s' "${platform}" +} + +# Currently supporting: +# - x86_64 +# - i386 +# - arm +# - arm64 +detect_arch() { + arch="$(uname -m | tr '[:upper:]' '[:lower:]')" + + case "${arch}" in + amd64) arch="x86_64" ;; + armv*) arch="arm" ;; + arm64) arch="aarch64" ;; + esac + + # `uname -m` in some cases miss-reports 32-bit OS as 64-bit, so double check + if [ "${arch}" = "x86_64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then + arch=i686 + elif [ "${arch}" = "aarch64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then + arch=arm + fi + + printf '%s' "${arch}" +} + +detect_target() { + arch="$1" + platform="$2" + target="$arch-$platform" + + if [ "${target}" = "arm-unknown-linux-musl" ]; then + target="${target}eabihf" + fi + + printf '%s' "${target}" +} + + +confirm() { + if [ -z "${FORCE-}" ]; then + printf "%s " "${MAGENTA}?${NO_COLOR} $* ${BOLD}[y/N]${NO_COLOR}" + set +e + read -r yn </dev/tty + rc=$? + set -e + if [ $rc -ne 0 ]; then + error "Error reading from prompt (please re-run with the '--yes' option)" + exit 1 + fi + if [ "$yn" != "y" ] && [ "$yn" != "yes" ]; then + error 'Aborting (please answer "yes" to continue)' + exit 1 + fi + fi +} + +check_bin_dir() { + bin_dir="${1%/}" + + if [ ! -d "$BIN_DIR" ]; then + error "Installation location $BIN_DIR does not appear to be a directory" + info "Make sure the location exists and is a directory, then try again." + usage + exit 1 + fi + + # https://stackoverflow.com/a/11655875 + good=$( + IFS=: + for path in $PATH; do + if [ "${path%/}" = "${bin_dir}" ]; then + printf 1 + break + fi + done + ) + + if [ "${good}" != "1" ]; then + warn "Bin directory ${bin_dir} is not in your \$PATH" + fi +} + +is_build_available() { + arch="$1" + platform="$2" + target="$3" + + good=$( + IFS=" " + for t in $SUPPORTED_TARGETS; do + if [ "${t}" = "${target}" ]; then + printf 1 + break + fi + done + ) + + if [ "${good}" != "1" ]; then + error "${arch} builds for ${platform} are not yet available for Rust template" + printf "\n" >&2 + info "If you would like to see a build for your configuration," + info "please create an issue requesting a build for ${MAGENTA}${target}${NO_COLOR}:" + info "${BOLD}${UNDERLINE}https://github.com/MathieuSoysal/Exercism-Rust-Template/issues/new/${NO_COLOR}" + printf "\n" + exit 1 + fi +} + +# defaults +if [ -z "${PLATFORM-}" ]; then + PLATFORM="$(detect_platform)" +fi + +if [ -z "${BIN_DIR-}" ]; then + BIN_DIR=/usr/local/bin +fi + +if [ -z "${ARCH-}" ]; then + ARCH="$(detect_arch)" +fi + +if [ -z "${BASE_URL-}" ]; then + BASE_URL="https://github.com/MathieuSoysal/Exercism-Rust-Template/releases" +fi + +# Non-POSIX shells can break once executing code due to semantic differences +verify_shell_is_posix_or_exit + +# parse argv variables +while [ "$#" -gt 0 ]; do + case "$1" in + -p | --platform) + PLATFORM="$2" + shift 2 + ;; + -b | --bin-dir) + BIN_DIR="$2" + shift 2 + ;; + -a | --arch) + ARCH="$2" + shift 2 + ;; + -B | --base-url) + BASE_URL="$2" + shift 2 + ;; + + -V | --verbose) + VERBOSE=1 + shift 1 + ;; + -f | -y | --force | --yes) + FORCE=1 + shift 1 + ;; + -h | --help) + usage + exit + ;; + + -p=* | --platform=*) + PLATFORM="${1#*=}" + shift 1 + ;; + -b=* | --bin-dir=*) + BIN_DIR="${1#*=}" + shift 1 + ;; + -a=* | --arch=*) + ARCH="${1#*=}" + shift 1 + ;; + -B=* | --base-url=*) + BASE_URL="${1#*=}" + shift 1 + ;; + -V=* | --verbose=*) + VERBOSE="${1#*=}" + shift 1 + ;; + -f=* | -y=* | --force=* | --yes=*) + FORCE="${1#*=}" + shift 1 + ;; + + *) + error "Unknown option: $1" + usage + exit 1 + ;; + esac +done + +TARGET="$(detect_target "${ARCH}" "${PLATFORM}")" + +is_build_available "${ARCH}" "${PLATFORM}" "${TARGET}" + +printf " %s\n" "${UNDERLINE}Configuration${NO_COLOR}" +info "${BOLD}Bin directory${NO_COLOR}: ${GREEN}${BIN_DIR}${NO_COLOR}" +info "${BOLD}Platform${NO_COLOR}: ${GREEN}${PLATFORM}${NO_COLOR}" +info "${BOLD}Arch${NO_COLOR}: ${GREEN}${ARCH}${NO_COLOR}" + +# non-empty VERBOSE enables verbose untarring +if [ -n "${VERBOSE-}" ]; then + VERBOSE=v + info "${BOLD}Verbose${NO_COLOR}: yes" +else + VERBOSE= +fi + +printf '\n' + +EXT=tar.gz +if [ "${PLATFORM}" = "pc-windows-msvc" ]; then + EXT=zip +fi + +URL="${BASE_URL}/latest/download/starship-${TARGET}.${EXT}" +info "Tarball URL: ${UNDERLINE}${BLUE}${URL}${NO_COLOR}" +confirm "Install Rust template ${GREEN}latest${NO_COLOR} to ${BOLD}${GREEN}${BIN_DIR}${NO_COLOR}?" +check_bin_dir "${BIN_DIR}" + +install "${EXT}" +completed "Rust template installed" + +printf '\n' diff --git a/install/windows/main.wxs b/install/windows/main.wxs new file mode 100644 index 0000000..c8ece4e --- /dev/null +++ b/install/windows/main.wxs @@ -0,0 +1,182 @@ +<?xml version='1.0' encoding='windows-1252'?> +<!-- + Copyright (C) 2017 Christopher R. Field. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- + The "cargo wix" subcommand provides a variety of predefined variables available + for customization of this template. The values for each variable are set at + installer creation time. The following variables are available: + + TargetTriple = The rustc target triple name. + TargetEnv = The rustc target environment. This is typically either + "msvc" or "gnu" depending on the toolchain downloaded and + installed. + TargetVendor = The rustc target vendor. This is typically "pc", but Rust + does support other vendors, like "uwp". + CargoTargetBinDir = The complete path to the binary (exe). The default would + be "target\release\<BINARY_NAME>.exe" where + "<BINARY_NAME>" is replaced with the name of each binary + target defined in the package's manifest (Cargo.toml). If + a different rustc target triple is used than the host, + i.e. cross-compiling, then the default path would be + "target\<CARGO_TARGET>\<CARGO_PROFILE>\<BINARY_NAME>.exe", + where "<CARGO_TARGET>" is replaced with the "CargoTarget" + variable value and "<CARGO_PROFILE>" is replaced with the + value from the `CargoProfile` variable. + CargoTargetDir = The path to the directory for the build artifacts, i.e. + "target". + CargoProfile = Either "debug" or `release` depending on the build + profile. The default is "release". + Version = The version for the installer. The default is the + "Major.Minor.Fix" semantic versioning number of the Rust + package. +--> + +<!-- + Please do not remove these pre-processor If-Else blocks. These are used with + the `cargo wix` subcommand to automatically determine the installation + destination for 32-bit versus 64-bit installers. Removal of these lines will + cause installation errors. +--> +<?if $(sys.BUILDARCH) = x64 or $(sys.BUILDARCH) = arm64?> +<?define PlatformProgramFilesFolder = "ProgramFiles64Folder"?> +<?else ?> +<?define PlatformProgramFilesFolder = "ProgramFilesFolder"?> +<?endif ?> + +<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'> + + <Product Id='*' Name='rust-template' UpgradeCode='0E489D6B-0FEA-4B6E-B57F-62DD1E892C46' Manufacturer='Rust template Contributors' Language='1033' Codepage='1252' Version='$(var.Version)'> + + <Package Id='*' Keywords='Installer' Description='Rust template that contains automatic benchmarking, automatic mutation testing, automatic fuzz testing. ' Manufacturer='Rust template Contributors' InstallerVersion='450' Languages='1033' Compressed='yes' InstallScope='perMachine' SummaryCodepage='1252' /> + + <MajorUpgrade Schedule='afterInstallInitialize' DowngradeErrorMessage='A newer version of [ProductName] is already installed. Setup will now exit.' /> + + <Media Id='1' Cabinet='media1.cab' EmbedCab='yes' DiskPrompt='CD-ROM #1' /> + <Property Id='DiskPrompt' Value='rust-template Installation' /> + + <Directory Id='TARGETDIR' Name='SourceDir'> + <Directory Id='$(var.PlatformProgramFilesFolder)' Name='PFiles'> + <Directory Id='APPLICATIONFOLDER' Name='rust-template'> + + <!-- + Enabling the license sidecar file in the installer is a four step process: + + 1. Uncomment the `Component` tag and its contents. + 2. Change the value for the `Source` attribute in the `File` tag to a path + to the file that should be included as the license sidecar file. The path + can, and probably should be, relative to this file. + 3. Change the value for the `Name` attribute in the `File` tag to the + desired name for the file when it is installed alongside the `bin` folder + in the installation directory. This can be omitted if the desired name is + the same as the file name. + 4. Uncomment the `ComponentRef` tag with the Id attribute value of "License" + further down in this file. + --> + <Component Id='License' Guid='*'> + <File Id='LicenseFile' Name='LICENSE' DiskId='1' Source='LICENSE' KeyPath='yes' /> + </Component> + + <Directory Id='Bin' Name='bin'> + <Component Id='Path' Guid='964FD77A-B1CF-4FC4-8F71-8015A879CB9C' KeyPath='yes'> + <Environment Id='PATH' Name='PATH' Value='[Bin]' Permanent='no' Part='last' Action='set' System='yes' /> + </Component> + <Component Id='binary0' Guid='*'> + <File Id='exe0' Name='rust-template.exe' DiskId='1' Source='$(var.CargoTargetBinDir)\rust-template.exe' KeyPath='yes' /> + </Component> + </Directory> + </Directory> + </Directory> + </Directory> + + <Feature Id='Binaries' Title='Application' Description='Installs all binaries and the license.' Level='1' ConfigurableDirectory='APPLICATIONFOLDER' AllowAdvertise='no' Display='expand' Absent='disallow'> + + <!-- + Uncomment the following `ComponentRef` tag to add the license + sidecar file to the installer. + --> + <ComponentRef Id='License' /> + + <ComponentRef Id='binary0' /> + + <Feature Id='Environment' Title='PATH Environment Variable' Description='Add the install location of the [ProductName] executable to the PATH system environment variable. This allows the [ProductName] executable to be called from any location.' Level='1' Absent='allow'> + <ComponentRef Id='Path' /> + </Feature> + </Feature> + + <SetProperty Id='ARPINSTALLLOCATION' Value='[APPLICATIONFOLDER]' After='CostFinalize' /> + + + <!-- + The product icon is the graphic that appears in the Add/Remove + Programs control panel for the application. + --> + <Icon Id='ProductICO' SourceFile='media\icon.ico' /> + <Property Id='ARPPRODUCTICON' Value='ProductICO' /> + + <Property Id='ARPHELPLINK' Value='https://github.com/MathieuSoysal/Exercism-Rust-Template' /> + + <UI> + <UIRef Id='WixUI_FeatureTree' /> + + <!-- + Enabling the EULA dialog in the installer is a three step process: + + 1. Comment out or remove the two `Publish` tags that follow the + `WixVariable` tag. + 2. Uncomment the `<WixVariable Id='WixUILicenseRtf' Value='Path\to\Eula.rft'>` tag further down + 3. Replace the `Value` attribute of the `WixVariable` tag with + the path to a RTF file that will be used as the EULA and + displayed in the license agreement dialog. + --> + <Publish Dialog='WelcomeDlg' Control='Next' Event='NewDialog' Value='CustomizeDlg' Order='99'>1</Publish> + <Publish Dialog='CustomizeDlg' Control='Back' Event='NewDialog' Value='WelcomeDlg' Order='99'>1</Publish> + + </UI> + + + <!-- + Enabling the EULA dialog in the installer requires uncommenting + the following `WixUILicenseRTF` tag and changing the `Value` + attribute. + --> + <WixVariable Id='WixUILicenseRtf' Value='install\windows\pkg_resources\license.rtf' /> + + + <!-- + Uncomment the next `WixVariable` tag to customize the installer's + Graphical User Interface (GUI) and add a custom banner image across + the top of each screen. See the WiX Toolset documentation for details + about customization. + + The banner BMP dimensions are 493 x 58 pixels. + --> + <WixVariable Id='WixUIBannerBmp' Value='install\windows\pkg_resources\Banner.bmp' /> + + + <!-- + Uncomment the next `WixVariable` tag to customize the installer's + Graphical User Interface (GUI) and add a custom image to the first + dialog, or screen. See the WiX Toolset documentation for details about + customization. + + The dialog BMP dimensions are 493 x 312 pixels. + --> + <WixVariable Id='WixUIDialogBmp' Value='install\windows\pkg_resources\Dialog.bmp' /> + + </Product> + +</Wix> \ No newline at end of file diff --git a/install/windows/pkg_resources/Banner.bmp b/install/windows/pkg_resources/Banner.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d087b1b2e56277208c00f1ba56af09ad5e9ff495 GIT binary patch literal 119819 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 literal 0 HcmV?d00001 diff --git a/install/windows/pkg_resources/Dialog.bmp b/install/windows/pkg_resources/Dialog.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d087b1b2e56277208c00f1ba56af09ad5e9ff495 GIT binary patch literal 119819 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 literal 0 HcmV?d00001 diff --git a/install/windows/pkg_resources/LICENSE.rtf b/install/windows/pkg_resources/LICENSE.rtf new file mode 100644 index 0000000..4a75616 --- /dev/null +++ b/install/windows/pkg_resources/LICENSE.rtf @@ -0,0 +1,4 @@ +{\pard \ql \f0 \sa180 \li0 \fi0 ISC License\par} +{\pard \ql \f0 \sa180 \li0 \fi0 Copyright (c) 2019-2022, Rust template Contributors\par} +{\pard \ql \f0 \sa180 \li0 \fi0 Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.\par} +{\pard \ql \f0 \sa180 \li0 \fi0 THE SOFTWARE IS PROVIDED \u8220"AS IS\u8221" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\par} \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d823bd7 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,88 @@ +#![feature(test)] +extern crate test; + +const MAX_FIBONACCI: u32 = 2_971_215_073; + +pub fn play_game(n: u32) { + println!("{}", fizz_buzz_fibonacci(n)); +} + +fn is_fibonacci_number(n: u32) -> bool { + let (mut previous, mut current) = (0, 1); + while current < n && n <= MAX_FIBONACCI { + let next = previous + current; + previous = current; + current = next; + } + current == n +} + +pub fn fizz_buzz_fibonacci(n: u32) -> String { + if is_fibonacci_number(n) { + "Fibonacci".to_string() + } else { + match (n % 3, n % 5) { + (0, 0) => "FizzBuzz".to_string(), + (0, _) => "Fizz".to_string(), + (_, 0) => "Buzz".to_string(), + (_, _) => n.to_string(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_is_fibonacci_number() { + assert!(is_fibonacci_number(2_971_215_073)); + assert_eq!(is_fibonacci_number(u32::MAX), false); + } + + #[test] + fn test_fizz_buzz_fibonacci() { + assert_eq!(fizz_buzz_fibonacci(1), "Fibonacci"); + assert_eq!(fizz_buzz_fibonacci(2), "Fibonacci"); + assert_eq!(fizz_buzz_fibonacci(3), "Fibonacci"); + assert_eq!(fizz_buzz_fibonacci(4), "4"); + assert_eq!(fizz_buzz_fibonacci(5), "Fibonacci"); + assert_eq!(fizz_buzz_fibonacci(6), "Fizz"); + assert_eq!(fizz_buzz_fibonacci(7), "7"); + assert_eq!(fizz_buzz_fibonacci(8), "Fibonacci"); + assert_eq!(fizz_buzz_fibonacci(9), "Fizz"); + assert_eq!(fizz_buzz_fibonacci(10), "Buzz"); + assert_eq!(fizz_buzz_fibonacci(15), "FizzBuzz"); + } +} + +#[cfg(test)] +mod benchmarks { + use super::*; + use std::hint::black_box; + use test::Bencher; + + #[bench] + fn bench_play_game(b: &mut Bencher) { + b.iter(|| { + black_box(for i in 1..=100 { + play_game(i) + }); + }); + } + + #[bench] + fn bench_play_game_100(b: &mut Bencher) { + b.iter(|| std::hint::black_box(play_game(100))); + } + + #[bench] + fn bench_play_game_1_000_000(b: &mut Bencher) { + b.iter(|| std::hint::black_box(play_game(1_000_000))); + } + + #[bench] + fn bench_play_game_2_971_215_073(b: &mut Bencher) { + b.iter(|| std::hint::black_box(play_game(2_971_215_073))); + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..9804836 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,14 @@ +#![feature(test)] +extern crate test; + +use template_exercisme::play_game; + +fn main() { + let args: Vec<String> = std::env::args().collect(); + let i = args + .get(1) + .expect("Give one argument") + .parse::<u32>() + .expect("Given argument should be a integer."); + play_game(i); +}