Proper way to use PathBuf


#1

Hello, I’ve just started to learn Rust. So, probably my problems arise from misunderstanding of some concepts.
Currently I’m experiencing problems using PathBuf. I want to construct some path to directory and then set it as CWD.
The simplified code below arises several questions:


let pb = PathBuf::new("/home/marvin/imonitor");
env::set_current_dir(*pb);

And the first question here is Deref trait. From its implementation for PathBuf I could see that dereference returns reference to Path:


impl ops::Deref for PathBuf {
    type Target = Path;
    fn deref(&self) -> &Path {
        unsafe { mem::transmute(&self.inner[..]) }
    }
}

But type Target is Path, so my code won’t compile, I have to change it to something like that:


let pb = PathBuf::new("/home/marvin/imonitor");
env::set_current_dir(&*pb); // &* looks wrong to me, but OK.

Still, this code doesn’t compile:


expected `&std::old_path::posix::Path`,
found `&std::path::Path`

Why? I decided to check env::set_current_dir implementation. It expects reference to some Path as it’s argument:


pub fn set_current_dir(p: &Path) -> IoResult<()> {
    os_imp::chdir(p)
}

What kind of Path it expects? Let’s check imports section:


use prelude::v1::*;

In prelude:


pub use old_path::{Path, GenericPath};

In mod.rs of old_path:


#[cfg(unix)]
pub use self::posix::Path as Path;

Now we have two Path structs to deal with. One, constructed from PathBuf:


pub struct Path {
    inner: OsStr
}

Another, expected by set_current_dir:


pub struct Path {
    repr: Vec,
    sepidx: Option
}

Basically, OsStr is just container for [u8]. So I could cast first Path to second:


trait AsOldPosixPath {
    fn as_old_path(&self) -> Option;
}

impl AsOldPosixPath for std::path::Path {
    fn as_old_path(&self) -> Option {
        match self.to_str() {
            Some(str_ref) => Some(std::old_path::posix::Path::new(str_ref)),
            None => None
        }
    }
}

fn main() {
    //........
    let pb = PathBuf::new("/home/marvin/imonitor");
    match pb.as_old_path() {
        Some(old_path) => {env::set_current_dir(&old_path);},
        None => panic!("Couldn't convert path!")
    }
    //........
}

This works but seems incredibly wrong to me.
As I stated earlier, it’s possible that I just don’t understand some concepts. Please, help me with it.
P.S.
Sorry for overly-detailed explanation. I just wanted to make sure, that I move in right direction.


#2

I think the main problem here is that std::env is currently using old paths, which was done to ease transition. However, there is now a PR to update it which should be landing soon.

Once this is done, you should be able to call set_current_dir(&some_path_buf).