Skip to content
dream-path

Library active

dream-path

Byte-first normalized virtual resource paths: one spelling for every asset lookup in DreamWeave and OpenMW-style tools.

cargo add dream-path
Stable
1.1.0 2026-09-30
Package
Rust crate
License
MIT OR Apache-2.0

Overview

A Morrowind plugin asks for Textures\Tx_Wood_01.DDS. The archive stores textures\tx_wood_01.dds. A mod ships TEXTURES/Tx_Wood_01.dds as a loose file, and a script asks for textures//tx_wood_01.dds. They are all the same resource, and every layer that looks one up has to agree on that, or a texture goes missing in one tool and not in another.

dream-path is where that agreement lives. It turns any spelling of a virtual resource path into one normalized byte string. An archive reader, a VFS, a renderer and a script that all normalize through it cannot disagree about a key; five slightly different normalizers would be five slightly different bugs.

Every layer asks for the same key

Archives, loose files, scripts and the renderer each receive paths spelled their own way. Normalizing them all the same way is what lets a lookup in one find what another stored.

  1. source

    Any spelling

    Textures\Tx_Wood.DDS from a plugin, textures/tx_wood.dds from an archive, //TEXTURES/tx_wood.dds from a script.

  2. tool

    dream-path

    Backslashes to slashes, ASCII to lowercase, repeated and leading separators gone. Every other byte kept.

  3. result

    One key

    textures/tx_wood.dds: the same bytes wherever the lookup happens, stored once as a NormalizedPath.

service

Archives and the VFS

dream_archive and vfstool index entries by the normalized key.

service

Luau scripts

require("@dream/path") gives scripts the same rules, byte for byte.

How the pieces relate
  • Any spelling dream-path
  • dream-path One key
  • One key index Archives and the VFS
  • One key @dream/path Luau scripts

The rules#

  • \ becomes /.
  • ASCII A to Z become lowercase.
  • Repeated separators collapse to one; leading separators are removed.
  • Every other byte is kept exactly: invalid UTF-8, non-ASCII letters, NUL, .., a trailing /.

That is all it does, on purpose. It does not decode legacy encodings, fold Unicode case, resolve .., or interpret host paths, drive letters or URIs. Normalization shows the literal consequences.

use dream_path::NormalizedPath;

let key = NormalizedPath::new(r"//Meshes\x\Ex_Door.NIF");
assert_eq!(key.as_bytes(), b"meshes/x/ex_door.nif");
assert_eq!(key.extension().unwrap(), "nif");
local dreamPath = require("@dream/path")
assert(dreamPath.normalize([[Textures\Tx_Wood_01.DDS]]) == "textures/tx_wood_01.dds")

Documentation#

  • Start here: normalize a path, store a key, look one up.
  • Guide: the rules, keys and lookups, inspecting paths, and the Luau module.
  • Rust API and Luau API: every function and type.

dream_archive and vfstool build on it. The crate has one dependency, bstr.

Install

Rust crate · 1.1.0

Add it with Cargofrom crates.io, 1.1.0 today

From your project's directory:

cargo add dream-path

Or by hand, in Cargo.toml:

[dependencies]
dream-path = "1.1.0"

Cargo reads a bare version as "this or any compatible newer release" and records the exact one in Cargo.lock.

From the repositorythe default branch, ahead of the latest release
[dependencies]
dream-path = { git = "https://github.com/DreamWeave-MP/dream_path" }

Cargo pins the commit it fetched in Cargo.lock; cargo update -p dream-path moves it forward.

  1. 1.1.0 stable 2026-09-30

    Relicensed as MIT OR Apache-2.0 and built on l3i 1.1.0.

    Changed

    • Relicensed from GPL-3.0 to MIT OR Apache-2.0: this is the first release under the new terms, and releases up to and including 1.0.0 stay GPL.
    • l3i 1.1.0 comes from crates.io; the @dream/path module is unchanged.
    dream-path 1.1.0 22.73 kB · crates.io
    View on crates.io
    Verify · sha256 b254e95d7f08…aa730ecb
    File
    dream-path-1.1.0.crate
    Size
    23274 bytes
    SHA-256
    b254e95d7f08989cb61e67c804a461ceb37e8411db5e6443159dfecdaa730ecb

    The same digest as the crates.io index's checksum, which Cargo checks on every download.

  2. 1.0.0 stable 2026-09-29

    First stable release: the Luau API is an l3i extension providing @dream/path, normalization is faster, and the Rust and Luau APIs are under semver.

    Breaking changes

    • The lua feature binds the crate as an l3i extension, lua::PathExtension, providing the module @dream/path. create_module, register_module, register_module_as and the standalone-lua feature are gone with mlua.
    • Building with the lua feature needs l3i’s toolchain: clang, lld and cross-language thin LTO.
    • Rust 1.92.

    Changed

    • An already-normalized path is copied as one block, and the rest folded without branches: a normalized 56-byte key costs 36 ns instead of 91 ns.
    • A Luau call reads its path as a borrowed view and normalizes into a per-thread buffer, allocating nothing after warm-up; calls take about half as long as with mlua.
    • The definitions check and the strict-script test build behind the luau-analysis feature (cargo test --features luau-analysis); cargo test --features lua does not build Luau’s analysis frontend.
    • l3i 1.0.0 comes from crates.io.

    Migration

    Compose dream_path::lua::PathExtension into the host’s RuntimePlan. A host that still wants the dreamPath global adds RuntimePolicy::compat_global("@dream/path", "dreamPath"). The functions and their results are unchanged.

    dream-path 1.0.0 30.27 kB · crates.io
    View on crates.io
    Verify · sha256 141f666f9371…683010de
    File
    dream-path-1.0.0.crate
    Size
    30995 bytes
    SHA-256
    141f666f9371f98d5e88a37bc388413a5acc77fae4f82d8d114e0297683010de

    The same digest as the crates.io index's checksum, which Cargo checks on every download.

  3. 0.2.0 stable 2026-09-26

    The Lua API runs on Luau, with camelCase names.

    Breaking changes

    • The Lua bindings build against mlua 0.12 and Luau. standalone-lua now selects Luau.
    • Lua functions are camelCase (fileName, isUtf8), and the module’s name is dreamPath.

    Added

    • isNormalized in Lua.
    dream-path 0.2.0 26.28 kB · crates.io
    View on crates.io
    Verify · sha256 e583db715c69…a18cac31
    File
    dream-path-0.2.0.crate
    Size
    26913 bytes
    SHA-256
    e583db715c69f57e21a9a6583a5eef99b707582dff189842a3cd595fa18cac31

    The same digest as the crates.io index's checksum, which Cargo checks on every download.

Credits