std::tstring (v0.2.1)
Owned null-terminated strings with byte operations, UTF-8 validation, and Unicode code point helpers.
Overview
The std::tstring module provides TString, an owned string type implemented with std::collections::vector. It stores bytes as char values and keeps a trailing null terminator so the buffer can be exposed as a CString when needed.
Use TString when code needs a mutable string-like buffer with explicit lifetime management. The module covers construction from C strings, copying, concatenation, trimming, prefix and suffix checks, ASCII case conversion, and UTF-8 validation.
The API is still low-level. TString owns its vector allocation, so callers must destroy values they create when the string is no longer needed. Operations that return a new TString also return ownership to the caller.
Source: thrustc/std/v0.2.1/tstring.thrust
Public Signatures
Exported declarations for this module snapshot.
type UnicodeCodePoint @public = u32;
struct TString @public {
fn newTString() TString @public;
fn withCapacity(capacity: usize) TString @public;
fn fromCString(text: CString) TString @public;
fn copy(text: ptr[TString]) TString @public;
fn toCString(text: ptr[TString]) CString @public;
fn destroyTString(text: ptr[TString]) void @public;
fn len(text: ptr[TString]) usize @public;
fn unicodeCodePointCount(text: ptr[TString]) usize @public;
fn isEmpty(text: ptr[TString]) bool @public;
fn hasIndex(text: ptr[TString], index: usize) bool @public;
fn get(text: ptr[TString], index: usize) char @public;
fn capacity(text: ptr[TString]) usize @public;
fn clear(text: ptr[TString]) void @public;
fn reserve(text: ptr[TString], requestedCapacity: usize) void @public;
fn appendCString(text: ptr[TString], value: CString) void @public;
fn appendTString(text: ptr[TString], value: ptr[TString]) void @public;
fn concat(left: ptr[TString], right: ptr[TString]) TString @public;
fn trim(text: ptr[TString]) TString @public;
fn trimStart(text: ptr[TString]) TString @public;
fn trimEnd(text: ptr[TString]) TString @public;
fn startsWith(text: ptr[TString], prefix: CString) bool @public;
fn endsWith(text: ptr[TString], suffix: CString) bool @public;
fn contains(text: ptr[TString], value: CString) bool @public;
fn indexOf(text: ptr[TString], value: CString) usize @public;
fn equals(left: ptr[TString], right: ptr[TString]) bool @public;
fn toUpperCaseASCII(text: ptr[TString]) TString @public;
fn toLowerCaseASCII(text: ptr[TString]) TString @public;
fn isValidUTF8(text: CString) bool @public;
fn isCharBoundary(text: ptr[TString], index: usize) bool @public;
fn decodeNext(text: ptr[TString], index: usize, outCodePoint: ptr[UnicodeCodePoint]) usize @public;
fn pushUnicodeCodePoint(text: ptr[TString], codePoint: UnicodeCodePoint) bool @public;
Behavior and Use
len returns the byte length without the trailing null terminator, while capacity reports usable byte capacity without counting that terminator.
toCString returns a pointer to the internal null-terminated buffer. Treat that pointer as borrowed from the TString and avoid using it after the TString is destroyed or mutated.
get, hasIndex, and indexOf use byte indexes. get returns '\0' when the index is outside the string, and indexOf returns len(text) when the value is not found.
UTF-8 helpers also operate on byte indexes. isCharBoundary can be used before slicing-style logic, and decodeNext advances from one code point boundary to the next.
ASCII case conversion only changes bytes in the A-Z or a-z ranges. It does not perform locale-aware or full Unicode casing.
Examples
import std::tstring;
import std::io;
fn main() s32 @public {
var text := tstring::fromCString("thrust");
tstring::appendCString(ref text, " language");
io::print("%s\n", tstring::toCString(ref text));
tstring::destroyTString(ref text);
return 0;
}
import std::tstring;
fn main() s32 @public {
var left := tstring::fromCString("hello");
var right := tstring::fromCString(" world");
var joined := tstring::concat(ref left, ref right);
var ok: bool = tstring::startsWith(ref joined, "hello") &&
tstring::endsWith(ref joined, "world");
tstring::destroyTString(ref joined);
tstring::destroyTString(ref right);
tstring::destroyTString(ref left);
if ok {
return 0;
}
return 1;
}
import std::tstring;
fn main() s32 @public {
var text := tstring::fromCString(" data ");
var trimmed := tstring::trim(ref text);
var upper := tstring::toUpperCaseASCII(ref trimmed);
var expected := tstring::fromCString("DATA");
var ok: bool = tstring::isValidUTF8(tstring::toCString(ref upper)) &&
tstring::equals(ref upper, ref expected);
tstring::destroyTString(ref expected);
tstring::destroyTString(ref upper);
tstring::destroyTString(ref trimmed);
tstring::destroyTString(ref text);
if ok {
return 0;
}
return 1;
}
import std::tstring;
fn main() s32 @public {
var text := tstring::newTString();
var ok: bool = tstring::pushUnicodeCodePoint(ref text, 0x41);
tstring::destroyTString(ref text);
if ok {
return 0;
}
return 1;
}
import std::tstring;
fn main() s32 @public {
var text := tstring::fromCString("hello");
if !tstring::hasIndex(ref text, 4) {
return 1;
}
if tstring::get(ref text, 1) != 'e' {
return 2;
}
if tstring::indexOf(ref text, "lo") != 3 {
return 3;
}
tstring::destroyTString(ref text);
return 0;
}
Notes
- TString values own heap storage through their internal vector. Call destroyTString for every live TString when ownership ends.
- Pointers returned by toCString are invalidated by destruction and may be affected by later mutations or reallocations.
- Lengths and indexes are byte-based, not Unicode scalar counts. Use unicodeCodePointCount when you need the decoded code point count.
- Use hasIndex before get when '\0' is also a valid value in the data you are inspecting.
- Invalid UTF-8 decoding stops at the invalid byte and returns the current index from decodeNextData through the public decodeNext wrapper.