1use std::iter::repeat_with;
2
3use chrono::{Datelike, Local};
4use rand::seq::SliceRandom;
5use rand::{Rng, RngCore};
6
7use crate::Unreal;
8use crate::data::payment::CARD;
9
10impl<R: RngCore> Unreal<R> {
12 fn card(&mut self) -> (&'static str, &'static [&'static str]) {
13 *CARD.choose(self).expect("CARDS should not be empty")
14 }
15
16 pub fn card_type(&mut self) -> &str {
18 self.card().0
19 }
20
21 pub fn credit_card_number(&mut self) -> String {
25 self.credit_card_number_inner().take(16).collect()
26 }
27
28 fn credit_card_number_inner(&mut self) -> impl Iterator<Item = char> {
29 let starts = Self::card(self).1;
30 let start =
31 *SliceRandom::choose(starts, self).expect("all cards should have starting digits");
32 start
33 .chars()
34 .chain(repeat_with(|| (b'0' + self.gen_range(0..=9)) as char))
35 }
36
37 pub fn credit_card_luhn_number(&mut self) -> String {
39 let number: String = self.credit_card_number_inner().take(15).collect();
40 let check_digit = ((10
41 - (number
42 .chars()
43 .enumerate()
44 .map(|(index, digit)| {
45 let digit = digit as u8 - b'0';
46 u32::from(if index % 2 == 0 {
47 (digit * 2) % 9
48 } else {
49 digit
50 })
51 })
52 .sum::<u32>()
53 % 10))
54 % 10)
55 .to_string();
56 number + &check_digit
57 }
58
59 pub fn credit_card_exp(&mut self) -> String {
62 let year = (Local::now().year() + self.gen_range(1..=10)).to_string();
63 let month = self.month();
64 format!("{:0>2}/{}", month, &year[year.len() - 2..])
65 }
66
67 pub fn credit_card_cvv(&mut self) -> String {
69 self.digits(3)
70 }
71}