Expand description
OsString-shaped strings with native, conversion-free u16 storage.
Rust’s OsString stores WTF-8 on Windows, so every
call into a wide (*W) Win32 API pays a WTF-8 -> UTF-16 re-encode and an
allocation on the way out, and the reverse on the way in. For code that lives
in u16 and calls Windows APIs repeatedly, that conversion is pure overhead.
This crate provides an OsString-shaped type whose canonical storage is
[u16] (WTF-16: arbitrary, ill-formed-surrogate-tolerant UTF-16, exactly
what NTFS and the Win32 APIs traffic in), so the conversion happens once at
the boundary from str/OsStr and never again. The analog of
OsStrExt::encode_wide becomes a zero-copy borrow of our own slice.
§Shape
The core is generic over a code-unit encoding: WtfString<E>
owns the units and WtfStr<E> is the borrowed slice. Two encodings ship: the
Wtf16 width (aliases Wtf16String / Wtf16Str) and the Wtf8 width
(aliases Wtf8String / Wtf8Str), a u8/WTF-8 storage variant whose
encode/decode, comparison, and formatting semantics this crate defines, backed
by a crate-owned Vec<u8> (its WTF-8 storage matches OsString’s, but the arm
is not built on OsString).
The storage and str/String conversions are portable; the OsStr /
OsString interop is Windows-only.
use wtf_string::Wtf16String;
// Encode once, at the boundary.
let s = Wtf16String::from("C:\\Windows");
// From here on the units are the storage: no re-encode, no allocation.
assert_eq!(s.len(), 10);
assert_eq!(s.as_units()[0], u16::from(b'C'));
// And back again when a `String` is genuinely wanted.
assert_eq!(s.to_string_lossy(), "C:\\Windows");§Conversion costs
The point of the crate is that the middle rows are free. Everything that costs anything is a boundary crossing you asked for:
| Operation | Cost |
|---|---|
Wtf16String::from(&str) / from(String) | encode + allocate, once |
Wtf16String::from_os_str (Windows) | encode + allocate, once |
as_ptr + len, for a counted *W call | free |
as_terminated_ptr, for an LPCWSTR call | free |
encode_wide (Windows), the OsStrExt analog | free (borrows our slice) |
as_units / len / comparison / hashing | free |
to_string_checked / to_string_lossy | decode + allocate |
to_os_string (Windows) | re-encode + allocate |
Compare OsString, where the first two rows are free and the wide-call
rows are the ones that re-encode. The two types are mirror images; which one
is right depends on whether your code spends its time in str or in Win32.
§The FFI surface
Both directions of a Win32 call are covered without leaving u16.
Input – pick the convention the signature wants:
- counted (
ptr+cch):as_ptrwithlen; - NUL-terminated (
LPCWSTR/PCWSTR):as_terminated_ptr. The terminator is always present in the owned buffer, so this never allocates.
Output – pick the shape the API uses:
- caller-allocated buffer-fill:
with_capacity,as_mut_ptr, thenset_len_from_ffito publish the content length the API reported; - callee-allocated buffer:
from_wide_ptr, which copies, leaving the caller to free the original.
See examples/win32_round_trip.rs for both halves against a real Win32 call.
§Interior NULs
Content may contain NUL, matching OsString and the underlying WTF model.
The trailing terminator is storage, not content: it is excluded from
len, as_units, comparison and hashing.
One consequence is worth knowing before using the terminated pointer: a C
string ends at the first NUL, so a callee reading
as_terminated_ptr sees a value with an
interior NUL truncated. Counted access is always exact.
has_interior_nul reports the condition when it
matters.
A checked, no-interior-NUL companion type – one that makes “this really is a
valid C string” a type-level guarantee rather than a precondition to check –
is a reserved seam for a future release, deliberately outside the v1
surface. Until then, pair has_interior_nul with the terminated pointer, or
use the counted pair, which is never ambiguous.
§Features
std(on by default) – adds the WindowsOsStr/OsStringinterop.OsStrlives instdand has noalloc-only equivalent, so it is the one part of the crate that needs it. With this feature off the crate isno_std+alloc: storage,str/Stringconversions, the mutation surface and the whole FFI pointer surface all still work.windows-core(off by default) – implements the high-levelwindowscrate’sParam<PCWSTR>for&Wtf16String, so awindowsAPI takingimpl Param<PCWSTR>accepts our type directly, handing over the already-terminated pointer with no conversion, allocation or copy. Rawwindows-syssignatures need no feature: they take*const u16, whichWtf16String::as_terminated_ptralready provides. The impl is written against onewindows-coreversion, so a caller must resolve to that same semver-compatible version for it to apply.
The crate is #![no_std] at its root and pulls in alloc. Unless the
windows-core feature is on, it has zero dependencies.
See the crate’s design records for the full set of decisions.
Structs§
- WtfStr
- A borrowed string slice of code units in encoding
E(the analog ofOsStr/str). - WtfString
- An owned, growable string of code units in encoding
E(the analog ofOsString/String).
Enums§
- Wtf8
- The WTF-8 encoding: arbitrary, ill-formed-tolerant WTF-8 stored as
u8code units – the byte representation a WindowsOsStruses. - Wtf16
- The WTF-16 encoding: arbitrary, ill-formed-surrogate-tolerant UTF-16 stored as
u16code units.
Traits§
- WtfEncoding
- A code-unit encoding for a
WtfString/WtfStr.
Type Aliases§
- Wtf8Str
- A
WtfStrwhose storage is WTF-8 (u8code units). - Wtf8
String - A
WtfStringwhose storage is WTF-8 (u8code units). - Wtf16
Str - A
WtfStrwhose storage is WTF-16 (u16code units). - Wtf16
String - A
WtfStringwhose storage is WTF-16 (u16code units).