ReadText
Collects and strictly decodes a complete UTF-8 stream. Validation occurs after EOF, so a Unicode sequence may span short reads. Invalid encoding and allocation/provider failures retain consumed bytes; no replacement decoding, newline conversion or locale behavior is introduced.
Module std.io
import std.io;Public declaration contracts and authored examples. A page can document several related symbols. Implementation bodies are excluded.
ReadText
pub fn ReadText<S>(Source: mut S&) -> Result<String, StreamReadError> where S: ReaderCollects and strictly decodes a complete UTF-8 stream. Validation occurs after EOF, so a Unicode sequence may span short reads. Invalid encoding and allocation/provider failures retain consumed bytes; no replacement decoding, newline conversion or locale behavior is introduced. S: Structural Reader source type. Source: Borrowed mutable stream, retained through completion. Return: owned immutable text or failure owning the consumed byte prefix. Warning: May allocate and block until EOF; text construction copies collected bytes.
Example
module example.stream_text;
from std.io import ReadBytes, ReadText, WriteText, IoError;
from std.prelude import Result;
class Stream {
pub Input: readonly byte[];
pub Offset: usize;
pub Written: usize;
pub FailAfterTwo: bool;
pub init(Input: readonly byte[], FailAfterTwo: bool) { this.Input = Input; this.Offset = 0; this.Written = 0; this.FailAfterTwo = FailAfterTwo; }
pub fn Read(Output: mut byte[]) -> Result<usize, IoError> {
if Output.Length == 0 || this.Offset == this.Input.Length { return .Ok { Value = 0 }; }
if this.FailAfterTwo && this.Offset == 2 { Output[0] = this.Input[this.Offset]; this.Offset += 1; return .Err { Error = .Failure { Reason = .Interrupted, Transferred = 1 } }; }
Output[0] = this.Input[this.Offset]; this.Offset += 1; return .Ok { Value = 1 };
}
pub fn Write(Input: readonly byte[]) -> Result<usize, IoError> {
if Input.Length == 0 { return .Ok { Value = 0 }; }
this.Written += 1; return .Ok { Value = 1 };
}
pub fn Flush() -> Result<void, IoError> { return .Ok; }
}
fn Main() -> i32 {
// U+03BB spans two one-byte provider reads; NUL is valid text content.
let Input: byte[4] = [0xCE_byte, 0xBB_byte, 0_byte, 0x61_byte];
var Source = Stream(Input, false);
var Text = switch ReadText(Source) { case .Ok { Value = Value } => break Value; case .Err => return 1; };
if Text.View != "λ\0a" { return 2; }
if WriteText(Source, Text.View) is .Err { Error = _ } { return 3; }
if Source.Written != 4 { return 4; }
let Invalid: byte[1] = [0xFF_byte];
var InvalidSource = Stream(Invalid, false);
// Match one enum layer at a time while preserving each original fallback.
switch ReadText(InvalidSource) {
case .Err { Error = Error } => {
if Error.Bytes.Length != 1 || Error.Bytes.At(0) != 0xFF_byte { return 5; }
switch Error.Reason {
case .Failure { Reason = PatternPayload5012, Transferred = Count } if (PatternPayload5012 is .InvalidUtf8) => { if Count != 1 { return 6; } }
default => return 7;
}
}
case .Ok => return 8;
}
var FailingSource = Stream(Input, true);
switch ReadBytes(FailingSource) {
case .Err { Error = Error } => {
if Error.Bytes.Length != 3 || Error.Bytes.At(2) != 0_byte || FailingSource.Offset != 3 { return 9; }
switch Error.Reason {
case .Failure { Reason = PatternPayload5013, Transferred = Count } if (PatternPayload5013 is .Interrupted) => { if Count != 3 { return 10; } }
default => return 11;
}
}
case .Ok => return 12;
}
return 0;
}