Rust Challenge: Implementing a Generic Luhn Algorithm Trait
Learn how to implement a flexible Luhn algorithm validation trait in Rust. This practical guide covers trait implementation, generic programming, and type conversion in Rust through a real-world example.
Rust Challenge: Implementing the Luhn Trait
In this Rust challenge, we'll implement a flexible trait for the Luhn algorithm. The Luhn algorithm is commonly used for validating various identification numbers, such as credit card numbers, Canadian Social Insurance Numbers, etc.
Challenge Description
The Luhn algorithm can be applied to various data types (strings, integers, etc.). Instead of creating a struct solely for validation purposes, we'll create and implement a custom trait to perform validation directly on different data types.
Prerequisites
You may want to familiarize yourself with the basic Luhn algorithm through these exercises:
exercism download --exercise=luhn --track=rust
exercism download --exercise=luhn-from --track=rust
Solution
Here's an implementation that demonstrates Rust's trait system and generic programming capabilities:
pub trait Luhn {
fn valid_luhn(&self) -> bool;
}
/// Implement auxiliary functions for Luhn algorithm
fn luhn_digits<I>(digits: I) -> bool
where
I: IntoIterator<Item = u8>,
{
let digits: Vec<u8> = digits.into_iter().collect();
let checksum: u8 = digits
.iter()
.rev()
.enumerate()
.map(|(i, &digit)| {
if i % 2 == 1 {
let doubled = digit * 2;
if doubled > 9 { doubled - 9 } else { doubled }
} else {
digit
}
})
.sum();
checksum % 10 == 0
}
impl<'a> Luhn for &'a str {
fn valid_luhn(&self) -> bool {
let digits: Vec<u8> = self.chars()
.filter_map(|c| c.to_digit(10).map(|d| d as u8))
.collect();
luhn_digits(digits)
}
}
impl Luhn for u64 {
fn valid_luhn(&self) -> bool {
let digits: Vec<u8> = self.to_string()
.chars()
.filter_map(|c| c.to_digit(10).map(|d| d as u8))
.collect();
luhn_digits(digits)
}
}
impl Luhn for String {
fn valid_luhn(&self) -> bool {
let digits: Vec<u8> = self.chars()
.filter_map(|c| c.to_digit(10).map(|d| d as u8))
.collect();
luhn_digits(digits)
}
}
impl Luhn for u8 {
fn valid_luhn(&self) -> bool {
luhn_digits(vec![*self])
}
}
impl Luhn for u16 {
fn valid_luhn(&self) -> bool {
let digits: Vec<u8> = self.to_string()
.chars()
.filter_map(|c| c.to_digit(10).map(|d| d as u8))
.collect();
luhn_digits(digits)
}
}
impl Luhn for u32 {
fn valid_luhn(&self) -> bool {
let digits: Vec<u8> = self.to_string()
.chars()
.filter_map(|c| c.to_digit(10).map(|d| d as u8))
.collect();
luhn_digits(digits)
}
}
impl Luhn for usize {
fn valid_luhn(&self) -> bool {
let digits: Vec<u8> = self.to_string()
.chars()
.filter_map(|c| c.to_digit(10).map(|d| d as u8))
.collect();
luhn_digits(digits)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid_luhn_str() {
assert!("091".valid_luhn());
assert!("046 454 286".valid_luhn());
assert!(!"046 454 287".valid_luhn());
}
#[test]
fn test_valid_luhn_string() {
assert!(String::from("046 454 286").valid_luhn());
assert!(!String::from("046 454 287").valid_luhn());
}
#[test]
fn test_valid_luhn_u16() {
let valid = 64_436u16;
let invalid = 64_437u16;
assert!(valid.valid_luhn());
assert!(!invalid.valid_luhn());
}
#[test]
fn test_valid_luhn_u32() {
let valid = 46_454_286u32;
let invalid = 46_454_287u32;
assert!(valid.valid_luhn());
assert!(!invalid.valid_luhn());
}
#[test]
fn test_valid_luhn_u64() {
let valid = 8273_1232_7352_0562u64;
let invalid = 8273_1232_7352_0569u64;
assert!(valid.valid_luhn());
assert!(!invalid.valid_luhn());
}
#[test]
fn test_valid_luhn_u8() {
assert!(240u8.valid_luhn());
assert!(!241u8.valid_luhn());
}
#[test]
fn test_valid_luhn_usize() {
let valid = 8273_1232_7352_0562usize;
let invalid = 8273_1232_7352_0569usize;
assert!(valid.valid_luhn());
assert!(!invalid.valid_luhn());
}
}
Related Posts
GitHub Daily Recommendation 2025-01-23
🚀 GitHub Daily Recommendations Alert! 🌟 Dive into today's top open-source treasures, from cutting-edge AI tools to essential Web Frontend Development resources. 🌐✨ Don't miss out on the latest in Cloud Computing, Data Analysis, and more! 📊🔧 #OpenSourceProjects #Featured
Product Hunt Daily Recommendation 2025-01-23
Discover the latest Product Hunt daily picks for today's top innovations! Dive into hand-picked AI tools, SaaS products, and mobile apps. Explore, learn, and be the first to try out the newest tech trends. 🚀 #ProductHunt #DailyInnovations #TechTrends
GitHub Daily Recommendation 2025-01-21
🚀 GitHub Daily Recommendations Alert! 🌟 Dive into today's top-notch open-source projects, from cutting-edge AI tools to essential Web Frontend Development resources. 🌐 Enhance your coding skills and discover the best of open-source innovation right here! 📚✨