StrictPath

Struct StrictPath 

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

SUMMARY: Hold a validated, system-facing filesystem path guaranteed to be within a PathBoundary.

DETAILS: Use when you need system-facing I/O with safety proofs. For user-facing display and rooted virtual operations prefer VirtualPath. Operations like strict_join and strictpath_parent preserve guarantees. Display shows the real system path. String accessors are prefixed with strictpath_ to avoid confusion.

Implementations§

Source§

impl<Marker> StrictPath<Marker>

Source

pub fn with_boundary<P: AsRef<Path>>(dir_path: P) -> Result<Self>

SUMMARY: Create the base StrictPath anchored at the provided boundary directory.

PARAMETERS:

  • dir_path (AsRef<Path>): Boundary directory (must exist).

RETURNS:

  • Result<StrictPath<Marker>>: Base path (“” join) within the boundary.

ERRORS:

  • StrictPathError::InvalidRestriction: If the boundary cannot be created/validated.

NOTE: Prefer passing PathBoundary in reusable flows.

Source

pub fn with_boundary_create<P: AsRef<Path>>(dir_path: P) -> Result<Self>

SUMMARY: Create the base StrictPath, creating the boundary directory if missing.

Source

pub fn strictpath_to_string_lossy(&self) -> Cow<'_, str>

SUMMARY: Return a lossy String view of the system path. Prefer .interop_path() only for unavoidable third-party interop.

Source

pub fn strictpath_to_str(&self) -> Option<&str>

SUMMARY: Return the underlying system path as &str if valid UTF‑8; otherwise None.

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 strictpath_display(&self) -> Display<'_>

SUMMARY: Return a Display wrapper that shows the real system path.

Source

pub fn unstrict(self) -> PathBuf

SUMMARY: Consume and return the inner PathBuf (escape hatch). Prefer .interop_path() (third-party adapters only) to borrow.

Source

pub fn virtualize(self) -> VirtualPath<Marker>

SUMMARY: Convert this StrictPath into a user‑facing VirtualPath.

Source

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

SUMMARY: Change the compile-time marker while reusing the validated strict path.

WHEN TO USE:

  • After authenticating/authorizing a user and granting them access to a 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:

  • StrictPath<NewMarker>: Same boundary-checked system path encoded with the new marker.

ERRORS:

  • _none_

SECURITY: The caller MUST ensure the new marker reflects real-world permissions. This method does not perform any authorization checks.

EXAMPLE:

// Verify user can write before granting write access
fn authorize_write_access(
    user_id: &str,
    path: StrictPath<(UserFiles, ReadOnly)>
) -> Result<StrictPath<(UserFiles, ReadWrite)>, &'static str> {
    if user_id == "admin" {
        Ok(path.change_marker())  // ✅ Transform after authorization check
    } else {
        Err("insufficient permissions")  // ❌ User lacks write permission
    }
}

// Function requiring write permission - enforces type safety at compile time
fn write_log_entry(path: StrictPath<(UserFiles, ReadWrite)>, content: &str) -> io::Result<()> {
    path.write(content.as_bytes())
}

// Start with read-only access
let read_only_path: StrictPath<(UserFiles, ReadOnly)> =
    boundary.strict_join("logs/app.log")?.change_marker();

// Elevate permissions after authorization
let read_write_path = authorize_write_access("admin", read_only_path)
    .expect("user must have sufficient permissions");

// Now we can call functions requiring write access
write_log_entry(read_write_path, "Application started")?;

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.

let read_only_path: StrictPath<ReadOnly> = boundary.strict_join("logs/app.log").unwrap();
fn require_write(_: StrictPath<WritePermission>) {}
// ❌ Compile error: expected `StrictPath<WritePermission>`, found `StrictPath<ReadOnly>`
require_write(read_only_path);
Source

pub fn try_into_boundary(self) -> Result<PathBoundary<Marker>>

SUMMARY: Consume and return a new PathBoundary anchored at this strict path.

RETURNS:

  • Result<PathBoundary<Marker>>: Boundary anchored at the strict path’s system location (must already exist and be a directory).

ERRORS:

  • StrictPathError::InvalidRestriction: If the strict path does not exist or is not a directory.
Source

pub fn try_into_boundary_create(self) -> Result<PathBoundary<Marker>>

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

RETURNS:

  • Result<PathBoundary<Marker>>: Boundary anchored at the strict path’s system location (created if necessary).

ERRORS:

  • StrictPathError::InvalidRestriction: If creation or canonicalization fails.
Source

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

SUMMARY: Join a path segment and re-validate against the boundary.

NOTE: Never wrap .interop_path() in Path::new() to use Path::join() — that defeats all security. Always use this method. After .unstrict() (explicit escape hatch), you own a PathBuf and can do whatever you need.

PARAMETERS:

  • path (AsRef<Path>): Segment or absolute path to validate.

RETURNS:

  • Result<StrictPath<Marker>>: Validated path inside the boundary.

ERRORS:

  • StrictPathError::PathResolutionError, StrictPathError::PathEscapesBoundary.
Source

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

SUMMARY: Return the parent as a new StrictPath, or None at the boundary root.

Source

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

SUMMARY: Return a new path with file name changed, re‑validating against the boundary.

Source

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

SUMMARY: Return a new path with extension changed; error at the boundary root.

Source

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

Returns the file name component of the system path, if any.

Source

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

Returns the file stem of the system path, if any.

Source

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

Returns the extension of the system path, if any.

Source

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

Returns true if the system path starts with the given prefix.

Source

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

Returns true if the system path ends with the given suffix.

Source

pub fn exists(&self) -> bool

Returns true if the system path exists.

Source

pub fn is_file(&self) -> bool

Returns true if the system path is a file.

Source

pub fn is_dir(&self) -> bool

Returns true if the system path is a directory.

Source

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

Returns the metadata for the system path.

Source

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

SUMMARY: Read directory entries at this path (discovery). Re‑join names through strict/virtual APIs before I/O.

Source

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

Reads the file contents as String.

Source

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

Reads the file contents as raw bytes.

Source

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

SUMMARY: Write bytes to the file (create if missing). Accepts any AsRef<[u8]> (e.g., &str, &[u8]).

Source

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

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

PARAMETERS:

  • none

RETURNS:

  • std::fs::File: Writable handle scoped to this boundary.

ERRORS:

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

EXAMPLE:

let log_path: StrictPath = boundary.strict_join("logs/app.log")?;
log_path.create_parent_dir_all()?;
let mut file = log_path.create_file()?;
file.write_all(b"session started")?;
Source

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

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

PARAMETERS:

  • none

RETURNS:

  • std::fs::File: Read-only handle scoped to this boundary.

ERRORS:

  • std::io::Error: Propagates OS errors when the file is missing or inaccessible.

EXAMPLE:

let transcript: StrictPath = boundary.strict_join("logs/session.log")?;
transcript.create_parent_dir_all()?;
transcript.write("session start")?;
let mut file = transcript.open_file()?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
assert_eq!(contents, "session start");
Source

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

Creates all directories in the system path if missing (like std::fs::create_dir_all).

Source

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

Creates the directory at the system path (non-recursive, like std::fs::create_dir).

Fails if the parent directory does not exist. Use create_dir_all to create missing parent directories recursively.

Source

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

SUMMARY: Create only the immediate parent directory (non‑recursive). Ok(()) at the boundary root.

Source

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

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

SUMMARY: Create a symbolic link at link_path pointing to this path (same boundary required). On Windows, file vs directory symlink is selected by target metadata (or best‑effort when missing). Relative paths are resolved as siblings; absolute paths are validated against the boundary.

SUMMARY: Create a hard link at link_path pointing to this path (same boundary; caller creates parents). Relative paths are resolved as siblings; absolute paths are validated against the boundary.

Source

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

SUMMARY: Rename/move within the same boundary. Relative destinations are siblings; absolute are validated. Parents are not created automatically.

Source

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

SUMMARY: Copy within the same boundary. Relative destinations are siblings; absolute are validated. Parents are not created automatically. Returns bytes copied.

Source

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

SUMMARY: Remove the file at this path.

Source

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

SUMMARY: Remove the directory at this path.

Source

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

SUMMARY: Recursively remove the directory and its contents.

Trait Implementations§

Source§

impl<Marker: Clone> Clone for StrictPath<Marker>

Source§

fn clone(&self) -> StrictPath<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 StrictPath<Marker>

Source§

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

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

impl<Marker> Hash for StrictPath<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 StrictPath<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 StrictPath<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 StrictPath<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 StrictPath<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 StrictPath<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> Eq for StrictPath<Marker>

Auto Trait Implementations§

§

impl<Marker> Freeze for StrictPath<Marker>

§

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

§

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

§

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

§

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

§

impl<Marker> UnwindSafe for StrictPath<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.