First thing I noticed: you're using char (which takes 32 bits in memory) to store instructions (which carry only 3 bits of information).
I would suggest making an enum of the instructions. Then you'll use less RAM, and the processing match can be exhaustively checked to be sure you've implemented all of them -- and thus you'd be able to remove this vestigial arm.
This is a classic Parse, don’t validate suggestion -- rather than checking that you only have the values you understand, and assuming in a bunch of processing code later, convert the input into something that can only represent what you expect, so your brain doesn't need to remember implicit context.
Read and adhere to the Rust API Guidelines Checklist. For example, you are not implementing any common traits (Default, Clone, Debug) on your structs. The entire Machine::new() function could be removed and replaced with the automatically derived implementation of Default.
The execution of loop instructions seems to be more convoluted than it needs to be. Perhaps because when you find an opening bracket, you initialize the bracket level to 0 (rather than 1), so you've got an extra condition to check. I would try to clean up these instructions. You are not really parsing the instructions in parse_instructions, either – you are effectively re-parsing the structure of brackets every time you get to one.
The following piece and its analogous repetitions are unnecessary:
Thank you @scottmcm@H2CO3 and Cerber-Ursi for taking your time and giving feedback. I spent the entire day making changes to my code incorporating your suggestions.
I am now using an enum for encoding and parsing the instructions.
I was not aware of the Rust API Guidelines. I have now implemented some of the common interoperability traits for the Machine struct. I was also able to replace Machine::new() with Machine::default()
I have tried to simplify the execution of the instructions as much as I could by getting rid of the unnecessary checks and statements and making use of standard library functions like u8::wrapping_add, u8::wrapping_sub and u8::rem_euclid.
Changing collect() in main() to nth(1) was simple enough
After all of this the code still compiles with no warnings and the linter gives no warnings as well.
Are the changes I made all right? what other changes do I need to make?
Also related to the derives, it's odd to see Hash without Eq, because the normal place to make use of Hash is in HashMap in std::collections - Rust, where the key type wants both Hash & Eq -- because just Hash isn't enough to lookup something in a hashmap, due to the collision potential.