Atbash Cipher in Rust - Exercism exercise
// "Encipher" with the Atbash cipher.
pub fn encode(plain: &amp;str) -&gt; String {
    let mut coded: String = plain.to_string();

    coded.retain(|c| c.is_ascii_alphanumeric());
    coded.make_ascii_lowercase();

    let coded_no_spacing = String::from_utf8(
        coded
            .bytes()
            .map(|c| {
                if c.is_ascii_alphabetic() {
                    122 - c + 97


You can b'z' and b'a' to refer to the ascii codes of the letters.

                } else {
                    c
                }
            })
            .collect(),
    )
    .unwrap();

    spacer(coded_no_spacing)
}


You are mixing two different approaches here. Firstly, you make a string out of the input and then modify it. Secondly, you use an iterator over the bytes of the string. This code would be more straightforward if you just iterated over the letters.

Here is my approach:

plain
    .chars()
    .filter_map(|c| {
        if c.is_ascii_alphabetic() {
            let letter = c.to_ascii_lowercase() as u8;
            Some(char::from(b'z' - letter + b'a'))
        } else if c.is_ascii_alphanumeric() {
            Some(c)
        } else {
            None
        }
    })
    .collect()


If you haven't seen it before, the filter_map function combines filtering and mapping. The closure can return either None, to remove the element or Some(x) to provide an element in the output.

/// "Decipher" with the Atbash cipher.
pub fn decode(cipher: &amp;str) -&gt; String {
    let mut out = encode(cipher);
    out.retain(|c| c.is_ascii_alphanumeric());
    out
}


It took me a bit to figure out why you were filtering the chars again. But I see it is remove the spacing. It would make more sense to split the basic ciphering and into its own function so you can call that without adding the spacing. Then you wouldn't have to filter it.

fn spacer(coded_no_spacing: String) -&gt; String {
    let mut coded_no_spacing = coded_no_spacing.chars();

    let mut temp_char = coded_no_spacing.next();
    let mut counter = 0;
    let mut coded_with_spaces = "".to_string();


I would use String::new() to create an empty string. For "extra credit", you could use String::with_capacity to reserve the correct amount of space for the string, something like:

String::with_capacity(coded_no_spacing.len() + coded_no_spacing.len() / 5);


That's dubiously worthwhile, but sometimes it can be a helpful optimization.

Onwards:

    while temp_char.is_some() {


Firstly, there is a construct you can use when you want to iterate as long as something return Some instead of None.

while let Some(temp_char) = coded_no_spacing.next()


But in this case, this is just iterating over for the chars, so you should use a forloop

for temp_char in coded_no_spacing.chars()

        if counter % 5 == 0 &amp;&amp; counter != 0 {
            coded_with_spaces.push(' ');
        }
        coded_with_spaces.push(temp_char.unwrap());
        temp_char = coded_no_spacing.next();
        counter += 1;


Instead of counting, use the enumerate() method on iterator. It will give you an index.

    }
    coded_with_spaces
}


Here is my version:

fn spacer(coded_no_spacing: &amp;str) -&gt; String {
    let mut coded_with_spaces = String::new();

    for (index, char) in coded_no_spacing.chars().enumerate() {
        if index % 5 == 0 &amp;&amp; index != 0 {
            coded_with_spaces.push(' ');
        }
        coded_with_spaces.push(char);
    }

    coded_with_spaces
}