silk/string
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc.
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. fromBytes adopts owned bytes without copying; intoBytes transfers them back.
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 { Result }
import silk.string { String, ScalarStep, InvalidUtf8 }
import silk.usize
pub fn main() -> i32 {
let valid = String.fromUtf8(b"Silk")
|> Result.unwrapOr<string, InvalidUtf8>("")
let rejected = String.fromUtf8(b"a\x80")
|> Result.unwrapOr<string, InvalidUtf8>("")
let length = String.byteLength(valid)
|> usize.toI32
let rejectedLength = String.byteLength(rejected)
|> usize.toI32
return length + rejectedLength + 38
}Build owned text and read its first scalar
import silk.char
import silk.allocator { Allocator, OutOfMemoryError }
import silk.effect { Effect }
import silk.option { Option }
import silk.string { String, ScalarStep, InvalidUtf8 }
import silk.u32
fn scalarCode(step: ScalarStep) -> i32 {
return String.scalarValue(&step)
|> char.toU32
|> u32.toI32
}
effect fn build() -> i32
! 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<ScalarStep, i32>(move stepped, scalarCode)
let scalar = Option.unwrapOr<i32>(move mapped, 0)
return scalar - 191
}
effect fn recover(error: OutOfMemoryError) -> i32 {
return 0
}
pub fn main() -> i32 {
return run Effect.catchAll(build(), recover)
}Import as String with import silk.string { String }.
Public declarations: 4.
String
pub struct StringAn owned sequence of valid UTF-8 bytes that releases its storage on drop.
Associated function String.fromUtf8Unchecked
pub unsafe fn fromUtf8Unchecked<'life0>(values: &'life0 [u8]) -> string<'life0>Borrows 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.
Associated function String.fromUtf8
pub fn fromUtf8<'life0>(values: &'life0 [u8]) -> silk/result.Result<string<'life0>, 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.
Associated function String.make
pub fn make() -> StringConstructs an empty owned String without allocating.
Associated function String.fromBytes
pub fn fromBytes(values: Bytes) -> silk/result.Result<silk/string.String, silk/string.InvalidUtf8>Validates owned bytes and transfers their storage into a String without allocation or copying.
When to use
Use when a byte buffer must become owned text. Use fromUtf8 to borrow bytes without consuming them.
Details
This function consumes values. Invalid UTF-8 returns the first invalid byte offset and releases
the input storage. Success preserves the input allocation and its capacity.
Associated function String.fromBytesUnchecked
pub unsafe fn fromBytesUnchecked(values: Bytes) -> StringTransfers caller-validated UTF-8 storage into a String without validation, allocation, or copying.
When to use
Use when an earlier operation proves that every initialized byte forms valid UTF-8.
Use fromBytes when that guarantee is not available.
Gotchas
The complete initialized contents of values must be valid UTF-8. Invalid bytes violate the safety contract.
This function consumes values and preserves its allocation and capacity.
Method String.intoBytes
pub fn intoBytes(self: String) -> BytesConsumes the String and returns its bytes without allocation or copying.
Details
The returned bytes retain the allocation, capacity, and complete UTF-8 contents. They can be modified as arbitrary bytes after this conversion.
Associated function String.copy
pub effect<'life0> fn copy<'life0>(value: string<'life0>) -> String ! OutOfMemoryError ? &mut AllocatorCopies valid borrowed text into independently owned storage.
Associated function String.copyUtf8
pub effect<'life0> fn copyUtf8<'life0>(values: &'life0 [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.
Method String.append
pub effect<'env> fn append<'life0: 'env, 'life1: 'env, 'env>(self: &'life0 mut String, value: string<'life1>) -> () ! 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.
Method String.appendOwned
pub effect<'life0> fn appendOwned<'life0>(self: &'life0 mut 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.
Method String.view
pub fn view<'life0>(self: &'life0 String) -> string<'life0>Borrows the complete owned contents as valid text without allocating or copying.
Associated function String.utf8Bytes
pub fn utf8Bytes<'life0>(value: string<'life0>) -> &'life0 [u8]Borrows a string's immutable UTF-8 encoding.
Associated function String.byteLength
pub fn byteLength<'life0>(value: string<'life0>) -> usizeReturns a string's UTF-8 byte length.
Method String.ownedUtf8Bytes
pub fn ownedUtf8Bytes<'life0>(self: &'life0 String) -> &'life0 [u8]Borrows an owned String's immutable UTF-8 encoding.
Method String.ownedByteLength
pub fn ownedByteLength<'life0>(self: &'life0 String) -> usizeReturns an owned String's initialized UTF-8 byte length.
Associated function String.scalarCursor
pub fn scalarCursor() -> ScalarCursorCreates a cursor at UTF-8 byte offset zero, before the first Unicode scalar.
Associated function String.cursorByteOffset
pub fn cursorByteOffset<'life0>(cursor: &'life0 silk/string.ScalarCursor) -> usizeReturns a cursor's explicit UTF-8 byte offset.
Associated function String.scalarValue
pub fn scalarValue<'life0>(step: &'life0 silk/string.ScalarStep) -> charReturns the decoded Unicode scalar value without consuming the step.
Associated function String.scalarByteOffset
pub fn scalarByteOffset<'life0>(step: &'life0 silk/string.ScalarStep) -> usizeReturns the UTF-8 byte offset at which one step begins.
Associated function String.nextCursor
pub fn nextCursor(step: ScalarStep) -> ScalarCursorConsumes one scalar step and returns the cursor immediately after that scalar.
Associated function String.nextScalar
pub fn nextScalar<'life0>(value: string<'life0>, cursor: ScalarCursor) -> silk/option.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.
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.