silk.schema.yaml.

Read and write Schema types as YAML.

When to use#

Call SchemaYaml.decode to read a value of a silk.schema.schema.Schema type from YAML text, such as a configuration file, SchemaYaml.decodeAll to report every problem in the text at once, and SchemaYaml.encode to write a value as YAML to the ambient Writer. Show the problems with silk.schema.report.SchemaReport. Use silk.yaml.document.YamlDocument to work with YAML whose shape is not known in advance.

Details#

Decoding parses the text into a YamlDocument first, then reads the value from it, so members may come in any order. Members the type does not name are skipped, or reported when its spec is Spec.strict. Every problem carries the span of the bytes it is about. A field that holds text also accepts a plain scalar that YAML reads as another kind, such as version: 1.10 or zip: 01234, and gets its text exactly as written. Encoding writes block-style YAML, with struct fields in declaration order.

Examples#

Read a configuration file#

silk
import silk.collections.list { List }
import silk.core.effect { Effect }
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.schema.issue { SchemaError }
import silk.schema.schema { Schema }
import silk.schema.yaml { SchemaYaml }
import silk.text.string { String }

struct Service {
  pub name: String,
  pub version: String,
  pub ports: List<u16>,
}

impl Schema for Service {}

effect fn load() -> i32 ! SchemaError | OutOfMemoryError ? &mut Allocator {
  let api = run SchemaYaml.decode<Service>(b"name: api\nversion: 1.10\nports: [80, 443]\n")
  if api.name.view() != "api" || api.version.view() != "1.10" || List<u16>.get(&api.ports, 1) != 443 {
    return 1
  }
  return 0
}

pub effect fn main() -> i32 ! SchemaError | OutOfMemoryError {
  let mut allocator = Allocator.systemAllocatorProvider()
  return run load() |> Effect.provideMut<Allocator>(&mut allocator)
}

Import as SchemaYaml with import silk.schema.yaml { SchemaYaml }.

Public declarations: 3.

SchemaYaml#

silk
pub struct SchemaYaml

The owner of the YAML entry points. It has no fields and is never constructed.

Implementation SchemaYaml#

silk
impl SchemaYaml

Associated function decode#

silk
pub effect fn decode<T: Schema>(bytes: &[u8]) -> T ! SchemaError | OutOfMemoryError ? &mut Allocator

Reads one value of type T from the YAML text bytes, stopping at the first problem.

Details#

The text must hold one YAML document. A text field also accepts a plain scalar that YAML reads as a number, a boolean, or null, and gets the text as written.

Errors#

  • SchemaError if the text is not valid YAML, holds more than one document, or does not hold a T. Its path names the part that failed, and its issue has the span of the bytes it is about. Invalid YAML gives IssueReason.InvalidSyntax.

  • OutOfMemoryError if the Allocator cannot supply the document or the value.

Associated function decodeAll#

silk
pub effect fn decodeAll<T: Schema>(bytes: &[u8]) -> T ! SchemaErrors | OutOfMemoryError ? &mut Allocator

Reads one value of type T from the YAML text bytes, reporting every problem.

Details#

A field, element or variant that fails is recorded and skipped, and reading goes on with the next one, so one call lists every problem, in input order: a missing key, a wrong type, a number out of range and a failed rule alike. Text that is not valid YAML is the one problem reported. At most MAX_PROBLEMS (64) are listed.

Errors#

  • SchemaErrors with every problem found.

  • OutOfMemoryError if the Allocator cannot supply the document or the value.

Associated function encode#

silk
pub effect fn encode<T: Schema>(value: &T)
    -> () ! SchemaError | WriterError | OutOfMemoryError ? &mut Writer | &mut Allocator

Writes value as block-style YAML to the ambient Writer.

Details#

Struct fields are written in declaration order, nested collections are indented by two spaces, and strings are quoted only when a reader would read them as something else. The text goes to the Writer in pieces of up to 4 KiB. It does not flush the Writer.

Errors#

  • SchemaError if the value nests more than 128 levels deep. Its path is empty.

  • WriterError if the Writer fails. Bytes that it accepted before the failure stay written.

  • OutOfMemoryError if a codec needs memory that the Allocator cannot supply.

Examples#

silk
import silk.collections.slice { Slice }
import silk.core.effect { Effect }
import silk.io.writer { Writer, WriterError }
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.schema.issue { SchemaError }
import silk.schema.schema { Schema }
import silk.schema.yaml { SchemaYaml }

struct Limits {
  pub retries: u8,
}

impl Schema for Limits {}

struct Server {
  pub port: u16,
  pub limits: Limits,
}

impl Schema for Server {}

struct Capture {
  bytes: [u8; 64],
  length: usize,
}

impl Writer for Capture {
  effect fn writeAll(self: &mut Self, val: &[u8]) -> () ! WriterError ? &mut Writer {
    Slice.copyInto<u8>(&mut self.bytes, self.length, val)
    self.length = self.length + val.length
    return ()
  }
  effect fn flush(self: &mut Self) -> () ! WriterError ? &mut Writer { return () }
}

pub effect fn main() -> i32 ! SchemaError | WriterError | OutOfMemoryError {
  let mut allocator = Allocator.systemAllocatorProvider()
  let mut capture = Capture {bytes: [0; 64], length: 0}
  let server = Server {port: 8080, limits: Limits {retries: 3}}
  run SchemaYaml.encode<Server>(&server) |> Effect.provideMut<Writer>(&mut capture)
    |> Effect.provideMut<Allocator>(&mut allocator)
  if Slice.view<u8>(&capture.bytes, 0, capture.length) != b"port: 8080\nlimits:\n  retries: 3\n" {
    return 1
  }
  return 0
}

YamlSchemaReader#

silk
pub struct YamlSchemaReader<'document>

A SchemaReader over a node of a parsed silk.yaml.document.YamlDocument.

When to use#

SchemaYaml.decode uses it. Use it directly to read a typed value from one node of a document that the program parsed itself, such as one document of a stream from YamlDocument.parseAll: call Schemas.read with it.

Details#

A text field also accepts a plain scalar that YAML reads as a number, a boolean, or null, and gets the text as written. Spans in the problems are byte positions in the parsed text.

Implementation YamlSchemaReader<'document>#

silk
impl<'document> YamlSchemaReader<'document>

Associated function make#

silk
pub fn make(document: &'document YamlDocument, node: YamlNode) -> YamlSchemaReader<'document>

Returns a reader of the value at node of document, which stops at the first problem.

Associated function collectingAll#

silk
pub fn collectingAll(document: &'document YamlDocument, node: YamlNode) -> YamlSchemaReader<'document>

Returns a reader of the value at node of document that records every problem instead of stopping at the first. Read them with YamlSchemaReader.intoErrors.

Method intoErrors#

silk
pub fn intoErrors(self: Self) -> List<SchemaError>

Returns the problems the reader recorded, in the order they were found.

Implementation YamlSchemaReader<'document>#

silk
impl<'document> YamlSchemaReader<'document>

Implementation SchemaReader for YamlSchemaReader<'document>#

silk
impl<'document> SchemaReader for YamlSchemaReader<'document>

Operation path#

silk
fn path(self: &mut Self) -> &mut SchemaPath

Returns the path of the part being read.

Operation report#

silk
effect fn report(self: &mut Self, issue: Issue) -> () ! Issue | OutOfMemoryError ? &mut Allocator

Fails with the issue, or records it and returns when the reader collects every problem.

Operation collecting#

silk
fn collecting(self: &Self) -> bool

Returns whether the reader records every problem.

Operation lastSpan#

silk
fn lastSpan(self: &Self) -> Option<Span>

Returns the span of the last complete value read.

Operation lastKind#

silk
fn lastKind(self: &Self) -> ValueKind

Returns the kind of the last complete value read.

Operation mark#

silk
effect fn mark(self: &mut Self) -> usize ! OutOfMemoryError ? &mut Allocator

Remembers the open mappings and sequences and the node being read.

Operation recover#

silk
effect fn recover(self: &mut Self, mark: usize, skip: bool) -> () ! Issue | OutOfMemoryError ? &mut Allocator

Returns to the mark, closing the mappings and sequences opened since. With skip, the value at the mark becomes the last one read.

Operation release#

silk
fn release(self: &mut Self, mark: usize) -> ()

Forgets the mark and every later one.

Operation boolean#

silk
effect fn boolean(self: &mut Self) -> bool ! Issue | OutOfMemoryError ? &mut Allocator

Reads true or false.

Operation signed#

silk
effect fn signed(self: &mut Self) -> i64 ! Issue | OutOfMemoryError ? &mut Allocator

Reads an integer as an i64.

Operation unsigned#

silk
effect fn unsigned(self: &mut Self) -> u64 ! Issue | OutOfMemoryError ? &mut Allocator

Reads an integer as a u64.

Operation float#

silk
effect fn float(self: &mut Self) -> f64 ! Issue | OutOfMemoryError ? &mut Allocator

Reads an integer or a float as an f64.

Operation text#

silk
effect fn text(self: &mut Self) -> String ! Issue | OutOfMemoryError ? &mut Allocator

Reads a string, or the text of a plain scalar that YAML reads as a number, a boolean, or null.

Operation null#

silk
effect fn null(self: &mut Self) -> bool ! Issue | OutOfMemoryError ? &mut Allocator

Reads past a null value and returns true, or returns false for another value.

Operation beginList#

silk
effect fn beginList(self: &mut Self) -> () ! Issue | OutOfMemoryError ? &mut Allocator

Starts reading a sequence.

Operation nextElement#

silk
effect fn nextElement(self: &mut Self) -> bool ! Issue | OutOfMemoryError ? &mut Allocator

Returns true at the next item, or ends the sequence and returns false.

Operation beginObject#

silk
effect fn beginObject(self: &mut Self) -> () ! Issue | OutOfMemoryError ? &mut Allocator

Starts reading a mapping.

Operation member#

silk
effect fn member(self: &mut Self, key: string) -> bool ! Issue | OutOfMemoryError ? &mut Allocator

Finds the member key of the mapping and leaves the reader at its value. A missing key leaves the start of the mapping as the last span.

Operation rejectUnread#

silk
effect fn rejectUnread(self: &mut Self, expected: string<'static>) -> () ! Issue | OutOfMemoryError ? &mut Allocator

Reports every member no member call found, at its key.

Operation endObject#

silk
effect fn endObject(self: &mut Self) -> () ! Issue | OutOfMemoryError ? &mut Allocator

Ends the mapping being read.

YamlSchemaWriter#

silk
pub struct YamlSchemaWriter

A SchemaWriter that writes block-style YAML to the ambient Writer.

When to use#

SchemaYaml.encode uses it. Use it directly to write several values as the documents of one stream: call Schemas.write for each, nextDocument between them, and finish at the end.

Gotchas#

The text is kept in a 4 KiB buffer; call finish after the last value, or the end of the text stays in it.

Implementation YamlSchemaWriter#

silk
impl YamlSchemaWriter

Associated function make#

silk
pub fn make() -> YamlSchemaWriter

Returns a writer at the start of the first document.

Method nextDocument#

silk
pub effect fn nextDocument(self: &mut Self) -> () ! Issue | WriterError ? &mut Writer

Ends the current document with a --- line, so that the next value starts a new document.

Errors#

  • WriterError if the Writer fails while the buffer is written out.

Method finish#

silk
pub effect fn finish(self: &mut Self) -> () ! Issue | WriterError ? &mut Writer

Writes the rest of the buffer to the Writer. It does not flush the Writer.

Errors#

  • WriterError if the Writer fails. Bytes that it accepted before the failure stay written.

Implementation SchemaWriter for YamlSchemaWriter#

silk
impl SchemaWriter for YamlSchemaWriter

Operation boolean#

silk
effect fn boolean(self: &mut Self, value: bool) -> () ! Issue | WriterError ? &mut Writer

Writes true or false.

Operation signed#

silk
effect fn signed(self: &mut Self, value: i64) -> () ! Issue | WriterError ? &mut Writer

Writes the integer in decimal.

Operation unsigned#

silk
effect fn unsigned(self: &mut Self, value: u64) -> () ! Issue | WriterError ? &mut Writer

Writes the integer in decimal.

Operation float#

silk
effect fn float(self: &mut Self, value: f64) -> () ! Issue | WriterError ? &mut Writer

Writes the number, with .nan, .inf, and -.inf for the values that are not finite.

Operation text#

silk
effect fn text(self: &mut Self, value: string) -> () ! Issue | WriterError ? &mut Writer

Writes the string, quoted only when a reader would read it as something else.

Operation null#

silk
effect fn null(self: &mut Self) -> () ! Issue | WriterError ? &mut Writer

Writes null.

Operation beginList#

silk
effect fn beginList(self: &mut Self) -> () ! Issue | WriterError ? &mut Writer

Starts a sequence.

Operation element#

silk
effect fn element(self: &mut Self) -> () ! Issue | WriterError ? &mut Writer

Starts the next item, with - .

Operation endList#

silk
effect fn endList(self: &mut Self) -> () ! Issue | WriterError ? &mut Writer

Ends the sequence; an empty one is written as [].

Operation beginObject#

silk
effect fn beginObject(self: &mut Self) -> () ! Issue | WriterError ? &mut Writer

Starts a mapping.

Operation key#

silk
effect fn key(self: &mut Self, name: string) -> () ! Issue | WriterError ? &mut Writer

Writes the key of the next entry and :.

Operation endObject#

silk
effect fn endObject(self: &mut Self) -> () ! Issue | WriterError ? &mut Writer

Ends the mapping; an empty one is written as {}.

Category: Data formats.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.

View the source of this page