diff --git a/rust/README.md b/rust/README.md index de2984c0..550d820a 100644 --- a/rust/README.md +++ b/rust/README.md @@ -41,3 +41,4 @@ - [scrabble-score](./scrabble-score/README.md) - [luhn-from](./luhn-from/README.md) - [collatz-conjecture](./collatz-conjecture/README.md) +- [luhn-trait](./luhn-trait/README.md) diff --git a/rust/luhn-trait/.exercism/config.json b/rust/luhn-trait/.exercism/config.json new file mode 100644 index 00000000..a8b53df2 --- /dev/null +++ b/rust/luhn-trait/.exercism/config.json @@ -0,0 +1,39 @@ +{ + "authors": [ + "IanWhitney" + ], + "contributors": [ + "AndrewKvalheim", + "coriolinus", + "cwhakes", + "efx", + "ErikSchierboom", + "IanWhitney", + "Insti", + "lutostag", + "mkantor", + "nfiles", + "petertseng", + "rofrol", + "stringparser", + "xakon", + "ZapAnton" + ], + "files": { + "solution": [ + "src/lib.rs", + "Cargo.toml" + ], + "test": [ + "tests/luhn-trait.rs" + ], + "example": [ + ".meta/example.rs" + ] + }, + "blurb": "Luhn: Using a Custom Trait", + "source": "The Rust track maintainers, based on the original Luhn exercise", + "custom": { + "allowed-to-not-compile": "Stub doesn't compile because the custom trait is not implemented for every type in the test suite. This exercise is an introduction to implementing custom traits for the primitives and fully implementing the trait for the test suite reduces learning." + } +} diff --git a/rust/luhn-trait/.exercism/metadata.json b/rust/luhn-trait/.exercism/metadata.json new file mode 100644 index 00000000..c00d63e5 --- /dev/null +++ b/rust/luhn-trait/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"rust","exercise":"luhn-trait","id":"4cd119f389124ffdbf323c376560c63e","url":"https://exercism.org/tracks/rust/exercises/luhn-trait","handle":"vpayno","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/rust/luhn-trait/.gitignore b/rust/luhn-trait/.gitignore new file mode 100644 index 00000000..db7f315c --- /dev/null +++ b/rust/luhn-trait/.gitignore @@ -0,0 +1,8 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +**/*.rs.bk + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/luhn-trait/Cargo.toml b/rust/luhn-trait/Cargo.toml new file mode 100644 index 00000000..75fa75d9 --- /dev/null +++ b/rust/luhn-trait/Cargo.toml @@ -0,0 +1,4 @@ +[package] +edition = "2021" +name = "luhn-trait" +version = "0.0.0" diff --git a/rust/luhn-trait/HELP.md b/rust/luhn-trait/HELP.md new file mode 100644 index 00000000..67add768 --- /dev/null +++ b/rust/luhn-trait/HELP.md @@ -0,0 +1,86 @@ +# Help + +## Running the tests + +Execute the tests with: + +```bash +$ cargo test +``` + +All but the first test have been ignored. After you get the first test to +pass, open the tests source file which is located in the `tests` directory +and remove the `#[ignore]` flag from the next test and get the tests to pass +again. Each separate test is a function with `#[test]` flag above it. +Continue, until you pass every test. + +If you wish to run _only ignored_ tests without editing the tests source file, use: + +```bash +$ cargo test -- --ignored +``` + +If you are using Rust 1.51 or later, you can run _all_ tests with + +```bash +$ cargo test -- --include-ignored +``` + +To run a specific test, for example `some_test`, you can use: + +```bash +$ cargo test some_test +``` + +If the specific test is ignored, use: + +```bash +$ cargo test some_test -- --ignored +``` + +To learn more about Rust tests refer to the online [test documentation][rust-tests]. + +[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html + +## Submitting your solution + +You can submit your solution using the `exercism submit src/lib.rs Cargo.toml` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Rust track's documentation](https://exercism.org/docs/tracks/rust) +- The [Rust track's programming category on the forum](https://forum.exercism.org/c/programming/rust) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +## Rust Installation + +Refer to the [exercism help page][help-page] for Rust installation and learning +resources. + +## Submitting the solution + +Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer. + +## Feedback, Issues, Pull Requests + +The GitHub [track repository][github] is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help! + +If you want to know more about Exercism, take a look at the [contribution guide]. + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + +[help-page]: https://exercism.org/tracks/rust/learning +[github]: https://github.com/exercism/rust +[contribution guide]: https://exercism.org/docs/community/contributors \ No newline at end of file diff --git a/rust/luhn-trait/README.md b/rust/luhn-trait/README.md new file mode 100644 index 00000000..17b1072a --- /dev/null +++ b/rust/luhn-trait/README.md @@ -0,0 +1,61 @@ +# Luhn Trait + +Welcome to Luhn Trait on Exercism's Rust Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Instructions + +Before doing this exercise you should probably do the original Luhn exercise and its successor, "Luhn: Using the From Trait" + +To get the original Luhn exercise, run + +```shell +exercism download --exercise=luhn --track=rust +``` + +To get the "Luhn: Using the From Trait" exercise, run + +```shell +exercism download --exercise=luhn-from --track=rust +``` + +In the original Luhn exercise you only validated strings, but the Luhn algorithm can be applied to integers as well. + +In "Luhn: Using the From Trait" you implemented a From trait, which also required you to create a Luhn struct. + +Instead of creating a Struct just to perform the validation, what if you validated the primitives (i.e, String, u8, etc.) themselves? + +In this exercise you'll create and implement a custom [trait](https://doc.rust-lang.org/book/2018-edition/ch10-02-traits.html) that performs the validation. + +## Source + +### Created by + +- @IanWhitney + +### Contributed to by + +- @AndrewKvalheim +- @coriolinus +- @cwhakes +- @efx +- @ErikSchierboom +- @IanWhitney +- @Insti +- @lutostag +- @mkantor +- @nfiles +- @petertseng +- @rofrol +- @stringparser +- @xakon +- @ZapAnton + +### Based on + +The Rust track maintainers, based on the original Luhn exercise + +### My Solution + +- [my solution](./src/lib.rs) +- [run-tests](./run-tests-rust.txt) diff --git a/rust/luhn-trait/coverage-annotations.txt b/rust/luhn-trait/coverage-annotations.txt new file mode 100644 index 00000000..f09def0e --- /dev/null +++ b/rust/luhn-trait/coverage-annotations.txt @@ -0,0 +1,256 @@ + 1| |pub trait Luhn { + 2| | fn valid_luhn(&self) -> bool; + 3| |} + 4| | + 5| |impl<'a> Luhn for &'a str { + 6| 45| fn valid_luhn(&self) -> bool { + 7| 45| match self { + 8| 45| code if *code == "0" => false, + ^0 ^0 + 9| 45| code if code.is_empty() => false, + ^0 ^0 + 10| 45| code if !code.is_ascii() => false, + ^0 ^0 + 11| 45| code if !is_only_numbers_and_spaces(code) => false, + ^0 ^0 + 12| 45| _ => is_luhn_number(self), + 13| | } + 14| 45| } + ------------------ + | Unexecuted instantiation: <&str as luhn_trait::Luhn>::valid_luhn + ------------------ + | <&str as luhn_trait::Luhn>::valid_luhn: + | 6| 45| fn valid_luhn(&self) -> bool { + | 7| 45| match self { + | 8| 45| code if *code == "0" => false, + | ^0 ^0 + | 9| 45| code if code.is_empty() => false, + | ^0 ^0 + | 10| 45| code if !code.is_ascii() => false, + | ^0 ^0 + | 11| 45| code if !is_only_numbers_and_spaces(code) => false, + | ^0 ^0 + | 12| 45| _ => is_luhn_number(self), + | 13| | } + | 14| 45| } + ------------------ + 15| |} + 16| | + 17| |impl Luhn for String { + 18| 36| fn valid_luhn(&self) -> bool { + 19| 36| self.as_str().valid_luhn() + 20| 36| } + ------------------ + | Unexecuted instantiation: ::valid_luhn + ------------------ + | ::valid_luhn: + | 18| 36| fn valid_luhn(&self) -> bool { + | 19| 36| self.as_str().valid_luhn() + | 20| 36| } + ------------------ + 21| |} + 22| |impl Luhn for u8 { + 23| 6| fn valid_luhn(&self) -> bool { + 24| 6| self.to_string().valid_luhn() + 25| 6| } + ------------------ + | Unexecuted instantiation: ::valid_luhn + ------------------ + | ::valid_luhn: + | 23| 6| fn valid_luhn(&self) -> bool { + | 24| 6| self.to_string().valid_luhn() + | 25| 6| } + ------------------ + 26| |} + 27| |impl Luhn for u16 { + 28| 6| fn valid_luhn(&self) -> bool { + 29| 6| self.to_string().valid_luhn() + 30| 6| } + ------------------ + | Unexecuted instantiation: ::valid_luhn + ------------------ + | ::valid_luhn: + | 28| 6| fn valid_luhn(&self) -> bool { + | 29| 6| self.to_string().valid_luhn() + | 30| 6| } + ------------------ + 31| |} + 32| |impl Luhn for u32 { + 33| 6| fn valid_luhn(&self) -> bool { + 34| 6| self.to_string().valid_luhn() + 35| 6| } + ------------------ + | Unexecuted instantiation: ::valid_luhn + ------------------ + | ::valid_luhn: + | 33| 6| fn valid_luhn(&self) -> bool { + | 34| 6| self.to_string().valid_luhn() + | 35| 6| } + ------------------ + 36| |} + 37| |impl Luhn for u64 { + 38| 6| fn valid_luhn(&self) -> bool { + 39| 6| self.to_string().valid_luhn() + 40| 6| } + ------------------ + | Unexecuted instantiation: ::valid_luhn + ------------------ + | ::valid_luhn: + | 38| 6| fn valid_luhn(&self) -> bool { + | 39| 6| self.to_string().valid_luhn() + | 40| 6| } + ------------------ + 41| |} + 42| |impl Luhn for usize { + 43| 6| fn valid_luhn(&self) -> bool { + 44| 6| self.to_string().valid_luhn() + 45| 6| } + ------------------ + | Unexecuted instantiation: ::valid_luhn + ------------------ + | ::valid_luhn: + | 43| 6| fn valid_luhn(&self) -> bool { + | 44| 6| self.to_string().valid_luhn() + | 45| 6| } + ------------------ + 46| |} + 47| | + 48| 45|pub fn is_luhn_number(code: &str) -> bool { + 49| 45| let digits: Vec = extract_digits_from_str_slice(code); + 50| 45| + 51| 45| let numbers = step_one_and_two(digits); + 52| 45| + 53| 45| let digit_sum: u32 = sum(numbers); + 54| 45| + 55| 45| (digit_sum % 10) == 0 + 56| 45|} + ------------------ + | Unexecuted instantiation: luhn_trait::is_luhn_number + ------------------ + | luhn_trait::is_luhn_number: + | 48| 45|pub fn is_luhn_number(code: &str) -> bool { + | 49| 45| let digits: Vec = extract_digits_from_str_slice(code); + | 50| 45| + | 51| 45| let numbers = step_one_and_two(digits); + | 52| 45| + | 53| 45| let digit_sum: u32 = sum(numbers); + | 54| 45| + | 55| 45| (digit_sum % 10) == 0 + | 56| 45|} + ------------------ + 57| | + 58| 45|pub fn step_one_and_two(mut vector: Vec) -> Vec { + 59| 45| let mut i = 1; + 60| | + 61| 189| while i < vector.len() { + 62| 189| vector[i] *= 2; + 63| 189| + 64| 189| if vector[i] > 9 { + 65| 81| vector[i] -= 9; + 66| 108| } + 67| | + 68| 189| i += 2; + 69| 189| + 70| 189| if i >= vector.len() { + 71| 45| break; + 72| 144| } + 73| | } + 74| | + 75| 45| vector + 76| 45|} + ------------------ + | Unexecuted instantiation: luhn_trait::step_one_and_two + ------------------ + | luhn_trait::step_one_and_two: + | 58| 45|pub fn step_one_and_two(mut vector: Vec) -> Vec { + | 59| 45| let mut i = 1; + | 60| | + | 61| 189| while i < vector.len() { + | 62| 189| vector[i] *= 2; + | 63| 189| + | 64| 189| if vector[i] > 9 { + | 65| 81| vector[i] -= 9; + | 66| 108| } + | 67| | + | 68| 189| i += 2; + | 69| 189| + | 70| 189| if i >= vector.len() { + | 71| 45| break; + | 72| 144| } + | 73| | } + | 74| | + | 75| 45| vector + | 76| 45|} + ------------------ + 77| | + 78| 45|pub fn sum(vector: Vec) -> u32 { + 79| 45| vector.iter().sum() + 80| 45|} + ------------------ + | Unexecuted instantiation: luhn_trait::sum + ------------------ + | luhn_trait::sum: + | 78| 45|pub fn sum(vector: Vec) -> u32 { + | 79| 45| vector.iter().sum() + | 80| 45|} + ------------------ + 81| | + 82| 45|pub fn extract_digits_from_str_slice(code: &str) -> Vec { + 83| 45| code.chars() + 84| 429| .filter(|x| x.is_ascii_digit()) + ------------------ + | Unexecuted instantiation: luhn_trait::extract_digits_from_str_slice::{closure#0} + ------------------ + | luhn_trait::extract_digits_from_str_slice::{closure#0}: + | 84| 429| .filter(|x| x.is_ascii_digit()) + ------------------ + 85| 405| .map(|x| x.to_digit(10).unwrap()) + ------------------ + | Unexecuted instantiation: luhn_trait::extract_digits_from_str_slice::{closure#1} + ------------------ + | luhn_trait::extract_digits_from_str_slice::{closure#1}: + | 85| 405| .map(|x| x.to_digit(10).unwrap()) + ------------------ + 86| 45| .rev() + 87| 45| .collect() + 88| 45|} + ------------------ + | Unexecuted instantiation: luhn_trait::extract_digits_from_str_slice + ------------------ + | luhn_trait::extract_digits_from_str_slice: + | 82| 45|pub fn extract_digits_from_str_slice(code: &str) -> Vec { + | 83| 45| code.chars() + | 84| 45| .filter(|x| x.is_ascii_digit()) + | 85| 45| .map(|x| x.to_digit(10).unwrap()) + | 86| 45| .rev() + | 87| 45| .collect() + | 88| 45|} + ------------------ + 89| | + 90| 45|pub fn is_only_numbers_and_spaces(code: &str) -> bool { + 91| 429| for c in code.chars() { + ^45 + 92| 429| if !c.is_ascii_digit() && !c.is_whitespace() { + ^24 + 93| 0| return false; + 94| 429| }; + 95| | } + 96| | + 97| 45| true + 98| 45|} + ------------------ + | Unexecuted instantiation: luhn_trait::is_only_numbers_and_spaces + ------------------ + | luhn_trait::is_only_numbers_and_spaces: + | 90| 45|pub fn is_only_numbers_and_spaces(code: &str) -> bool { + | 91| 429| for c in code.chars() { + | ^45 + | 92| 429| if !c.is_ascii_digit() && !c.is_whitespace() { + | ^24 + | 93| 0| return false; + | 94| 429| }; + | 95| | } + | 96| | + | 97| 45| true + | 98| 45|} + ------------------ \ No newline at end of file diff --git a/rust/luhn-trait/coverage-missing-lines.txt b/rust/luhn-trait/coverage-missing-lines.txt new file mode 100644 index 00000000..1283c62a --- /dev/null +++ b/rust/luhn-trait/coverage-missing-lines.txt @@ -0,0 +1,10 @@ +Running: cargo llvm-cov --no-clean --all-features --workspace --show-missing-lines + +Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait/src/lib.rs 46 9 80.43% 14 0 100.00% 69 1 98.55% 0 0 - +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +TOTAL 46 9 80.43% 14 0 100.00% 69 1 98.55% 0 0 - +Uncovered Lines: +/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait/src/lib.rs: 93 + diff --git a/rust/luhn-trait/report.lcov b/rust/luhn-trait/report.lcov new file mode 100644 index 00000000..ef3209c6 --- /dev/null +++ b/rust/luhn-trait/report.lcov @@ -0,0 +1,131 @@ +SF:/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait/src/lib.rs +FN:23,_RNvXs0_Cs5qdxllgkmwL_10luhn_traithNtB5_4Luhn10valid_luhn +FN:38,_RNvXs3_Cs5qdxllgkmwL_10luhn_traityNtB5_4Luhn10valid_luhn +FN:78,_RNvCs5qdxllgkmwL_10luhn_trait3sum +FN:82,_RNvCs5qdxllgkmwL_10luhn_trait29extract_digits_from_str_slice +FN:28,_RNvXs1_Cs5qdxllgkmwL_10luhn_traittNtB5_4Luhn10valid_luhn +FN:43,_RNvXs4_Cs5qdxllgkmwL_10luhn_traitjNtB5_4Luhn10valid_luhn +FN:84,_RNCNvCs5qdxllgkmwL_10luhn_trait29extract_digits_from_str_slice0B3_ +FN:18,_RNvXs_Cs5qdxllgkmwL_10luhn_traitNtNtCseUNaFxoWMgP_5alloc6string6StringNtB4_4Luhn10valid_luhn +FN:33,_RNvXs2_Cs5qdxllgkmwL_10luhn_traitmNtB5_4Luhn10valid_luhn +FN:48,_RNvCs5qdxllgkmwL_10luhn_trait14is_luhn_number +FN:58,_RNvCs5qdxllgkmwL_10luhn_trait16step_one_and_two +FN:6,_RNvXCs5qdxllgkmwL_10luhn_traitReNtB2_4Luhn10valid_luhn +FN:85,_RNCNvCs5qdxllgkmwL_10luhn_trait29extract_digits_from_str_slices_0B3_ +FN:90,_RNvCs5qdxllgkmwL_10luhn_trait26is_only_numbers_and_spaces +FN:23,_RNvXs0_Cs9UQeYrlCNkx_10luhn_traithNtB5_4Luhn10valid_luhn +FN:38,_RNvXs3_Cs9UQeYrlCNkx_10luhn_traityNtB5_4Luhn10valid_luhn +FN:78,_RNvCs9UQeYrlCNkx_10luhn_trait3sum +FN:82,_RNvCs9UQeYrlCNkx_10luhn_trait29extract_digits_from_str_slice +FN:28,_RNvXs1_Cs9UQeYrlCNkx_10luhn_traittNtB5_4Luhn10valid_luhn +FN:43,_RNvXs4_Cs9UQeYrlCNkx_10luhn_traitjNtB5_4Luhn10valid_luhn +FN:84,_RNCNvCs9UQeYrlCNkx_10luhn_trait29extract_digits_from_str_slice0B3_ +FN:18,_RNvXs_Cs9UQeYrlCNkx_10luhn_traitNtNtCseUNaFxoWMgP_5alloc6string6StringNtB4_4Luhn10valid_luhn +FN:33,_RNvXs2_Cs9UQeYrlCNkx_10luhn_traitmNtB5_4Luhn10valid_luhn +FN:48,_RNvCs9UQeYrlCNkx_10luhn_trait14is_luhn_number +FN:58,_RNvCs9UQeYrlCNkx_10luhn_trait16step_one_and_two +FN:6,_RNvXCs9UQeYrlCNkx_10luhn_traitReNtB2_4Luhn10valid_luhn +FN:90,_RNvCs9UQeYrlCNkx_10luhn_trait26is_only_numbers_and_spaces +FN:85,_RNCNvCs9UQeYrlCNkx_10luhn_trait29extract_digits_from_str_slices_0B3_ +FNDA:0,_RNvXs0_Cs5qdxllgkmwL_10luhn_traithNtB5_4Luhn10valid_luhn +FNDA:0,_RNvXs3_Cs5qdxllgkmwL_10luhn_traityNtB5_4Luhn10valid_luhn +FNDA:0,_RNvCs5qdxllgkmwL_10luhn_trait3sum +FNDA:0,_RNvCs5qdxllgkmwL_10luhn_trait29extract_digits_from_str_slice +FNDA:0,_RNvXs1_Cs5qdxllgkmwL_10luhn_traittNtB5_4Luhn10valid_luhn +FNDA:0,_RNvXs4_Cs5qdxllgkmwL_10luhn_traitjNtB5_4Luhn10valid_luhn +FNDA:0,_RNCNvCs5qdxllgkmwL_10luhn_trait29extract_digits_from_str_slice0B3_ +FNDA:0,_RNvXs_Cs5qdxllgkmwL_10luhn_traitNtNtCseUNaFxoWMgP_5alloc6string6StringNtB4_4Luhn10valid_luhn +FNDA:0,_RNvXs2_Cs5qdxllgkmwL_10luhn_traitmNtB5_4Luhn10valid_luhn +FNDA:0,_RNvCs5qdxllgkmwL_10luhn_trait14is_luhn_number +FNDA:0,_RNvCs5qdxllgkmwL_10luhn_trait16step_one_and_two +FNDA:0,_RNvXCs5qdxllgkmwL_10luhn_traitReNtB2_4Luhn10valid_luhn +FNDA:0,_RNCNvCs5qdxllgkmwL_10luhn_trait29extract_digits_from_str_slices_0B3_ +FNDA:0,_RNvCs5qdxllgkmwL_10luhn_trait26is_only_numbers_and_spaces +FNDA:2,_RNvXs0_Cs9UQeYrlCNkx_10luhn_traithNtB5_4Luhn10valid_luhn +FNDA:2,_RNvXs3_Cs9UQeYrlCNkx_10luhn_traityNtB5_4Luhn10valid_luhn +FNDA:15,_RNvCs9UQeYrlCNkx_10luhn_trait3sum +FNDA:15,_RNvCs9UQeYrlCNkx_10luhn_trait29extract_digits_from_str_slice +FNDA:2,_RNvXs1_Cs9UQeYrlCNkx_10luhn_traittNtB5_4Luhn10valid_luhn +FNDA:2,_RNvXs4_Cs9UQeYrlCNkx_10luhn_traitjNtB5_4Luhn10valid_luhn +FNDA:143,_RNCNvCs9UQeYrlCNkx_10luhn_trait29extract_digits_from_str_slice0B3_ +FNDA:12,_RNvXs_Cs9UQeYrlCNkx_10luhn_traitNtNtCseUNaFxoWMgP_5alloc6string6StringNtB4_4Luhn10valid_luhn +FNDA:2,_RNvXs2_Cs9UQeYrlCNkx_10luhn_traitmNtB5_4Luhn10valid_luhn +FNDA:15,_RNvCs9UQeYrlCNkx_10luhn_trait14is_luhn_number +FNDA:15,_RNvCs9UQeYrlCNkx_10luhn_trait16step_one_and_two +FNDA:15,_RNvXCs9UQeYrlCNkx_10luhn_traitReNtB2_4Luhn10valid_luhn +FNDA:15,_RNvCs9UQeYrlCNkx_10luhn_trait26is_only_numbers_and_spaces +FNDA:135,_RNCNvCs9UQeYrlCNkx_10luhn_trait29extract_digits_from_str_slices_0B3_ +FNF:14 +FNH:14 +DA:6,15 +DA:7,15 +DA:8,15 +DA:9,15 +DA:10,15 +DA:11,15 +DA:12,15 +DA:14,15 +DA:18,12 +DA:19,12 +DA:20,12 +DA:23,2 +DA:24,2 +DA:25,2 +DA:28,2 +DA:29,2 +DA:30,2 +DA:33,2 +DA:34,2 +DA:35,2 +DA:38,2 +DA:39,2 +DA:40,2 +DA:43,2 +DA:44,2 +DA:45,2 +DA:48,15 +DA:49,15 +DA:50,15 +DA:51,15 +DA:52,15 +DA:53,15 +DA:54,15 +DA:55,15 +DA:56,15 +DA:58,15 +DA:59,15 +DA:61,63 +DA:62,63 +DA:63,63 +DA:64,63 +DA:65,27 +DA:66,36 +DA:68,63 +DA:69,63 +DA:70,63 +DA:71,15 +DA:72,48 +DA:75,15 +DA:76,15 +DA:78,15 +DA:79,15 +DA:80,15 +DA:82,15 +DA:83,15 +DA:84,143 +DA:85,135 +DA:86,15 +DA:87,15 +DA:88,15 +DA:90,15 +DA:91,143 +DA:92,143 +DA:93,0 +DA:94,143 +DA:97,15 +DA:98,15 +BRF:0 +BRH:0 +LF:69 +LH:68 +end_of_record \ No newline at end of file diff --git a/rust/luhn-trait/run-tests-rust.txt b/rust/luhn-trait/run-tests-rust.txt new file mode 100644 index 00000000..5653f1f5 --- /dev/null +++ b/rust/luhn-trait/run-tests-rust.txt @@ -0,0 +1,464 @@ +Running automated test file(s): + + +=============================================================================== + +Running: ../../.github/citools/rust/rust-lint-check --release + +Running Rust Cargo Check + +Rust version: + + rustc 1.72.0 (5680fa18f 2023-08-23) + + + ============================================================================== + +Running: cargo clean + + +real 0m0.014s +user 0m0.005s +sys 0m0.009s + + + ============================================================================== + +Running: cargo check --future-incompat-report --release + + Checking luhn-trait v0.0.0 (/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait) + Finished release [optimized] target(s) in 0.15s +note: 0 dependencies had future-incompatible warnings + +real 0m0.158s +user 0m0.021s +sys 0m0.040s + + + ============================================================================== + +Exit code: 0 + +real 0m0.188s +user 0m0.032s +sys 0m0.061s + +real 0m0.192s +user 0m0.034s +sys 0m0.063s + +=============================================================================== + +Running: ../../.github/citools/rust/rust-lint-clippy --release + +Running Rust Cargo Clippy + +Rust version: + + rustc 1.72.0 (5680fa18f 2023-08-23) + + + ============================================================================== + +Running: cargo clean + + +real 0m0.008s +user 0m0.006s +sys 0m0.002s + + + ============================================================================== + +Running: cargo clippy --release + + Checking luhn-trait v0.0.0 (/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait) + Finished release [optimized] target(s) in 0.08s + +real 0m0.108s +user 0m0.051s +sys 0m0.058s + + + ============================================================================== + +Exit code: 0 + +real 0m0.128s +user 0m0.061s +sys 0m0.068s + +real 0m0.130s +user 0m0.062s +sys 0m0.069s + +=============================================================================== + +Running: ../../.github/citools/rust/rust-lint-audit +No deps found, skipping cargo audit. + +real 0m0.046s +user 0m0.022s +sys 0m0.025s + +real 0m0.048s +user 0m0.023s +sys 0m0.026s + +=============================================================================== + +rm -fv ./*.profraw ./*.profdata + +=============================================================================== + +Running: ../../.github/citools/rust/rust-test-with-tarpaulin + +Running Rust Tests With Tarpaulin + +Rust version: + + rustc 1.72.0 (5680fa18f 2023-08-23) + + + ============================================================================== + +Running: cargo clean + + +real 0m0.010s +user 0m0.005s +sys 0m0.005s + + + ============================================================================== + +Running: cargo test --all-features + + Compiling luhn-trait v0.0.0 (/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait) + Finished test [unoptimized + debuginfo] target(s) in 0.38s + Running unittests src/lib.rs (target/debug/deps/luhn_trait-959ab26895591430) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/luhn-trait.rs (target/debug/deps/luhn_trait-97aaa95ce4c3f8ad) + +running 8 tests +test you_can_validate_from_a_u16 ... ok +test you_can_validate_from_a_str ... ok +test input_digit_9_is_still_correctly_converted_to_output_digit_9 ... ok +test you_can_validate_from_a_string ... ok +test you_can_validate_from_a_u32 ... ok +test you_can_validate_from_a_u64 ... ok +test you_can_validate_from_a_u8 ... ok +test you_can_validate_from_a_usize ... ok + +test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Doc-tests luhn-trait + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +real 0m0.414s +user 0m0.639s +sys 0m0.255s + + + ============================================================================== + +Running: cargo tarpaulin --release --timeout=300 + +Sep 18 21:40:02.874  INFO cargo_tarpaulin::config: Creating config +Sep 18 21:40:02.885  INFO cargo_tarpaulin: Running Tarpaulin +Sep 18 21:40:02.885  INFO cargo_tarpaulin: Building project +Sep 18 21:40:02.886  INFO cargo_tarpaulin::cargo: Cleaning project + Compiling luhn-trait v0.0.0 (/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait) + Finished release [optimized] target(s) in 0.49s +Sep 18 21:40:03.426  INFO cargo_tarpaulin::process_handling::linux: Launching test +Sep 18 21:40:03.426  INFO cargo_tarpaulin::process_handling: running /home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait/target/release/deps/luhn_trait-c359a82a0c01e758 + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +Sep 18 21:40:03.916  INFO cargo_tarpaulin::process_handling::linux: Launching test +Sep 18 21:40:03.916  INFO cargo_tarpaulin::process_handling: running /home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait/target/release/deps/luhn_trait-2bedbc1206753bfd + +running 8 tests +test you_can_validate_from_a_usize ... ok +test you_can_validate_from_a_u16 ... ok +test you_can_validate_from_a_string ... ok +test you_can_validate_from_a_str ... ok +test you_can_validate_from_a_u8 ... ok +test you_can_validate_from_a_u64 ... ok +test you_can_validate_from_a_u32 ... ok +test input_digit_9_is_still_correctly_converted_to_output_digit_9 ... ok + +test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + +Sep 18 21:40:04.411  INFO cargo_tarpaulin::report: Coverage Results: +|| Uncovered Lines: +|| src/lib.rs: 7, 9-12, 48, 58, 75, 78, 82, 90-91, 97 +|| Tested/Total Lines: +|| src/lib.rs: 18/31 +|| +58.06% coverage, 18/31 lines covered + +real 0m1.554s +user 0m0.587s +sys 0m1.050s + + + ============================================================================== + +Exit code: 0 + +real 0m1.991s +user 0m1.237s +sys 0m1.319s + +real 0m1.994s +user 0m1.238s +sys 0m1.321s + +=============================================================================== + +Running: ../../.github/citools/rust/rust-test-with-llvm-coverage + +Running Rust Tests With LLVM Coverage + +Rust version: + + rustc 1.72.0 (5680fa18f 2023-08-23) + + + ============================================================================== + +Running: cargo clean + + +real 0m0.014s +user 0m0.008s +sys 0m0.006s + + + ============================================================================== + +Running: cargo llvm-cov clean --workspace + + +real 0m0.224s +user 0m0.126s +sys 0m0.100s + + + ============================================================================== + +Running: cargo test --all-features --doc + + Compiling luhn-trait v0.0.0 (/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait) + Finished test [unoptimized + debuginfo] target(s) in 0.14s + Doc-tests luhn-trait + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +real 0m0.171s +user 0m0.234s +sys 0m0.087s + + + ============================================================================== + +Running: cargo llvm-cov --no-clean --all-features --workspace + + Compiling luhn-trait v0.0.0 (/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait) + Finished test [unoptimized + debuginfo] target(s) in 0.34s + Running unittests src/lib.rs (target/llvm-cov-target/debug/deps/luhn_trait-236d908bb0669b06) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/luhn-trait.rs (target/llvm-cov-target/debug/deps/luhn_trait-c8a99d53a893a2b6) + +running 8 tests +test input_digit_9_is_still_correctly_converted_to_output_digit_9 ... ok +test you_can_validate_from_a_str ... ok +test you_can_validate_from_a_string ... ok +test you_can_validate_from_a_u16 ... ok +test you_can_validate_from_a_u32 ... ok +test you_can_validate_from_a_u64 ... ok +test you_can_validate_from_a_u8 ... ok +test you_can_validate_from_a_usize ... ok + +test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + +Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait/src/lib.rs 46 9 80.43% 14 0 100.00% 69 1 98.55% 0 0 - +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +TOTAL 46 9 80.43% 14 0 100.00% 69 1 98.55% 0 0 - + +real 0m0.487s +user 0m0.348s +sys 0m0.198s + + + ============================================================================== + +Running: cargo llvm-cov report --lcov --output-path report.lcov + + + Finished report saved to report.lcov + +real 0m0.142s +user 0m0.071s +sys 0m0.072s + + Finished test [unoptimized + debuginfo] target(s) in 0.00s + Running unittests src/lib.rs (target/llvm-cov-target/debug/deps/luhn_trait-236d908bb0669b06) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/luhn-trait.rs (target/llvm-cov-target/debug/deps/luhn_trait-c8a99d53a893a2b6) + +running 8 tests +test input_digit_9_is_still_correctly_converted_to_output_digit_9 ... ok +test you_can_validate_from_a_str ... ok +test you_can_validate_from_a_string ... ok +test you_can_validate_from_a_u16 ... ok +test you_can_validate_from_a_u32 ... ok +test you_can_validate_from_a_u64 ... ok +test you_can_validate_from_a_u8 ... ok +test you_can_validate_from_a_usize ... ok + +test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + +real 0m0.176s +user 0m0.092s +sys 0m0.081s + + ============================================================================== + +Running: cargo llvm-cov --no-clean --all-features --workspace --text --output-path=coverage-annotations.txt + + Finished test [unoptimized + debuginfo] target(s) in 0.00s + Running unittests src/lib.rs (target/llvm-cov-target/debug/deps/luhn_trait-236d908bb0669b06) + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/luhn-trait.rs (target/llvm-cov-target/debug/deps/luhn_trait-c8a99d53a893a2b6) + +running 8 tests +test input_digit_9_is_still_correctly_converted_to_output_digit_9 ... ok +test you_can_validate_from_a_str ... ok +test you_can_validate_from_a_string ... ok +test you_can_validate_from_a_u16 ... ok +test you_can_validate_from_a_u32 ... ok +test you_can_validate_from_a_u64 ... ok +test you_can_validate_from_a_u8 ... ok +test you_can_validate_from_a_usize ... ok + +test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + + Finished report saved to coverage-annotations.txt + +real 0m0.152s +user 0m0.074s +sys 0m0.080s + + + ============================================================================== + +Running: cargo llvm-cov clean --workspace + + +real 0m0.139s +user 0m0.080s +sys 0m0.061s + + + ============================================================================== + +Running: lcov --list report.lcov + +Reading tracefile report.lcov + |Lines |Functions |Branches +Filename |Rate Num|Rate Num|Rate Num +================================================== +[/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait/src/] +lib.rs |98.5% 67|50.0% 28| - 0 +================================================== + Total:|98.5% 67|50.0% 28| - 0 + +real 0m0.036s +user 0m0.031s +sys 0m0.005s + + +Running: lcov --summary report.lcov + +Reading tracefile report.lcov +Summary coverage rate: + lines......: 98.5% (66 of 67 lines) + functions..: 50.0% (14 of 28 functions) + branches...: no data found + +real 0m0.033s +user 0m0.028s +sys 0m0.006s + + + ============================================================================== + +Exit code: 0 + +real 0m1.588s +user 0m1.098s +sys 0m0.703s + +real 0m1.590s +user 0m1.099s +sys 0m0.704s + +=============================================================================== + +Running: misspell . + +real 0m0.024s +user 0m0.034s +sys 0m0.012s + +=============================================================================== + +Running: cargo doc + Documenting luhn-trait v0.0.0 (/home/vpayno/git_vpayno/exercism-workspace/rust/luhn-trait) + Finished dev [unoptimized + debuginfo] target(s) in 0.18s + +real 0m0.191s +user 0m0.155s +sys 0m0.037s + +=============================================================================== + +Running: cargo clean + +real 0m0.011s +user 0m0.006s +sys 0m0.005s + +=============================================================================== + diff --git a/rust/luhn-trait/src/lib.rs b/rust/luhn-trait/src/lib.rs new file mode 100644 index 00000000..1f5c8c4c --- /dev/null +++ b/rust/luhn-trait/src/lib.rs @@ -0,0 +1,98 @@ +pub trait Luhn { + fn valid_luhn(&self) -> bool; +} + +impl<'a> Luhn for &'a str { + fn valid_luhn(&self) -> bool { + match self { + code if *code == "0" => false, + code if code.is_empty() => false, + code if !code.is_ascii() => false, + code if !is_only_numbers_and_spaces(code) => false, + _ => is_luhn_number(self), + } + } +} + +impl Luhn for String { + fn valid_luhn(&self) -> bool { + self.as_str().valid_luhn() + } +} +impl Luhn for u8 { + fn valid_luhn(&self) -> bool { + self.to_string().valid_luhn() + } +} +impl Luhn for u16 { + fn valid_luhn(&self) -> bool { + self.to_string().valid_luhn() + } +} +impl Luhn for u32 { + fn valid_luhn(&self) -> bool { + self.to_string().valid_luhn() + } +} +impl Luhn for u64 { + fn valid_luhn(&self) -> bool { + self.to_string().valid_luhn() + } +} +impl Luhn for usize { + fn valid_luhn(&self) -> bool { + self.to_string().valid_luhn() + } +} + +pub fn is_luhn_number(code: &str) -> bool { + let digits: Vec = extract_digits_from_str_slice(code); + + let numbers = step_one_and_two(digits); + + let digit_sum: u32 = sum(numbers); + + (digit_sum % 10) == 0 +} + +pub fn step_one_and_two(mut vector: Vec) -> Vec { + let mut i = 1; + + while i < vector.len() { + vector[i] *= 2; + + if vector[i] > 9 { + vector[i] -= 9; + } + + i += 2; + + if i >= vector.len() { + break; + } + } + + vector +} + +pub fn sum(vector: Vec) -> u32 { + vector.iter().sum() +} + +pub fn extract_digits_from_str_slice(code: &str) -> Vec { + code.chars() + .filter(|x| x.is_ascii_digit()) + .map(|x| x.to_digit(10).unwrap()) + .rev() + .collect() +} + +pub fn is_only_numbers_and_spaces(code: &str) -> bool { + for c in code.chars() { + if !c.is_ascii_digit() && !c.is_whitespace() { + return false; + }; + } + + true +} diff --git a/rust/luhn-trait/tests/luhn-trait.rs b/rust/luhn-trait/tests/luhn-trait.rs new file mode 100644 index 00000000..479e1cec --- /dev/null +++ b/rust/luhn-trait/tests/luhn-trait.rs @@ -0,0 +1,56 @@ +use luhn_trait::*; + +#[test] +fn you_can_validate_from_a_str() { + assert!("046 454 286".valid_luhn()); + assert!(!"046 454 287".valid_luhn()); +} + +#[test] +fn you_can_validate_from_a_string() { + assert!(String::from("046 454 286").valid_luhn()); + assert!(!String::from("046 454 287").valid_luhn()); +} + +#[test] +fn you_can_validate_from_a_u8() { + assert!(240u8.valid_luhn()); + assert!(!241u8.valid_luhn()); +} + +#[test] +fn you_can_validate_from_a_u16() { + let valid = 64_436u16; + let invalid = 64_437u16; + assert!(valid.valid_luhn()); + assert!(!invalid.valid_luhn()); +} + +#[test] +fn you_can_validate_from_a_u32() { + let valid = 46_454_286u32; + let invalid = 46_454_287u32; + assert!(valid.valid_luhn()); + assert!(!invalid.valid_luhn()); +} + +#[test] +fn you_can_validate_from_a_u64() { + let valid = 8273_1232_7352_0562u64; + let invalid = 8273_1232_7352_0569u64; + assert!(valid.valid_luhn()); + assert!(!invalid.valid_luhn()); +} + +#[test] +fn you_can_validate_from_a_usize() { + let valid = 8273_1232_7352_0562usize; + let invalid = 8273_1232_7352_0569usize; + assert!(valid.valid_luhn()); + assert!(!invalid.valid_luhn()); +} + +#[test] +fn input_digit_9_is_still_correctly_converted_to_output_digit_9() { + assert!("091".valid_luhn()); +}