Under heavy development. This site describes the intended 1.0 language. Current features and performance vary. Development status
Sn50SnThe SnAPI programming language
0.2.0 Preview 1 · Frozen documentation

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.

Sn is under heavy development. Reference extracted from this release’s bundled standard library. Public API examples are not an exhaustive compatibility test. Read the matching release guide for tested workflows and limitations. Read the status →

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: Reader

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. 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;
}
Documentation snapshot: October 24, 2026 About versions ↗
Searching Development · language & standard library