pub struct SafeRelativePath(/* private fields */);Expand description
A borrowed relative path that statically cannot escape its parent.
This is the borrowed, unsized companion to SafeRelativePathBuf: same
guarantee, same string form, just held as &SafeRelativePath. Use this
type in function signatures to make the caller prove the path is safe
before you touch it; reach for SafeRelativePathBuf when you need
ownership.
To construct one from a literal that’s known at compile time, use the
srpath! macro — it validates the literal at compile
time and produces a &'static SafeRelativePath with no run-time cost.
For the limits of the guarantee (specifically, what happens with symlinks), see the crate-level note.
Implementations§
Source§impl SafeRelativePath
impl SafeRelativePath
Sourcepub fn to_safe_relative_path_buf(&self) -> SafeRelativePathBuf
pub fn to_safe_relative_path_buf(&self) -> SafeRelativePathBuf
Copy this borrowed path into an owned SafeRelativePathBuf.
Sourcepub fn normalize_safe(&self) -> SafeRelativePathBuf
pub fn normalize_safe(&self) -> SafeRelativePathBuf
Collapse . components and produce a normalised owned path.
Unlike Path::canonicalize this is purely lexical — no filesystem
access. A SafeRelativePath cannot contain .. segments, so
normalisation only ever drops . components.
§Example
use zenops_safe_relative_path::SafeRelativePath;
let p = SafeRelativePath::from_relative_path("a/./b").unwrap();
assert_eq!(p.normalize_safe().as_str(), "a/b");Sourcepub fn safe_join(
&self,
path: impl AsRef<SafeRelativePath>,
) -> SafeRelativePathBuf
pub fn safe_join( &self, path: impl AsRef<SafeRelativePath>, ) -> SafeRelativePathBuf
Join another already-safe path onto this one.
The infallible counterpart to try_join: both
sides are already known to be safe, so the join cannot introduce
traversal and no validation is needed.
§Example
use zenops_safe_relative_path::srpath;
let joined = srpath!("config").safe_join(srpath!("app.toml"));
assert_eq!(joined.as_str(), "config/app.toml");Source§impl SafeRelativePath
impl SafeRelativePath
Sourcepub const unsafe fn new_unchecked_from_str(v: &str) -> &Self
pub const unsafe fn new_unchecked_from_str(v: &str) -> &Self
Reinterpret a &str as a SafeRelativePath without checking it.
§Safety
The caller must guarantee that v would succeed if passed through
from_relative_path — it has to parse as
a RelativePath and contain no .. components. Violating this
hands out a SafeRelativePath whose safety invariant doesn’t hold,
and any downstream code that trusts the type is misled.
Sourcepub const unsafe fn new_unchecked(v: &RelativePath) -> &Self
pub const unsafe fn new_unchecked(v: &RelativePath) -> &Self
Reinterpret a &RelativePath as a SafeRelativePath without
checking it.
§Safety
The caller must guarantee that v contains no .. components — i.e.
would succeed if passed through
from_relative_path.
Sourcepub fn from_relative_path<P>(v: &P) -> Result<&Self, Error>
pub fn from_relative_path<P>(v: &P) -> Result<&Self, Error>
Try to view an arbitrary RelativePath as a SafeRelativePath.
Returns Error::PathGoesOutsideParent if the path contains any
.. segment — including ones that would
notionally cancel out: a/../b is rejected even though it normalises
to b. Anything else, including the empty path and ., succeeds.
§Example
use zenops_safe_relative_path::SafeRelativePath;
assert!(SafeRelativePath::from_relative_path("config/app.toml").is_ok());
assert!(SafeRelativePath::from_relative_path("../etc/passwd").is_err());
assert!(SafeRelativePath::from_relative_path("a/../b").is_err());Sourcepub fn try_join(
&self,
path: impl AsRef<RelativePath>,
) -> Result<SafeRelativePathBuf, Error>
pub fn try_join( &self, path: impl AsRef<RelativePath>, ) -> Result<SafeRelativePathBuf, Error>
Join another path onto this one, returning an error if the joined segment would escape.
This is the safe counterpart to Path::join for inputs that come
from configuration or another untrusted source: the result is still
a relative path contained by the original base.
§Example
use zenops_safe_relative_path::srpath;
let base = srpath!("config");
assert_eq!(
base.try_join("app.toml").unwrap().as_str(),
"config/app.toml",
);
assert!(base.try_join("../../etc/passwd").is_err());Sourcepub fn to_full_path(&self, base: impl AsRef<Path>) -> PathBuf
pub fn to_full_path(&self, base: impl AsRef<Path>) -> PathBuf
Resolve this relative path against base to produce an absolute
PathBuf.
Use this at the edge of the program, when a SafeRelativePath
finally needs to be handed to a filesystem call against a known
root — typically $HOME or $XDG_CONFIG_HOME. The result is base
followed by this path’s components, with no .. traversal between
them.
§Example
use std::path::Path;
use zenops_safe_relative_path::srpath;
let abs = srpath!("config/app.toml").to_full_path(Path::new("/home/ada"));
assert_eq!(abs, Path::new("/home/ada/config/app.toml"));Sourcepub fn safe_parent(&self) -> Option<&SafeRelativePath>
pub fn safe_parent(&self) -> Option<&SafeRelativePath>
Return the parent path, or None if there is no parent.
The parent of a SafeRelativePath is itself a SafeRelativePath
— dropping a final component can never introduce traversal.
§Example
use zenops_safe_relative_path::srpath;
assert_eq!(srpath!("a/b/c").safe_parent().unwrap().as_str(), "a/b");
assert!(srpath!("").safe_parent().is_none());