How do I convert Python context manager to Rust?

43 views Asked by At

I have this Python code from an existing project that I'm trying to port to Rust as a learning exercise (plus a thing I actually have a use for if I succeed):

class BaseKlazz:
    # stuff

    # from contextlib import contextmanager
    @contextmanager
    def set_directory(self, path: str):
        orig_dir = os.getcwd()
        try:
            os.chdir(path)
            yield
        finally:
            os.chdir(org_dir)
class Klazz(BaseKlazz):
    # stuff

    def funktion():
        # do stuff
        try:
            # rm -rf somedir
            # mkdir -p somedir

            with self.set_directory(somedir): # <-- How do I port this to Rust?
                # do things, maybe write files, maybe more mkdir, maybe write more files
                pass

            # potentially do more things with original dir
        except:
            # handle/propagate library/application errors
            pass

The original codebase is in Python and therefore makes use of OOP and exceptions, which are not the easiest things to port to Rust, but manageable.

The generators / context managers it uses though, I'm not sure how I can port to rust. I saw this question which suggests I use RAII, but I'm still unsure how to make that work:

pub struct ChdirGuard {
    original_path: PathBuf
}

impl ChdirGuard {
    pub fn new(target_path: PathBuf) -> ChdirGuard {
        let chdir_guard = ChdirGuard {
            original_path: std::env::current_dir().unwrap()
        };

        std::env::set_current_dir(&target_path);

        return chdir_guard
    }
}

impl Drop for ChdirGuard {
    fn drop(&mut self) {
        std::env::set_current_dir(&self.original_path)
    }
}
struct Klazz {}
impl Klazz {
    pub fn funktion(&self) {
        // rm -rf somedir + check result of rm, because rust
        // mkdir -p somedir + check result of mkdir, because rust

        {
            let _ = ChdirGuard::new(PathBuf::from("somedir"));

            // do things, maybe write files, maybe more mkdir, maybe write more files
        }

        // potentially do more things with original dir
    }
}

Looks a bit jank, certainly not used to seeing a random unnamed block in the middle of a function. Maybe I'm missing something, or is this really the way to do RAII in Rust? Will it work if I .unwrap() and explode, return prematurely from funktion with a Result, etc. ?

0

There are 0 answers