pub struct PortablePath(/* private fields */);Expand description
A retained entry’s canonical POSIX-relative name, in the form ordered pages use.
This is not the filename. It is a derived name, and it differs from the native one
whenever a component holds bytes that are not valid UTF-8, or holds a literal %.
Never open, stat, or compare a filesystem path against one of these:
EntryValue::path is the identity, and this is the wire form the ordered
projections are keyed and ordered by. The newtype exists so that mistake is a compile
error rather than a convention, because a bare String here reads exactly like a path
and every test tree an author thinks to write is pure UTF-8, so the substitution passes
locally and fails on a real disk.
Every entry has one. A native path is not obliged to be UTF-8 — Unix filenames are
arbitrary non-NUL bytes, Windows filenames may hold unpaired surrogates — so the two
kinds of byte that cannot be carried are percent-escaped: those that do not decode,
and % itself. Escaping % is what makes the mapping injective. A file named
caf%FF.txt is valid UTF-8 and a file named caf<0xFF>.txt is not; escaping only the
undecodable byte would give both the same wire name, which is the aliasing bug of
lossy conversion in better clothes.
Nothing else is touched. This produces a JSON string, not a URL, so spaces, #, ?
and every non-ASCII scalar pass through: café/naïve.txt is unchanged.
Totality is why ordered pages and native roll-ups answer over one population, why a
directory whose name has a stray byte still lists its children, and why a complete
directory that does not hold a name can answer absent rather than unknown. The
partial version that preceded it needed an omission count, bounded escaped examples,
and a second completeness flag on TreePage to describe what it could not name; all
three are gone.
Distinct from the unrelated structural question of whether a path is relative and never ascends. A path can satisfy either condition and fail the other.