Creating a loop of iterations

Can someone help me please, I am new to rust been doing some basic coding and tried to convert one other python script I had to rust to manage efficiency and memory usage but I cant seem to get it right, even AI could give a good direction, here's the code:

use rand::{thread_rng, Rng};

fn generate_strings() {
    let _p = 0;
    let mut keys = thread_rng().gen_range(16820263..268412967);
    let v = "00000000000000000000000000000000000000000000000000".to_string();
    loop {
        let x = format!("{:x}", keys);
        let b = (0..16).map(|i| format!("{:x}{}", i, x));
        let c = b.flat_map(|bi| (0..16).map(move |j| format!("{:x}{}", j, bi)));
        let d = c.flat_map(|ci| (0..16).map(move |k| format!("{:x}{}", k, ci)));
        let e = d.flat_map(|di| (0..16).map(move |l| format!("{:x}{}", l, di)));
        let f = e.flat_map(|ei| (0..16).map(move |m| format!("{:x}{}", m, ei)));
        let g = f.flat_map(|fi| (0..16).map(move |n| format!("{:x}{}", n, fi)));
        let h = g.flat_map(|gi| (0..16).map(move |o| format!("{:x}{}", o, gi)));
        let t = h.flat_map(|hi| (0..16).map(move |p| format!("{:x}{}", p, hi)));
        let u = t.flat_map(|ti| (0..16).map(move |q| format!("{:x}{}", q, ti)));
        let s = u.flat_map(|ui| (1..16).map(move |r| format!("{}{:x}{}", v.clone(), r, ui)));
        for string in s {
            println!("{}", string);
        }
        keys += 1;
    }
}

fn main() {
    generate_strings();
}

Can you please edit your post and add backticks around the code block so that it renders properly?

```
like this
```

Also, for the future, it's generally helpful if you can provide a playground link and a copy of the error message when you ask a question, as it makes it easier for us to investigate the problem.

   Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of `v`, a captured variable in an `FnMut` closure
  --> src/main.rs:18:45
   |
6  |     let v = "00000000000000000000000000000000000000000000000000".to_string();
   |         - captured outer variable
...
18 |         let s = u.flat_map(|ui| (1..16).map(move |r| format!("{}{:x}{}", v.clone(), r, ui)));
   |                            ----             ^^^^^^^^                     -
   |                            |                |                            |
   |                            |                |                            variable moved due to use in closure
   |                            |                `v` is moved here            move occurs because `v` has type `String`, which does not implement the `Copy` trait
   |                            captured by this `FnMut` closure

error[E0382]: use of moved value: `v`
  --> src/main.rs:18:28
   |
6  |     let v = "00000000000000000000000000000000000000000000000000".to_string();
   |         - move occurs because `v` has type `String`, which does not implement the `Copy` trait
...
18 |         let s = u.flat_map(|ui| (1..16).map(move |r| format!("{}{:x}{}", v.clone(), r, ui)));
   |                            ^^^^                                          - use occurs due to use in closure
   |                            |
   |                            value moved into closure here, in previous iteration of loop

I don't really understand what you're trying to accomplish here, so all I can really do is figure out how to make this compile; there might be a better approach that I'm not seeing.

Since you're never mutating v, there's no need to upgrade it from &str to String:

-let v = "00000000000000000000000000000000000000000000000000".to_string();
+let v = "00000000000000000000000000000000000000000000000000";

And, because &... is Copy, you don't need to clone v later:

-let s = u.flat_map(|ui| (1..16).map(move |r| format!("{}{:x}{}", v.clone(), r, ui)));
+let s = u.flat_map(|ui| (1..16).map(move |r| format!("{}{:x}{}", v, r, ui)));

With these two changes, the code compiles and runs.

1 Like

Thank you for your quick response it totally work as needed... You guys rock!!!

Even though that wasn't the question, I couldn't help trying to reduce the code duplication here…

fn f(a: impl Iterator<Item = String>) -> impl Iterator<Item = String> {
    a.flat_map(|a| (0..16).map(move |i| format!("{i:x}{a}")))
}
let a = std::iter::once(format!("{keys:x}"));
let s = f(f(f(f(f(f(f(f(f(f(a)))))))))).map(|a| format!("{v}{a}"));

Edit: Ah, I missed the 1..16 in the last line, that's different... with that taken into account, perhaps this is the way:

fn f(l: u8, a: impl Iterator<Item = String>) -> impl Iterator<Item = String> {
    a.flat_map(move |a| (l..16).map(move |i| format!("{i:x}{a}")))
}
let a = std::iter::once(format!("{keys:x}"));
let s = f(1, f(0, f(0, f(0, f(0, f(0, f(0, f(0, f(0, f(0, a))))))))))
    .map(|a| format!("{v}{a}"));
2 Likes

If you're flexible regarding the order of the output, I'd consider writing it like this. BTW, are you aware that the output is not fixed-length because of keys?

let _p = 0;
let mut keys = thread_rng().gen_range(0x100a827..0x100a827);
loop {
    for first_digit in 1..16 {
        for digits in 0u32..=0xFFFF_FFFF {
            println!("00000000000000000000000000000000000000000000000000{first_digit:x}{digits:08x}{keys}");
        }
    }
    keys += 1;
}
1 Like

I am also having trouble interpreting the intention of the code. But adapting @jendrikw's suggestion, this retains the original ordering (and fixes some bugs in the transformation).

fn generate_strings() {
    let v = "00000000000000000000000000000000000000000000000000";
    let mut keys = thread_rng().gen_range(16820263..268412967);
    let mut buffer = String::new();
    loop {
        for first_digit in 1..16 {
            for digits in 0..=0xf_ffff_ffff_u64 {
                println!(
                    "{v}{first_digit:x}{reversed}{keys:x}",
                    reversed = rev(&mut buffer, digits),
                );
            }
        }
        keys += 1;
    }
}

fn rev(buffer: &mut String, mut y: u64) -> &str {
    buffer.clear();
    for _ in 0..9 {
        buffer.push(char::from_digit(y as u32 & 0xf, 16).unwrap());
        y >>= 4;
    }

    buffer
}

You can also do some fancy bit-twiddling to reverse the digits, but this is more readable, IMHO.