VirtualPath

Struct VirtualPath 

Source
pub struct VirtualPath<Marker = ()> { /* private fields */ }
Expand description

SUMMARY: Hold a user‑facing path clamped to a virtual root ("/") over a PathBoundary.

DETAILS: virtualpath_display() shows rooted, forward‑slashed paths (e.g., "/a/b.txt"). Use virtual manipulation methods to compose paths while preserving clamping, then convert to StrictPath with unvirtual() for system‑facing I/O.

Implementations§

Source§

impl<Marker> VirtualPath<Marker>

Source

pub fn with_root<P: AsRef<Path>>(root: P) -> Result<Self>

SUMMARY: Create the virtual root ("/") for the given filesystem root.

Source

pub fn with_root_create<P: AsRef<Path>>(root: P) -> Result<Self>

SUMMARY: Create the virtual root, creating the filesystem root if missing.

Source

pub fn unvirtual(self) -> StrictPath<Marker>

SUMMARY: Convert this VirtualPath back into a system‑facing StrictPath.

Source

pub fn change_marker<NewMarker>(self) -> VirtualPath<NewMarker>

SUMMARY: Change the compile-time marker while keeping the virtual and strict views in sync.

WHEN TO USE:

  • After authenticating/authorizing a user and granting them access to a virtual path
  • When escalating or downgrading permissions (e.g., ReadOnly → ReadWrite)
  • When reinterpreting a path’s domain (e.g., TempStorage → UserUploads)

WHEN NOT TO USE:

  • When converting between path types - conversions preserve markers automatically
  • When the current marker already matches your needs - no transformation needed
  • When you haven’t verified authorization - NEVER change markers without checking permissions

PARAMETERS:

  • _none_

RETURNS:

  • VirtualPath<NewMarker>: Same clamped path encoded with the new marker.

ERRORS:

  • _none_

SECURITY: This method performs no permission checks. Only elevate markers after verifying real authorization out-of-band.

EXAMPLE:

// Simulated authorization: verify user credentials before granting access
fn grant_user_access(user_token: &str, path: VirtualPath<GuestAccess>) -> Option<VirtualPath<UserAccess>> {
    if user_token == "valid-token-12345" {
        Some(path.change_marker())  // ✅ Only after token validation
    } else {
        None  // ❌ Invalid token
    }
}

let guest_path: VirtualPath<GuestAccess> = guest_root.virtual_join("docs/readme.md")?;
let user_path = grant_user_access("valid-token-12345", guest_path).expect("authorized");
assert_eq!(user_path.virtualpath_display().to_string(), "/docs/readme.md");

Type Safety Guarantee:

The following code fails to compile because you cannot pass a path with one marker type to a function expecting a different marker type. This compile-time check enforces that permission changes are explicit and cannot be bypassed accidentally.

fn require_editor(_: VirtualPath<EditorAccess>) {}
let guest_file = guest_root.virtual_join("docs/manual.txt").unwrap();
// ❌ Compile error: expected `VirtualPath<EditorAccess>`, found `VirtualPath<GuestAccess>`
require_editor(guest_file);
Source

pub fn try_into_root(self) -> Result<VirtualRoot<Marker>>

SUMMARY: Consume and return the VirtualRoot for its boundary (no directory creation).

RETURNS:

  • Result<VirtualRoot<Marker>>: Virtual root anchored at the strict path’s directory.

ERRORS:

  • StrictPathError::InvalidRestriction: Propagated from try_into_boundary when the strict path does not exist or is not a directory.
Source

pub fn try_into_root_create(self) -> Result<VirtualRoot<Marker>>

SUMMARY: Consume and return a VirtualRoot, creating the underlying directory if missing.

RETURNS:

  • Result<VirtualRoot<Marker>>: Virtual root anchored at the strict path’s directory (created if necessary).

ERRORS:

  • StrictPathError::InvalidRestriction: Propagated from try_into_boundary or directory creation failures wrapped in InvalidRestriction.
Source

pub fn as_unvirtual(&self) -> &StrictPath<Marker>

SUMMARY: Borrow the underlying system‑facing StrictPath (no allocation).

Source

pub fn interop_path(&self) -> &OsStr

SUMMARY: Return the underlying system path as &OsStr for unavoidable third-party AsRef<Path> interop.

Source

pub fn virtual_join<P: AsRef<Path>>(&self, path: P) -> Result<Self>

SUMMARY: Join a virtual path segment (virtual semantics) and re‑validate within the same restriction.

DETAILS: Applies virtual path clamping: absolute paths are interpreted relative to the virtual root, and traversal attempts are clamped to prevent escaping the boundary. This method maintains the security guarantee that all VirtualPath instances stay within their virtual root.

PARAMETERS:

  • path (impl AsRef<Path>): Path segment to join. Absolute paths are clamped to virtual root.

RETURNS:

  • Result<VirtualPath<Marker>>: New virtual path within the same restriction.

EXAMPLE:

let vroot: VirtualRoot = VirtualRoot::try_new_create(td.path())?;
let base = vroot.virtual_join("data")?;

// Absolute paths are clamped to virtual root
let abs = base.virtual_join("/etc/config")?;
assert_eq!(abs.virtualpath_display().to_string(), "/etc/config");
Source

pub fn virtualpath_parent(&self) -> Result<Option<Self>>

SUMMARY: Return the parent virtual path, or None at the virtual root.

Source

pub fn virtualpath_with_file_name<S: AsRef<OsStr>>( &self, file_name: S, ) -> Result<Self>

SUMMARY: Return a new virtual path with file name changed, preserving clamping.

Source

pub fn virtualpath_with_extension<S: AsRef<OsStr>>( &self, extension: S, ) -> Result<Self>

SUMMARY: Return a new virtual path with the extension changed, preserving clamping.

Source

pub fn virtualpath_file_name(&self) -> Option<&OsStr>

SUMMARY: Return the file name component of the virtual path, if any.

Source

pub fn virtualpath_file_stem(&self) -> Option<&OsStr>

SUMMARY: Return the file stem of the virtual path, if any.

Source

pub fn virtualpath_extension(&self) -> Option<&OsStr>

SUMMARY: Return the extension of the virtual path, if any.

Source

pub fn virtualpath_starts_with<P: AsRef<Path>>(&self, p: P) -> bool

SUMMARY: Return true if the virtual path starts with the given prefix (virtual semantics).

Source

pub fn virtualpath_ends_with<P: AsRef<Path>>(&self, p: P) -> bool

SUMMARY: Return true if the virtual path ends with the given suffix (virtual semantics).

Source

pub fn virtualpath_display(&self) -> VirtualPathDisplay<'_, Marker>

SUMMARY: Return a Display wrapper that shows a rooted virtual path (e.g., `“/a/b.txt”).

Source

pub fn exists(&self) -> bool

SUMMARY: Return true if the underlying system path exists.

Source

pub fn is_file(&self) -> bool

SUMMARY: Return true if the underlying system path is a file.

Source

pub fn is_dir(&self) -> bool

SUMMARY: Return true if the underlying system path is a directory.

Source

pub fn metadata(&self) -> Result<Metadata>

SUMMARY: Return metadata for the underlying system path.

Source

pub fn read_to_string(&self) -> Result<String>

SUMMARY: Read the file contents as String from the underlying system path.

Source

pub fn read_bytes(&self) -> Result<Vec<u8>>

👎Deprecated since 0.1.0-alpha.5: Use read() instead

Reads the file contents as raw bytes from the underlying system path.

Source

pub fn write_bytes(&self, data: &[u8]) -> Result<()>

👎Deprecated since 0.1.0-alpha.5: Use write(…) instead

Writes raw bytes to the underlying system path.

Source

pub fn write_string(&self, data: &str) -> Result<()>

👎Deprecated since 0.1.0-alpha.5: Use write(…) instead

Writes a UTF-8 string to the underlying system path.

Source

pub fn read(&self) -> Result<Vec<u8>>

SUMMARY: Read raw bytes from the underlying system path (replacement for read_bytes).

Source

pub fn read_dir(&self) -> Result<ReadDir>

SUMMARY: Read directory entries (discovery). Re‑join names with virtual_join(...) to preserve clamping.

Source

pub fn write<C: AsRef<[u8]>>(&self, contents: C) -> Result<()>

SUMMARY: Write bytes to the underlying system path. Accepts &str, String, &[u8], Vec<u8], etc.

Source

pub fn create_file(&self) -> Result<File>

SUMMARY: Create or truncate the file at this virtual path and return a writable handle.

PARAMETERS:

  • none

RETURNS:

  • std::fs::File: Writable handle scoped to the same virtual root restriction.

ERRORS:

  • std::io::Error: Propagates operating-system errors when the parent directory is missing or file creation fails.

EXAMPLE:

let report = vroot.virtual_join("reports/summary.txt")?;
report.create_parent_dir_all()?;
let mut file = report.create_file()?;
file.write_all(b"summary")?;
Source

pub fn open_file(&self) -> Result<File>

SUMMARY: Open the file at this virtual path in read-only mode.

PARAMETERS:

  • none

RETURNS:

  • std::fs::File: Read-only handle scoped to the same virtual root restriction.

ERRORS:

  • std::io::Error: Propagates operating-system errors when the file is missing or inaccessible.

EXAMPLE:

let report = vroot.virtual_join("reports/summary.txt")?;
report.create_parent_dir_all()?;
report.write("summary")?;
let mut file = report.open_file()?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
assert_eq!(contents, "summary");
Source

pub fn create_dir_all(&self) -> Result<()>

SUMMARY: Create all directories in the underlying system path if missing.

Source

pub fn create_dir(&self) -> Result<()>

SUMMARY: Create the directory at this virtual location (non‑recursive). Fails if parent missing.

Source

pub fn create_parent_dir(&self) -> Result<()>

SUMMARY: Create only the immediate parent of this virtual path (non‑recursive). Ok(()) at virtual root.

Source

pub fn create_parent_dir_all(&self) -> Result<()>

SUMMARY: Recursively create all missing directories up to the immediate parent. Ok(()) at virtual root.

Source

pub fn remove_file(&self) -> Result<()>

SUMMARY: Remove the file at the underlying system path.

Source

pub fn remove_dir(&self) -> Result<()>

SUMMARY: Remove the directory at the underlying system path.

Source

pub fn remove_dir_all(&self) -> Result<()>

SUMMARY: Recursively remove the directory and its contents at the underlying system path.

SUMMARY: Create a symlink at link_path pointing to this virtual path (same virtual root required).

DETAILS: Both self (target) and link_path must be VirtualPath instances created via virtual_join(), which ensures all paths are clamped to the virtual root. Absolute paths like "/etc/config" passed to virtual_join() are automatically clamped to vroot/etc/config, ensuring symlinks cannot escape the virtual root boundary.

EXAMPLE:

let vroot: VirtualRoot = VirtualRoot::try_new_create(td.path())?;

// Create target - absolute path "/etc/config" is clamped to vroot/etc/config
let target = vroot.virtual_join("/etc/config/app.conf")?;
target.create_parent_dir_all()?;
target.write(b"config data")?;

// Create symlink - absolute path "/var/app/link" is clamped to vroot/var/app/link
let link = vroot.virtual_join("/var/app/link.conf")?;
link.create_parent_dir_all()?;

// On Windows, symlink creation may fail without privileges - gracefully handle
if let Err(e) = target.virtual_symlink(&link) {
    // Windows ERROR_PRIVILEGE_NOT_HELD (1314) is expected without admin/dev mode
    #[cfg(windows)]
    if e.raw_os_error() == Some(1314) { return Ok(()); }
    return Err(e.into());
}

assert_eq!(link.read_to_string()?, "config data");

SUMMARY: Create a hard link at link_path pointing to this virtual path (same virtual root required).

DETAILS: Both self (target) and link_path must be VirtualPath instances created via virtual_join(), which ensures all paths are clamped to the virtual root. Absolute paths like "/etc/data" passed to virtual_join() are automatically clamped to vroot/etc/data, ensuring hard links cannot escape the virtual root boundary.

EXAMPLE:

let vroot: VirtualRoot = VirtualRoot::try_new_create(td.path())?;

// Create target - absolute path clamped to virtual root
let target = vroot.virtual_join("/shared/data.dat")?;
target.create_parent_dir_all()?;
target.write(b"shared data")?;

// Create hard link - also clamped to virtual root
let link = vroot.virtual_join("/backup/data.dat")?;
link.create_parent_dir_all()?;
target.virtual_hard_link(&link)?;

// Modify through link, verify through target (hard link behavior)
link.write(b"modified")?;
assert_eq!(target.read_to_string()?, "modified");
Source

pub fn virtual_rename<P: AsRef<Path>>(&self, dest: P) -> Result<()>

SUMMARY: Rename/move within the same virtual root. Relative destinations are siblings; absolute are clamped to root.

DETAILS: Accepts impl AsRef<Path> for the destination. Absolute paths (starting with "/") are automatically clamped to the virtual root via internal virtual_join() call, ensuring the destination cannot escape the virtual boundary. Relative paths are resolved as siblings. Parent directories are not created automatically.

PARAMETERS:

  • dest (impl AsRef<Path>): Destination path. Absolute paths like "/archive/file.txt" are clamped to vroot/archive/file.txt.

EXAMPLE:

let vroot: VirtualRoot = VirtualRoot::try_new_create(td.path())?;

let source = vroot.virtual_join("temp/file.txt")?;
source.create_parent_dir_all()?;
source.write(b"content")?;

// Absolute destination path is clamped to virtual root
let dest_dir = vroot.virtual_join("/archive")?;
dest_dir.create_dir_all()?;
source.virtual_rename("/archive/file.txt")?;

let renamed = vroot.virtual_join("/archive/file.txt")?;
assert_eq!(renamed.read_to_string()?, "content");
Source

pub fn virtual_copy<P: AsRef<Path>>(&self, dest: P) -> Result<u64>

SUMMARY: Copy within the same virtual root. Relative destinations are siblings; absolute are clamped to root.

DETAILS: Accepts impl AsRef<Path> for the destination. Absolute paths (starting with "/") are automatically clamped to the virtual root via internal virtual_join() call, ensuring the destination cannot escape the virtual boundary. Relative paths are resolved as siblings. Parent directories are not created automatically. Returns the number of bytes copied.

PARAMETERS:

  • dest (impl AsRef<Path>): Destination path. Absolute paths like "/backup/file.txt" are clamped to vroot/backup/file.txt.

RETURNS:

  • u64: Number of bytes copied.

EXAMPLE:

let vroot: VirtualRoot = VirtualRoot::try_new_create(td.path())?;

let source = vroot.virtual_join("data/source.txt")?;
source.create_parent_dir_all()?;
source.write(b"data to copy")?;

// Absolute destination path is clamped to virtual root
let dest_dir = vroot.virtual_join("/backup")?;
dest_dir.create_dir_all()?;
let bytes = source.virtual_copy("/backup/copy.txt")?;

let copied = vroot.virtual_join("/backup/copy.txt")?;
assert_eq!(copied.read_to_string()?, "data to copy");
assert_eq!(bytes, 12);

Trait Implementations§

Source§

impl<Marker: Clone> Clone for VirtualPath<Marker>

Source§

fn clone(&self) -> VirtualPath<Marker>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<Marker> Debug for VirtualPath<Marker>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<Marker> Hash for VirtualPath<Marker>

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<Marker> Ord for VirtualPath<Marker>

Source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl<Marker> PartialEq<StrictPath<Marker>> for VirtualPath<Marker>

Source§

fn eq(&self, other: &StrictPath<Marker>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: AsRef<Path>, Marker> PartialEq<T> for VirtualPath<Marker>

Source§

fn eq(&self, other: &T) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<Marker> PartialEq<VirtualPath<Marker>> for StrictPath<Marker>

Available on crate feature virtual-path only.
Source§

fn eq(&self, other: &VirtualPath<Marker>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<Marker> PartialEq for VirtualPath<Marker>

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: AsRef<Path>, Marker> PartialOrd<T> for VirtualPath<Marker>

Source§

fn partial_cmp(&self, other: &T) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl<Marker> PartialOrd for VirtualPath<Marker>

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl<Marker> Serialize for VirtualPath<Marker>

Available on crate feature serde only.
Source§

fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl<Marker> Eq for VirtualPath<Marker>

Auto Trait Implementations§

§

impl<Marker> Freeze for VirtualPath<Marker>

§

impl<Marker> RefUnwindSafe for VirtualPath<Marker>
where Marker: RefUnwindSafe,

§

impl<Marker> Send for VirtualPath<Marker>
where Marker: Send + Sync,

§

impl<Marker> Sync for VirtualPath<Marker>
where Marker: Sync + Send,

§

impl<Marker> Unpin for VirtualPath<Marker>
where Marker: Unpin,

§

impl<Marker> UnwindSafe for VirtualPath<Marker>
where Marker: UnwindSafe + RefUnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.