Text v0.1.0
Strings and fundamental text manipulation
Installation
Add Text to the [Dependencies] table of your package's Rux.toml:
[Dependencies]
Text = { Namespace = "Rux", Version = "0.1.0" }
Standard packages are declared by hand: the registry does not serve them, so rux add Rux/Text cannot add them.
Dependencies
Guide
What it provides
StringView— a borrowed run of bytes checked once to be UTF-8, so everything downstream may assume text and be right. Byte-indexed; a cut off a character boundary is refused rather than rounded. Search, trim, split and the walk over lines live here, since they answer questions about bytes that already exist and allocate nothing.String— immutable text with value semantics. Language copies allocate an independent block from the same allocator;Clonereports allocation failure when it must be handled explicitly.StringBuilder— where text is assembled. Keeps spare room and doubles it, holds well-formed UTF-8 at every moment, and hands its block over throughIntoStringwithout copying it. Copying is prohibited.- UTF-8 — validation, decoding and encoding by Table 3-7 of the Unicode standard, so overlong forms, surrogate halves and values past U+10FFFF are refused structurally.
Encodereturnsuint ! Utf8Error,DecodeAtreturns aDecodedScalar(the scalar and its width)! Utf8Error, andValidatereturns! Utf8Failure, which says where the bytes stopped being UTF-8 as well as why. CString— move-only, NUL-checked interop with C: text holding a zero byte is refused rather than truncated on the way out, and bytes from C are bounded and validated on the way in.- Transforms —
Concat,Join,Repeat,Replace, the ASCII-only case conversions, andToUpper,ToLowerandFoldCaseby Unicode's full, unconditional mappings fromRux/Unicode. - The presentation contracts —
DisplayandDebugare what a value implements to describe itself,TextWriteris where the text goes, andFormatSpecis what a placeholder asked for. They live here rather than inRux/Formatso that a package can describe its own values without depending on the numeric conversion engine:Time,UuidandPathall implement them and none of them needs to know how a float is rounded.WriteAlignedapplies a spec's width, fill and alignment, which is the one part every type applies the same way, to text already rendered;WriteDisplayAlignedapplies them around a value that writes its text in pieces, as dates and identifiers do. - Text presents itself —
StringandStringViewimplementDisplayas their own characters andDebugas those characters quoted and escaped. What is escaped is narrow on purpose: the quote and the backslash, which collide with the quoting, and the C0 and C1 controls, which act on a terminal instead of being read. All ordinary non-ASCII text is left alone, because escaping it would make most of the world's scripts unreadable in the one place a reader is trying to read them. BufferWriter— a fixed buffer that holds text at every moment. Every write is validated as UTF-8 before any of it lands, and a write that does not fit lands not at all, so what has been written is always the concatenation of the runs that succeeded. That second promise is what makes the buffer usable after a failure: a caller who runs out of room writes the same run somewhere larger without first working out how much of it went in.FormatSpecandParseFormatSpec— what a placeholder asked for, parsed once by the grammar[[fill]align][+][#][0][width][.precision][style]. A style is an identifier, soxandiso8601parse by the same rule; the parser recognizes syntax and the value decides whether the style means anything, refusing what it does not support withUnsupportedRequest. An integer understands the basesb,o,xandX, and renders a negative value in any of them as a minus sign and the magnitude rather than as two's-complement bits:{:b}of-5is-101. A float understandseandE, which ask for scientific notation. A malformed specification reports the byte offset where parsing stopped.- Errors describe themselves —
TextError,TextFailureKind,FormatErrorandUtf8ErrorimplementDisplayandDebug, and so doAllocErrorandPageError, which surface throughTextErrorand whose owning packages do not depend on this one.Displayis the stable description a reader is shown, short enough to sit inside a sentence a program is already writing;Debugnames the case and its payload, soFormatError::InvalidSpecification(12)says where. The descriptions are stable and are not a parsing contract: a program branches on the case, not the words.EntropyErroris deliberately absent — presenting it would need a dependency edge the layering forbids in both directions — and callers handle its cases or wrap it in a diagnostic type of their own. - Outcomes and runs show what is inside them —
WriteOptionalDebug,WriteFallibleDebugandWriteSliceDebugwrite an optionalT?asSome(value)ornone, a fallibleT ! EasSuccess(value)orFailure(reason), and a run of elements as[first, second, third]. None of the three can be an interface implementation, because native forms implement no interface and what aT?looks like is entirely a question aboutT; they are handwritten functions carrying the bound, resolved at each instantiation with nothing dispatched at run time. They borrow, which is the point:??and?consume the optional because taking a payload out is a transfer of ownership, while showing one is not, so an optional holding a move-only value can be written as often as wanted and still holds it. The specification reaches the elements unchanged; the brackets, commas and case names are punctuation and are never padded. Sequential containers areRux/Collections' own writers, built onWriteSliceDebug. FormatError— why a value could not be turned into text, with no case for success.TextErrornext door is the same shape for this package's storage and validation operations, which returnT ! TextError;FromTextErroris the one sanctioned crossing between the two, used as a mapper:builder.Append(view)? else (e => FromTextError(e)).
Example
import Allocator::{ Allocator, SystemAllocator };
import Io::PrintLine;
import Text::{ String, TextError };
func Main() -> ! TextError {
var system = SystemAllocator();
let allocator: Allocator = system;
let greeting = String::FromBytes(allocator, "Hello")?;
PrintLine(greeting);
}
Use String(allocator), StringBuilder(allocator), and StringView() for empty values. Move builders and C strings explicitly with <-. Ordinary String copy syntax is infallible and terminates on allocation failure; use Clone(), which returns String ! TextError, in recoverable paths.
Index
Interfaces
| Name | Summary |
|---|---|
Display | The text a value has for a reader. |
Debug | The text a value has for whoever is inspecting a program. |
ParseFailure | A parsing failure that can say where it happened. |
TextWriter | Somewhere formatted text can be written. |
Types
| Name | Summary |
|---|---|
BufferWriter | A fixed buffer being filled with text from the front. |
CString | Text carrying the terminator C expects, in storage of its own. |
TextFailureKind | The ways text handling fails, with no case for success. |
FormatError | Why a formatting operation did not produce the text it was asked for. |
SplitIterator | A walk over the parts of a view between occurrences of a separator. |
LineIterator | A walk over the lines of a view, each without its line break. |
FormatAlign | Where the padding goes when the rendering is narrower than the width. |
FormatBase | The base an integer renders in. |
FormatSpec | Everything a placeholder asked for. |
String | Text that owns its bytes. |
StringBuilder | A growable buffer of text. |
StringView | A borrowed run of bytes that has been checked to be UTF-8. |
ScalarIterator | A walk over the scalar values of a view, first to last. |
TextError | What went wrong. |
Utf8Error | What was wrong with a byte sequence. |
DecodedScalar | One scalar value decoded from UTF-8, with the number of bytes it occupied. |
Utf8Failure | Where and why a byte sequence stopped being well-formed UTF-8. |
Functions
| Name | Summary |
|---|---|
PaddingAround | How many fill characters go on each side of a rendering that occupies occupied scalars. |
WriteFill | Writes count copies of the spec's fill byte. |
WriteAligned | Writes rendered into writer under spec's width, fill and alignment. |
WriteDisplayAligned | Writes value's text under spec, applying the spec's width, fill and alignment around the text the value writes itself. |
WriteValue | Writes value under spec through its Display implementation. |
WriteDebugValue | Writes value under spec through its Debug implementation. |
TextFailureOf | The failure-only kind corresponding to error. |
FromTextError | error translated across the boundary between this package's status convention and the formatting protocol. |
WriteEscaped | Writes text with the characters that would be ambiguous or invisible replaced by escapes. |
IsAsciiSpace | Whether byte is ASCII whitespace: space, tab, newline, carriage return, form feed or vertical tab. |
ParseFormatSpec | Parses the text between {: and }. |
RejectStyle | Refuses a specification that names any style. |
RejectNonBaseStyle | Refuses a specification whose style is not one of the integer bases. |
WriteOptionalDebug<T> | Writes a borrowed optional as Some(value) or none. |
WriteFallibleDebug<T, E> | Writes a borrowed fallible as Success(value) or Failure(reason). |
WriteSliceDebug<T> | Writes a borrowed run of elements as [first, second, third]. |
FromAllocError | The text error an allocator's failure becomes. |
Join | The text of every part of parts in order, with separator between each two. |
ToUpper | The text of view in upper case by Unicode's full, unconditional mappings, so ß becomes SS and ʼn becomes ʼN. |
ToLower | The text of view in lower case by Unicode's full, unconditional mappings. |
FoldCase | The text of view case-folded by Unicode's full folding, the form for comparing text without regard to case: two texts that differ only in case fold to the same bytes, Straße and STRASSE included. |
Concat | The text of left followed by the text of right. |
Repeat | The text of view written count times. |
Replace | The text of view with every occurrence of needle replaced by replacement. |
IsAsciiLetter | Whether byte is an ASCII letter. |
ToAsciiUpper | The text of view with every ASCII lower-case letter raised, and everything else left alone. |
ToAsciiLower | The text of view with every ASCII upper-case letter lowered. |
IsScalarValue | Whether value is a Unicode scalar value: at most MaxScalarValue, and not a surrogate half. |
EncodedLength | How many bytes scalar takes in UTF-8, or zero when it is not a scalar value. |
IsContinuation | Whether byte is a continuation byte, the 10xxxxxx shape every byte after a leading one has. |
Encode | Writes scalar into into as UTF-8 and reports how many bytes it took. |
DecodeAt | Decodes the scalar value starting at index, reporting it and how many bytes it occupied. |
Validate | Whether bytes is well-formed UTF-8 from end to end, reporting where it first is not. |
IsBoundary | Whether index is where a scalar value starts, and so a place a string may be cut. |
CountScalars | How many scalar values bytes holds, assuming it is well-formed. |
BoundaryAtOrBelow | The index of the scalar boundary at or below index. |
WriteBytes | Writes bytes to writer. |
WriteAscii | Writes one ASCII byte. |
WriteScalar | Writes one character, encoded as UTF-8. |
Constants
| Name | Summary |
|---|---|
MinimumBuilderCapacity | The room a builder takes when it first needs any. |
MaxScalarValue | The largest Unicode scalar value. |
FirstSurrogate | The first value of the surrogate range, which holds no scalar values. |
LastSurrogate | The last value of the surrogate range. |
MaxEncodedLength | The most bytes any one scalar value takes in UTF-8. |