1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
// The author disclaims copyright to this source code. In place of // a legal notice, here is a blessing: // May you do good and not evil. // May you find forgiveness for yourself and forgive others. // May you share freely, never taking more than you give. //! This is a Rust implementation of the [Damm algorithm](https://en.wikipedia.org/wiki/Damm_algorithm). //! The algorithm is used for ID validation to catch //! common transposition errors. //! //! This crate provides a simple and fast implementation //! of the Damm algorithm using `u128` as the type of the id. //! The only downside to this approach is that the largest ID //! that one can use is `340282366920938463463374607431768211455`, //! which means that the largest number of digits that one can use //! _reliably_ is 38. //! //! If for some reason this is a major issue for someone needing any //! more digits than that, open an issue at gitlab and I'll extend this //! library to provide a string representation for Really Long ID's™. extern crate digits_iterator; use digits_iterator::DigitsExtension; // usize to avoid casting everywhere (elements of this // are used as indicies) const OP_TABLE: [[usize; 10]; 10] = [ [0, 3, 1, 7, 5, 9, 8, 6, 4, 2], [7, 0, 9, 2, 1, 5, 4, 8, 6, 3], [4, 2, 0, 6, 8, 7, 1, 3, 5, 9], [1, 7, 5, 0, 9, 8, 3, 4, 2, 6], [6, 1, 2, 3, 0, 4, 5, 9, 7, 8], [3, 6, 7, 4, 2, 0, 9, 5, 8, 1], [5, 8, 6, 9, 7, 2, 0, 1, 3, 4], [8, 9, 4, 5, 3, 6, 2, 0, 1, 7], [9, 4, 3, 8, 6, 1, 7, 2, 0, 5], [2, 5, 8, 1, 4, 3, 6, 7, 9, 0] ]; // Used for both generation and verification fn check_digit(bare_id: u128) -> usize { let mut interim = 0; for digit in bare_id.digits() { interim = OP_TABLE[interim][digit as usize]; } interim } /// Is an ID valid? /// /// # Example /// ```rust /// # use damm; /// if damm::verify(928374629172) { /// // ... (will execute) /// } /// # else { /// # panic!(); /// # } pub fn verify(id: u128) -> bool { check_digit(id) == 0 } /// Append a checksum to an existing ID /// /// # Example /// ```rust /// # use damm; /// // Could be a random number /// let id = damm::id(8293); // 82931 /// ``` pub fn id(bare_id: u128) -> u128 { let sum = check_digit(bare_id); (bare_id * 10) + sum as u128 } #[cfg(test)] mod tests { use *; // This id is pulled from wikipedia // The others were generated using this library (bad) #[test] fn _572() { assert_eq!(check_digit(572), 4); assert_eq!(id(572), 5724); assert!(verify(5724)); } #[test] fn _8293() { assert_eq!(check_digit(8293), 1); assert_eq!(id(8293), 82931); assert!(verify(82931)); } #[test] fn _92837462917() { assert_eq!(check_digit(92837462917), 2); assert_eq!(id(92837462917), 928374629172); assert!(verify(928374629172)); } }