ReverseRelativePath

Hello there!
I need a little help with a thing, havent found it on docs.
I need to retrieve as a str the reverse relative given two Path, as example:
Dir 1: /root/folder/subfolder/subsubfolder
Dir 2: /root/folder

To "go" from Dir2 to dir1 is ../../

I need a function or method with the "reverse" from dir1 to 2, that is:
./subfolder/subsubfolder.

Or the opposite, too, like
StrReverse = reverseRelativePath(Dir1, dir2);

StrReverse is ../../
Thank you!

It looks like what you want is to use Path::parent twice.

let my_path = Path::new("/root/folder/subfolder/subsubfolder");

let grandparent = my_path.parent()?.parent()?;
assert_eq!(Path::new("/root/folder", my_path));

Whathever since it results in the reverse path. But not only twice. Maybe a unknown amount of subfolders

Thanks for your kind answer!

Going from parent to sub is strip_prefix. Once stripped, you could count components or similar to go backwards.

There's a whole lot of fiddly corner-cases around canonicalization, trailing files, symlinks, and the like.

1 Like

Here's one possible approach. It may not handle all cases.

An improvement:

pub fn relative(from: &Path, to: &Path) -> PathBuf {
    let common = from
        .components()
        .zip(to.components())
        .take_while(|(a, b)| a == b)
        .count();
    from.components()
        .skip(common)
        .map(|_| Component::ParentDir)
        .chain(to.components().skip(common))
        .collect()
}
1 Like

Oh thanks, ill try some of those! :smiling_face::smiling_face::smiling_face:

Maybe RelativePathBuf in relative_path - Rust will be of help

thanks!
I`ve tried somethink like:

 let destiny_prefix =
                RelativePath::new(referencepath.canonicalize()?.to_str().unwrap())
                    .relative(RelativePath::new(
                        destinypath.canonicalize()?.to_str().unwrap(),
                    ))
                    .to_string()

but i cannot achieve the results i expect... at least not that way.

Guys you need to stop that... I was waiting an answer, once, maybe in 4 to 5 months blaming me lol. That community is great as told so!

Something alike that, thats the closest i`ve come :slight_smile:

use std::path::{Component, Path, PathBuf};

pub fn relative(from: &Path, to: &Path) -> PathBuf {
    let common = from
        .components()
        .zip(to.components())
        .take_while(|(a, b)| a == b)
        .count();
    let mut res = PathBuf::new();
    for c in from
        .components()
        .skip(common)
        .map(|_| Component::ParentDir)
        .chain(to.components().skip(common))
    {
        res.push(c);
    }
    res
}

fn main() {
    println!(
        "{:?}",
        relative(
            &"/root/folder/suba0".parse::<PathBuf>().unwrap(),
            &"/root/folder/subb0/suba1/suba2".parse::<PathBuf>().unwrap(),
            //&"/root/folder/subb0".parse::<PathBuf>().unwrap(),
        )
    )
}

got "../subb0/suba1/suba2"

now i can append a "/" at the end to get the "../subb0/suba1/suba2" i wanted. At least a modification in code do better.

thanks you all, dear friends!
God bless :smiley:

i only could achieve the result i wanted with:

// Does the same as canonicalize() but without needing the file to exist
fn canonical_path(path: &Path) -> PathBuf {
    let mut result = PathBuf::new();
    for component in path.components() {
        match component {
            Component::CurDir => continue,
            Component::ParentDir => {
                result.pop();
            }
            _ => result.push(component),
        }
    }
    result
}

//    the call REQUIRES ALREADY MADE &from_path.canonicalize()?,
fn reverse_relative_path(from: &Path, to: &Path) -> PathBuf {
    let path_to = canonical_path(to);
    let common = path_to
        .components()
        .zip(from.components())
        .take_while(|(a, b)| a == b)
        .count();
    let mut res = PathBuf::new();
    let mut skip_first_parent = true;
    for c in path_to
        .components()
        .skip(common)
        .map(|_| Component::ParentDir)
        .chain(from.components().skip(common))
    {
        if skip_first_parent && c == Component::ParentDir {
            skip_first_parent = false;
            continue;
        }
        res.push(c);
    }
    res
}

Like, from ".\src" to ".\target" : "..\src"
think something like: i am at the terminal prompt, and go from src to target:
cd ..
cd target

so, what i need to do to go "back" to src?
cd ..
*cd \src*

so thats the "..\src"

Thank you!!! :smiley:

By the way, if you enclose your code in 3 backticks, it'll render as a code block, making it easier for all of us to read.

Here's an example:

```
println!("blah");
```

will render as

println!("blah");
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.