diff --git a/.github/workflows/actions/rust-toolchain/action.yml b/.github/workflows/actions/rust-toolchain/action.yml new file mode 100644 index 0000000..4547904 --- /dev/null +++ b/.github/workflows/actions/rust-toolchain/action.yml @@ -0,0 +1,25 @@ +name: rust-toolchain +inputs: + toolchain: + description: "Which rust toolchain to use" + required: false + +runs: + using: "composite" + steps: + - id: get-toolchain + shell: bash + run: | + USER_OVERRIDE=${{ inputs.toolchain }} + DEFAULT_TOOLCHAIN=$(grep channel rust-toolchain.toml | awk '{print $3}' | sed 's/"//g') + TOOLCHAIN=${USER_OVERRIDE:-$DEFAULT_TOOLCHAIN} + echo "toolchain=$TOOLCHAIN" >> $GITHUB_OUTPUT + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ steps.get-toolchain.outputs.toolchain }} + override: true + - uses: Swatinem/rust-cache@v2.0.0 + with: + shared-key: ${{ steps.get-toolchain.outputs.toolchain }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f139730 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,77 @@ +name: ci-rust-push + +on: + push: + branches: + - 'main' + - 'master' + +jobs: + skip-duplicates: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + concurrent_skipping: "same_content_newer" + + check: + needs: skip-duplicates + if: needs.skip-duplicates.outputs.should_skip != 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - uses: ./.github/workflows/actions/rust-toolchain + - run: cargo check --all-features + + test: + needs: skip-duplicates + if: needs.skip-duplicates.outputs.should_skip != 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - uses: ./.github/workflows/actions/rust-toolchain + - run: cargo test --all-features + + fmt: + needs: skip-duplicates + if: needs.skip-duplicates.outputs.should_skip != 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - uses: ./.github/workflows/actions/rust-toolchain + with: + toolchain: nightly + - run: rustup component add rustfmt + - run: cargo fmt --all --check + + clippy: + needs: skip-duplicates + if: needs.skip-duplicates.outputs.should_skip != 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - uses: ./.github/workflows/actions/rust-toolchain + - run: rustup component add clippy + - run: cargo clippy --all-features -- --deny warnings + + doc: + needs: skip-duplicates + if: needs.skip-duplicates.outputs.should_skip != 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - uses: ./.github/workflows/actions/rust-toolchain + - run: cargo doc --all-features --no-deps diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..791af9f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/logs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..ae15f94 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,65 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "const-decimal" +version = "0.1.0" +dependencies = [ + "serde", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..9fdd59a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "const-decimal" +version = "0.1.0" +authors = ["Oliver Chalk"] +edition = "2021" +readme = "README.md" + +[lints.clippy] +cast_possible_truncation = 'warn' +cast_possible_wrap = 'warn' +cast_sign_loss = 'warn' +# See `clippy.toml`. +disallowed_methods = 'warn' + +[features] +serde = ["dep:serde"] + +[dependencies] +serde = { version = "1.0.210", features = ["derive"], optional = true } + +[build-dependencies] + +[profile.release] +opt-level = 3 +debug = true + +[profile.paranoid] +inherits = "release" +overflow-checks = true +debug-assertions = true + +[profile.performance] +inherits = "release" +lto = "fat" +codegen-units = 1 +incremental = false diff --git a/README.md b/README.md new file mode 100644 index 0000000..5b1c380 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Const Point + +Fixed precision maths type implemented using compile time constants. diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..baf057c --- /dev/null +++ b/clippy.toml @@ -0,0 +1,13 @@ +[[disallowed-methods]] +path = "core::cmp::Ord::min" +reason = ''' +Too easy to misread `x.min(y)` as "let the minimum value of `x` be `y`" when it actually means the exact opposite; +Use `std::cmp::min` instead. +''' + +[[disallowed-methods]] +path = "core::cmp::Ord::max" +reason = ''' +Too easy to misread `x.max(y)` as "let the maximum value of `x` be `y`" when it actually means the exact opposite; +Use `std::cmp::max` instead. +''' diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..624eb0e --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.76.0" diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..b14388b --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,10 @@ +edition = "2021" +error_on_line_overflow = true +wrap_comments = true +use_field_init_shorthand = true +imports_granularity = "Module" +condense_wildcard_suffixes = true +format_strings = true +group_imports = "StdExternalCrate" +use_small_heuristics = "Max" +chain_width = 60 diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ae9cd0d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,72 @@ +use std::ops::{Add, Div, Mul, Sub}; + +pub const PRECISION_FACTOR: u64 = 10u64.pow(9); + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Decimal64(pub u64); + +impl Decimal64 { + pub const ONE: Decimal64 = Decimal64(PRECISION_FACTOR); +} + +impl Add for Decimal64 { + type Output = Self; + + #[inline] + fn add(self, rhs: Self) -> Self::Output { + Decimal64(self.0 + rhs.0) + } +} + +impl Sub for Decimal64 { + type Output = Self; + + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + Decimal64(self.0 - rhs.0) + } +} + +impl Mul for Decimal64 { + type Output = Self; + + #[inline] + fn mul(self, rhs: Self) -> Self::Output { + Decimal64(self.0 * rhs.0 / PRECISION_FACTOR) + } +} + +impl Div for Decimal64 { + type Output = Self; + + #[inline] + fn div(self, rhs: Self) -> Self::Output { + Decimal64(self.0 * PRECISION_FACTOR / rhs.0) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn add() { + assert_eq!(Decimal64::ONE + Decimal64::ONE, Decimal64(PRECISION_FACTOR * 2)); + } + + #[test] + fn sub() { + assert_eq!(Decimal64::ONE - Decimal64::ONE, Decimal64(0)); + } + + #[test] + fn mul() { + assert_eq!(Decimal64::ONE * Decimal64::ONE, Decimal64::ONE); + } + + #[test] + fn div() { + assert_eq!(Decimal64::ONE / Decimal64::ONE, Decimal64::ONE); + } +} diff --git a/taplo.toml b/taplo.toml new file mode 100644 index 0000000..73ee440 --- /dev/null +++ b/taplo.toml @@ -0,0 +1,10 @@ +[formatting] +column_width = 120 +array_auto_expand = true +allowed_blank_lines = 1 + +[[rule]] +keys = ["dependencies", "dev-dependencies", "build-dependencies", "toolchain", "workspace.dependencies"] + +[rule.formatting] +reorder_keys = true