Skip to content

Jonstep101010/minishell-rs

Repository files navigation

A gradual rewrite of a c2rust transpiled codebase.

Discover how C language programming constructs can be implemented in a more concise way.

goals

  1. see where rust syntax and std containers can enable better readability or code structure
  2. discover where CString, CStr and &[u8] (u8) can find usage and reduce interactions with char *
  3. replace extern "C" and libc usage with nix wrappers, enabling more idiomatic (and less error prone?) usage of unix system functions.
  4. provide me with an excuse to write rust code

journey

context

The original implementation used loads of custom glue that could have been replaced with libc functions (strtok, strcoll, scanf/sprintf, fprintf).

This was fine as a school project and provided me with ample opportunities for refactoring in the rust version.

key takeaways

  • since rust is not c, interacting with raw pointers is more error prone due to its memory model and my assumptions about memory derived from c
  • signal handling was easier to do in c, I ended up removing it as it caused weird bugs
  • even though rust has Command, it was not used. I adapted my execution logic to be more idiomatic by using nix wrappers (the reason for most unsafe usage)
  • taking advantage of rust's rich type system can improve readability and facilitate quick iteration - choosing the correct tool is key

process

tactics

  1. transpile, then simplify some operations, mostly aligning types (e.g. libc::size_t for u64/usize), removing non-needed casts and replacing .offset() with .add()
  2. multiple failed rewrites of core functionality caused by newly introduced logic bugs - mitigated by comprehensive test cases
  3. issues with readability, naming - resolved by using more idiomatic constructs: Option, Result, tuples, slices instead of references, impl for structs
  4. remove duplicate or dead code replaced by std (format!, vec![], ...)

strategy

  1. document & simplify original logic
  2. create adaptable tests, wrappers fitting both c-like and idiomatic rust outputs
  3. apply TDD feedback loop while simplifying logic and reducing unsafe