All Projects β†’ udoprog β†’ relative-path

udoprog / relative-path

Licence: Apache-2.0, MIT licenses found Licenses found Apache-2.0 LICENSE-APACHE MIT LICENSE-MIT
Portable relative UTF-8 paths for Rust.

Programming Languages

rust
11053 projects

Projects that are alternatives of or similar to relative-path

llvm-epp
Efficient Path Profiling using LLVM
Stars: ✭ 16 (-70.37%)
Mutual labels:  path
intellij-idea-community-portable
πŸš€ IntelliJ IDEA Community portable for Windows
Stars: ✭ 41 (-24.07%)
Mutual labels:  portable
Port-Able-Suite
🌐 Manager for portable applications
Stars: ✭ 35 (-35.19%)
Mutual labels:  portable
highlight
Source code to formatted text converter
Stars: ✭ 44 (-18.52%)
Mutual labels:  portable
react-svg-pathline
React component for drawing SVG path through set of points, smoothing the corners
Stars: ✭ 42 (-22.22%)
Mutual labels:  path
XRadarView
A highly customizable radar view for Android
Stars: ✭ 106 (+96.3%)
Mutual labels:  path
path-absolutize
A library for extending `Path` and `PathBuf` in order to get an absolute path and remove the containing dots.
Stars: ✭ 37 (-31.48%)
Mutual labels:  path
xtd
Free open-source modern C++17 / C++20 framework to create console, forms (GUI like WinForms) and unit test applications on Microsoft Windows, Apple macOS and Linux.
Stars: ✭ 321 (+494.44%)
Mutual labels:  portable
path-that-svg
Path that SVG!
Stars: ✭ 45 (-16.67%)
Mutual labels:  path
Asuite
ASuite is a simple open source portable launcher for Microsoft Windows.
Stars: ✭ 58 (+7.41%)
Mutual labels:  portable
vlc-portable
πŸš€ VLC Media Player portable for Windows
Stars: ✭ 17 (-68.52%)
Mutual labels:  portable
Windows10Tools
Tools for Windows 10
Stars: ✭ 45 (-16.67%)
Mutual labels:  portable
signal-portable
πŸš€ Signal portable for Windows
Stars: ✭ 22 (-59.26%)
Mutual labels:  portable
mulle-thread
πŸ” Β Cross-platform thread/mutex/tss/atomic operations in C
Stars: ✭ 22 (-59.26%)
Mutual labels:  portable
EverythingPortable
EverythingPortable
Stars: ✭ 59 (+9.26%)
Mutual labels:  portable
wine-portable-executable
Wine builds packed into portable executables
Stars: ✭ 85 (+57.41%)
Mutual labels:  portable
DebugVision
Portable set of log collection and visualization tools
Stars: ✭ 45 (-16.67%)
Mutual labels:  portable
PCLExt.FileStorage
Portable Storage APIs
Stars: ✭ 35 (-35.19%)
Mutual labels:  portable
BezierKit
Bezier curves and paths in Swift for building vector applications
Stars: ✭ 190 (+251.85%)
Mutual labels:  path
get-bin-path
Get the current package's binary path
Stars: ✭ 25 (-53.7%)
Mutual labels:  path

relative-path

github crates.io docs.rs build status

Portable relative UTF-8 paths for Rust.

This provide a module analogous to std::path, with the following characteristics:

  • The path separator is set to a fixed character (/), regardless of platform.
  • Relative paths cannot represent a path in the filesystem without first specifying what they are relative to through to_path.
  • Relative paths are always guaranteed to be a UTF-8 string.

On top of this we support many path-like operations that guarantee portable behavior.


Usage

Add the following to your Cargo.toml:

relative-path = "1.6.1"

Serde Support

This library includes serde support that can be enabled with the serde feature.


Why is std::path a portability hazard?

Path representations differ across platforms.

  • Windows permits using drive volumes (multiple roots) as a prefix (e.g. "c:\") and backslash (\) as a separator.
  • Unix references absolute paths from a single root and uses slash (/) as a separator.

If we use PathBuf, Storing paths like this in a manifest would happily allow our applications to build and run on one platform, but potentially not others.

Consider the following manifest:

use std::path::PathBuf;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct Manifest {
    source: PathBuf,
}

Which represents this TOML file:

# Uh oh, trouble.
source = "C:\\path\\to\\source"

Assuming "C:\\path\\to\\source" is a legal path on Windows, this will happily run for one platform when checked into source control but not others.

Since RelativePath strictly uses / as a separator it avoids this issue. Anything non-slash will simply be considered part of a distinct component.

Conversion to Path may only happen if it is known which path it is relative to through the to_path or to_logical_path functions. This is where the relative part of the name comes from.

use relative_path::RelativePath;
use std::path::Path;

// to_path unconditionally concatenates a relative path with its base:
let relative_path = RelativePath::new("../foo/./bar");
let full_path = relative_path.to_path("C:\\");
assert_eq!(full_path, Path::new("C:\\..\\foo\\.\\bar"));

// to_logical_path tries to apply the logical operations that the relative
// path corresponds to:
let relative_path = RelativePath::new("../foo/./bar");
let full_path = relative_path.to_logical_path("C:\\baz");
assert_eq!(full_path, Path::new("C:\\foo\\bar"));

This would permit relative paths to portably be used in project manifests or configurations. Where files are referenced from some specific, well-known point in the filesystem.

source = "path/to/source"

The fixed manifest would look like this:

use relative_path::RelativePathBuf;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Manifest {
    source: RelativePathBuf,
}

Overview

When two relative paths are compared to each other, their exact component makeup determines equality.

use relative_path::RelativePath;

assert_ne!(
    RelativePath::new("foo/bar/../baz"),
    RelativePath::new("foo/baz")
);

Using platform-specific path separators to construct relative paths is not supported.

Path separators from other platforms are simply treated as part of a component:

use relative_path::RelativePath;

assert_ne!(
    RelativePath::new("foo/bar"),
    RelativePath::new("foo\\bar")
);

assert_eq!(1, RelativePath::new("foo\\bar").components().count());
assert_eq!(2, RelativePath::new("foo/bar").components().count());

To see if two relative paths are equivalent you can use normalize:

use relative_path::RelativePath;

assert_eq!(
    RelativePath::new("foo/bar/../baz").normalize(),
    RelativePath::new("foo/baz").normalize(),
);

Additional portability notes

While relative paths avoid the most egregious portability issues, namely that absolute paths will work equally unwell on all platforms. We do not avoid all.

This section tries to document additional portability issues that we know about.

RelativePath, similarly to Path, makes no guarantees that the components represented in them makes up legal file names. While components are strictly separated by slashes, we can still store things in path components which may not be used as legal paths on all platforms.

  • NUL is not permitted on unix platforms - this is a terminator in C-based filesystem APIs. Slash (/) is also used as a path separator.
  • Windows has a number of reserved characters and names.

A relative path that actually contains a platform-specific absolute path will result in a nonsensical path being generated.

use relative_path::RelativePath;
use std::path::Path;

if cfg!(windows) {
    assert_eq!(
        Path::new("foo\\c:\\bar\\baz"),
        RelativePath::new("c:\\bar\\baz").to_path("foo")
    );
}

if cfg!(unix) {
    assert_eq!(
        Path::new("foo/bar/baz"),
        RelativePath::new("/bar/baz").to_path("foo")
    );
}

This is intentional in order to cause an early breakage when a platform encounters paths like "foo/c:\\bar\\baz" to signal that it is a portability hazard. On Unix it's a bit more subtle with ""foo/bar/baz"", since the leading slash (/) will simply be ignored. The hope is that it will be more probable to cause an early error unless a compatible relative path also exists.

License: MIT/Apache-2.0

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].