silk.yaml.output.

Write YAML text: a whole YamlDocument, or values one at a time with YamlEmitter.

When to use#

Use YamlOutput.write to write a parsed silk.yaml.document.YamlDocument back as text. Use YamlEmitter to write YAML from a program's own data, value by value. Use silk.schema.yaml.SchemaYaml.encode to write a typed value.

Details#

The output is block style: each mapping entry and each sequence item is on its own line, and nested collections are indented by two spaces. An empty mapping is written as {} and an empty sequence as []. A string is written plain (without quotes) when a YAML 1.2 reader reads the plain text back as the same string, and a YAML 1.1 reader does too: yes, no, on, off, y, n, dates such as 2001-12-14, and numbers such as 12:30 and 1_000 are quoted. A string with line breaks is written as a literal block scalar (|). All other strings are double-quoted, with escapes for control characters and line separators. Floats are written with the shortest text that reads back to the same value, and a whole float keeps a .0 so it stays a float.

The text goes to the ambient Writer in pieces of up to 4 KiB.

Examples#

Write a mapping#

silk
import silk.collections.slice { Slice }
import silk.core.effect { Effect }
import silk.io.writer { Writer, WriterError }
import silk.yaml.document { YamlError }
import silk.yaml.output { YamlEmitter }

struct Capture {
  bytes: [u8; 128],
  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 () }
}

effect fn emit() -> () ! YamlError | WriterError ? &mut Writer {
  let mut emitter = YamlEmitter.make()
  run emitter.beginMapping()
  run emitter.key("name")
  run emitter.text("Ada")
  run emitter.key("ports")
  run emitter.beginSequence()
  run emitter.element()
  run emitter.signed(80)
  run emitter.element()
  run emitter.signed(443)
  run emitter.endSequence()
  run emitter.endMapping()
  return run emitter.finish()
}

pub effect fn main() -> i32 ! YamlError | WriterError {
  let mut capture = Capture {bytes: [0; 128], length: 0}
  run emit() |> Effect.provideMut<Writer>(&mut capture)
  if Slice.view<u8>(&capture.bytes, 0, capture.length) != b"name: Ada\nports:\n  - 80\n  - 443\n" {
    return 1
  }
  return 0
}

Import as YamlOutput with import silk.yaml.output { YamlOutput }.

Public declarations: 2.

YamlOutput#

silk
pub struct YamlOutput

The owner of the functions that write a whole document. It has no fields and is never constructed.

Implementation YamlOutput#

silk
impl YamlOutput

Associated function write#

silk
pub effect fn write(document: &YamlDocument) -> () ! YamlError | WriterError ? &mut Writer

Writes every document of document as YAML text to the ambient Writer, and a --- line before each document after the first. A stream with no documents writes nothing.

Details#

The text is block style, with two spaces of indentation. Strings are written plain when that reads back as the same string, as a literal block scalar (|) when they hold line breaks, and double-quoted otherwise. Comments, anchors, tags, and the source style of each value are not kept: a value that an alias copied is written in full. The text goes to the Writer in pieces of up to 4 KiB. It does not flush the Writer.

Errors#

  • YamlError with reason YamlReason.DepthExceeded if the collections nest more than MAX_DEPTH (128) levels deep, which aliases can cause. Its offset is 0.

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

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.yaml.document { YamlDocument, YamlError }
import silk.yaml.output { YamlOutput }

struct Capture {
  bytes: [u8; 128],
  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 ! YamlError | WriterError | OutOfMemoryError {
  let mut allocator = Allocator.systemAllocatorProvider()
  let document = run YamlDocument.parse(b"{name: Ada, tags: [a, 'b c']}") |> Effect.provideMut<Allocator>(&mut allocator)
  let mut capture = Capture {bytes: [0; 128], length: 0}
  run YamlOutput.write(&document) |> Effect.provideMut<Writer>(&mut capture)
  if Slice.view<u8>(&capture.bytes, 0, capture.length) != b"name: Ada\ntags:\n  - a\n  - b c\n" {
    return 1
  }
  return 0
}

YamlEmitter#

silk
pub struct YamlEmitter

Writes YAML text to the ambient Writer, one value at a time, in block style.

When to use#

Write YAML from a program's own data without building a YamlDocument first. Use YamlOutput.write for a document you have.

Details#

Start a mapping with beginMapping, then call key before each value and endMapping at the end. Start a sequence with beginSequence, then call element before each value and endSequence at the end. A value is a scalar (null, boolean, signed, unsigned, float, text) or a nested collection. One document is one value; call nextDocument to start another, and finish at the end. Nested collections are indented by two spaces, an empty mapping is {}, and an empty sequence is []. A string is written plain when a reader reads it back as the same string, as a literal block scalar (|) when it holds line breaks, and double-quoted otherwise. The text is kept in a 4 KiB buffer that goes to the Writer when it is full and at finish.

Gotchas#

  • Call finish after the last value, or the end of the text stays in the buffer.

  • Calls out of order trap: a value with no key or element before it in a collection, a key outside a mapping, an element outside a sequence, a key or element before the last one has its value, a second value in one document, or an end call that does not match the open collection.

Examples#

silk
import silk.collections.slice { Slice }
import silk.core.effect { Effect }
import silk.io.writer { Writer, WriterError }
import silk.yaml.document { YamlError }
import silk.yaml.output { YamlEmitter }

struct Capture {
  bytes: [u8; 128],
  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 () }
}

effect fn emit() -> () ! YamlError | WriterError ? &mut Writer {
  let mut emitter = YamlEmitter.make()
  run emitter.beginSequence()
  run emitter.element()
  run emitter.beginMapping()
  run emitter.key("on")
  run emitter.boolean(true)
  run emitter.key("note")
  run emitter.text("line one\nline two\n")
  run emitter.endMapping()
  run emitter.endSequence()
  return run emitter.finish()
}

pub effect fn main() -> i32 ! YamlError | WriterError {
  let mut capture = Capture {bytes: [0; 128], length: 0}
  run emit() |> Effect.provideMut<Writer>(&mut capture)
  if Slice.view<u8>(&capture.bytes, 0, capture.length) != b"- \"on\": true\n  note: |\n    line one\n    line two\n" {
    return 1
  }
  return 0
}

Implementation YamlEmitter#

silk
impl YamlEmitter

Associated function make#

silk
pub fn make() -> YamlEmitter

Returns an emitter at the start of the first document, with an empty buffer.

Method null#

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

Writes null.

Errors#

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

Method boolean#

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

Writes true or false.

Errors#

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

Method signed#

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

Writes the integer in decimal.

Errors#

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

Method unsigned#

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

Writes the integer in decimal.

Errors#

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

Method float#

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

Writes the float with the shortest text that reads back to the same value.

Details#

A whole number keeps a fraction, as 2.0, so it reads back as a float. An exponent comes after a fraction and has a sign, as in 1.0e+30, so YAML 1.1 readers read it too. A NaN is written as .nan, and the infinities as .inf and -.inf.

Errors#

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

Method text#

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

Writes the string: plain when a reader reads it back as the same string, as a literal block scalar (|) when it holds line breaks, and double-quoted otherwise.

Details#

Text that a reader would take for another kind of value, such as true, 12, or null, is quoted, as is text that a YAML 1.1 reader takes for another value: yes, no, on, off, y, n, dates such as 2001-12-14, and numbers such as 12:30 and 1_000. Double-quoted text escapes ", \, control characters, and the Unicode line separators.

Errors#

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

Method beginSequence#

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

Starts a sequence. Call element before each item and endSequence after the last.

Errors#

  • YamlError with reason YamlReason.DepthExceeded if more than MAX_DEPTH (128) collections are open. Its offset is 0.

Method element#

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

Starts the next item of the open sequence.

Errors#

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

Gotchas#

Traps if the innermost open collection is not a sequence, or the last item has no value.

Method endSequence#

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

Ends the open sequence. A sequence with no items is written as [].

Errors#

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

Gotchas#

Traps if the innermost open collection is not a sequence, or its last item has no value.

Method beginMapping#

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

Starts a mapping. Call key before each value and endMapping after the last.

Errors#

  • YamlError with reason YamlReason.DepthExceeded if more than MAX_DEPTH (128) collections are open. Its offset is 0.

Method key#

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

Writes the key of the next entry of the open mapping, and :.

Details#

The key is plain or double-quoted by the rules of text; a key with line breaks is double-quoted. A key longer than 1000 bytes is written as an explicit key (? key), because YAML limits other keys to 1024 characters. The emitter does not check that keys are unique.

Errors#

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

Gotchas#

Traps if the innermost open collection is not a mapping, or the last key has no value.

Method endMapping#

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

Ends the open mapping. A mapping with no entries is written as {}.

Errors#

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

Gotchas#

Traps if the innermost open collection is not a mapping, or its last key has no value.

Method value#

silk
pub effect fn value(self: &mut Self, document: &YamlDocument, value: YamlNode) -> () ! YamlError | WriterError ? &mut Writer

Writes value, the node of document, with everything in it.

Details#

Comments, anchors, tags, and the source style of each value are not kept. An integer is written in decimal.

Errors#

  • YamlError with reason YamlReason.DepthExceeded if more than MAX_DEPTH (128) collections would be open. Its offset is 0.

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

Method nextDocument#

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

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

Details#

A document with no value is written as null.

Errors#

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

Gotchas#

Traps if a collection is still open.

Method finish#

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

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

Details#

A document with no value is written as null. The emitter can write more values after it only after nextDocument.

Errors#

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

Gotchas#

Traps if a collection is still open.

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