silk/string
Valid UTF-8 text, including owned storage, byte validation, and scalar-by-scalar traversal.
When to use
Use the built-in string type for borrowed text and String when text must own its storage.
Use Bytes when arbitrary octets must survive without UTF-8 validation.
Details
fromUtf8 validates and borrows existing bytes without allocating; copyUtf8 validates and
owns a copy. append and appendOwned leave the original value unchanged if growth cannot
allocate. Scalar cursors expose Unicode scalar values and byte offsets, not grapheme clusters.
Gotchas
A ScalarCursor is meaningful only for the same unchanged string from which its traversal
began. Start with scalarCursor and advance only with nextCursor.
Examples
Validate borrowed UTF-8 bytes
import silk.result as Result
import silk.string as String
import silk.usize as usize
pub fn main() -> i32 {
let valid = String.fromUtf8(b"Silk")
|> Result.unwrapOr<string, String.InvalidUtf8>("")
let invalid = String.fromUtf8(b"a\x80")
if !Result.isFailure<string, String.InvalidUtf8>(&invalid) {
return 0
}
let length = String.byteLength(valid)
|> usize.toI32
return length + 38
}Build owned text and read its first scalar
import silk.char as char
import silk.allocator { Allocator }
import silk.effect { Effect }
import silk.option as Option
import silk.string as String
import silk.u32 as u32
fn scalarCode(step: String.ScalarStep) -> i32 {
return String.scalarValue(&step)
|> char.toU32
|> u32.toI32
}
effect fn build() -> i32
! Allocator.OutOfMemoryError {
let mut allocator = Allocator.systemAllocatorProvider()
let copying = String.copy("é")
|> Effect.provideMut<Allocator>(&mut allocator)
let mut text = run copying
let appending = String.append(&mut text, "!")
|> Effect.provideMut<Allocator>(&mut allocator)
let appended = run appending
let stepped = String.nextScalar(String.view(&text), String.scalarCursor())
let mapped = Option.map<String.ScalarStep, i32>(move stepped, scalarCode)
let scalar = Option.unwrapOr<i32>(move mapped, 0)
return scalar - 191
}
effect fn recover(error: Allocator.OutOfMemoryError) -> i32 {
return 0
}
pub fn main() -> i32 {
return run Effect.catchAll(build(), recover)
}Import as String with import silk.string.
Public declarations: 22.
String
pub struct StringAn owned sequence of valid UTF-8 bytes that releases its storage on drop.
InvalidUtf8
pub struct InvalidUtf8The first byte offset at which UTF-8 validation failed.
Field offset
pub offset: usizeThe zero-based offset of the first byte that cannot continue a valid UTF-8 sequence.
ScalarCursor
pub struct ScalarCursorAn opaque UTF-8 position used for scalar-by-scalar traversal.
ScalarStep
pub struct ScalarStepOne decoded Unicode scalar, its byte offset, and the cursor after it.
fromUtf8Unchecked
pub unsafe fn fromUtf8Unchecked(values: &[u8]) -> stringBorrows caller-validated UTF-8 bytes as text without runtime validation.
When to use
Use this function only when an earlier operation proves that the complete byte view is UTF-8.
Use fromUtf8 when the bytes have not been validated.
Gotchas
The caller must guarantee that the complete byte view is valid UTF-8 for the lifetime of the returned string view. Invalid bytes violate the safety contract.
fromUtf8
pub fn fromUtf8(values: &[u8]) -> silk/result.Result<string, silk/string.InvalidUtf8>Validates a complete byte view and borrows it as text without allocating.
Details
Success returns a string view with the same lexical lifetime as values. Failure returns the
first invalid byte offset in InvalidUtf8.
make
pub fn make() -> StringConstructs an empty owned String without allocating.
copy
pub effect fn copy(value: string) -> String ! OutOfMemoryError ? &mut AllocatorCopies valid borrowed text into independently owned storage.
copyUtf8
pub effect fn copyUtf8(values: &[u8]) -> silk/result.Result<silk/string.String, silk/string.InvalidUtf8> ! OutOfMemoryError ? &mut AllocatorValidates complete UTF-8 bytes and copies them into independently owned storage.
When to use
Use this function when the bytes must outlive their current buffer. Use fromUtf8 for a
borrowed result without allocation.
Details
Invalid input returns InvalidUtf8 as ordinary result data. Allocation failure remains in the
Effect failure channel. No owned string is returned in either failure case.
append
pub effect fn append(self: &mut silk/string.String, value: string) -> () ! OutOfMemoryError ? &mut AllocatorAppends complete valid text atomically with respect to allocation failure.
When to use
Use this function for borrowed text. Use appendOwned when the suffix is an owned String.
Details
If growth fails, self keeps its prior contents and byte length.
appendOwned
pub effect fn appendOwned(self: &mut silk/string.String, value: String) -> () ! OutOfMemoryError ? &mut AllocatorAppends another owned String atomically with respect to allocation failure.
When to use
Use this function to consume an owned suffix. Use append when the suffix is borrowed text.
Details
This function consumes value. If growth fails, self keeps its prior contents and byte length.
view
pub fn view(self: &silk/string.String) -> stringBorrows the complete owned contents as valid text without allocating or copying.
utf8Bytes
pub fn utf8Bytes(value: string) -> &[u8]Borrows a string's immutable UTF-8 encoding.
byteLength
pub fn byteLength(value: string) -> usizeReturns a string's UTF-8 byte length.
ownedUtf8Bytes
pub fn ownedUtf8Bytes(self: &silk/string.String) -> &[u8]Borrows an owned String's immutable UTF-8 encoding.
ownedByteLength
pub fn ownedByteLength(self: &silk/string.String) -> usizeReturns an owned String's initialized UTF-8 byte length.
scalarCursor
pub fn scalarCursor() -> ScalarCursorCreates a cursor at UTF-8 byte offset zero, before the first Unicode scalar.
cursorByteOffset
pub fn cursorByteOffset(cursor: &silk/string.ScalarCursor) -> usizeReturns a cursor's explicit UTF-8 byte offset.
scalarValue
pub fn scalarValue(step: &silk/string.ScalarStep) -> charReturns the decoded Unicode scalar value without consuming the step.
scalarByteOffset
pub fn scalarByteOffset(step: &silk/string.ScalarStep) -> usizeReturns the UTF-8 byte offset at which one step begins.
nextCursor
pub fn nextCursor(step: ScalarStep) -> ScalarCursorConsumes one scalar step and returns the cursor immediately after that scalar.
nextScalar
pub fn nextScalar(value: string, cursor: ScalarCursor) -> Option<silk/string.ScalarStep>Decodes the scalar at a cursor, or returns None at the end of the string.
Details
A present step contains the scalar, its starting byte offset, and the next cursor. This function does not allocate.
Gotchas
The cursor must come from scalarCursor or nextCursor for the same unchanged string.