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#
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#
pub struct YamlOutputThe owner of the functions that write a whole document. It has no fields and is never constructed.
Implementation YamlOutput#
impl YamlOutputAssociated function write#
pub effect fn write(document: &YamlDocument) -> () ! YamlError | WriterError ? &mut WriterWrites 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#
YamlErrorwith reasonYamlReason.DepthExceededif the collections nest more thanMAX_DEPTH(128) levels deep, which aliases can cause. Itsoffsetis 0.WriterErrorif theWriterfails. Bytes that it accepted before the failure stay written.
Examples#
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#
pub struct YamlEmitterWrites 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
finishafter the last value, or the end of the text stays in the buffer.Calls out of order trap: a value with no
keyorelementbefore it in a collection, akeyoutside a mapping, anelementoutside a sequence, akeyorelementbefore the last one has its value, a second value in one document, or an end call that does not match the open collection.
Examples#
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#
impl YamlEmitterAssociated function make#
pub fn make() -> YamlEmitterReturns an emitter at the start of the first document, with an empty buffer.
Method null#
pub effect fn null(self: &mut Self) -> () ! YamlError | WriterError ? &mut WriterWrites null.
Errors#
WriterErrorif theWriterfails while the buffer is written out.
Method boolean#
pub effect fn boolean(self: &mut Self, value: bool) -> () ! YamlError | WriterError ? &mut WriterWrites true or false.
Errors#
WriterErrorif theWriterfails while the buffer is written out.
Method signed#
pub effect fn signed(self: &mut Self, value: i64) -> () ! YamlError | WriterError ? &mut WriterWrites the integer in decimal.
Errors#
WriterErrorif theWriterfails while the buffer is written out.
Method unsigned#
pub effect fn unsigned(self: &mut Self, value: u64) -> () ! YamlError | WriterError ? &mut WriterWrites the integer in decimal.
Errors#
WriterErrorif theWriterfails while the buffer is written out.
Method float#
pub effect fn float(self: &mut Self, value: f64) -> () ! YamlError | WriterError ? &mut WriterWrites 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#
WriterErrorif theWriterfails while the buffer is written out.
Method text#
pub effect fn text(self: &mut Self, value: string) -> () ! YamlError | WriterError ? &mut WriterWrites 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#
WriterErrorif theWriterfails while the buffer is written out.
Method beginSequence#
pub effect fn beginSequence(self: &mut Self) -> () ! YamlError | WriterError ? &mut WriterStarts a sequence. Call element before each item and endSequence after the last.
Errors#
YamlErrorwith reasonYamlReason.DepthExceededif more thanMAX_DEPTH(128) collections are open. Itsoffsetis 0.
Method element#
pub effect fn element(self: &mut Self) -> () ! YamlError | WriterError ? &mut WriterStarts the next item of the open sequence.
Errors#
WriterErrorif theWriterfails 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#
pub effect fn endSequence(self: &mut Self) -> () ! YamlError | WriterError ? &mut WriterEnds the open sequence. A sequence with no items is written as [].
Errors#
WriterErrorif theWriterfails 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#
pub effect fn beginMapping(self: &mut Self) -> () ! YamlError | WriterError ? &mut WriterStarts a mapping. Call key before each value and endMapping after the last.
Errors#
YamlErrorwith reasonYamlReason.DepthExceededif more thanMAX_DEPTH(128) collections are open. Itsoffsetis 0.
Method key#
pub effect fn key(self: &mut Self, name: string) -> () ! YamlError | WriterError ? &mut WriterWrites 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#
WriterErrorif theWriterfails 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#
pub effect fn endMapping(self: &mut Self) -> () ! YamlError | WriterError ? &mut WriterEnds the open mapping. A mapping with no entries is written as {}.
Errors#
WriterErrorif theWriterfails 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#
pub effect fn value(self: &mut Self, document: &YamlDocument, value: YamlNode) -> () ! YamlError | WriterError ? &mut WriterWrites 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#
YamlErrorwith reasonYamlReason.DepthExceededif more thanMAX_DEPTH(128) collections would be open. Itsoffsetis 0.WriterErrorif theWriterfails while the buffer is written out.
Method nextDocument#
pub effect fn nextDocument(self: &mut Self) -> () ! YamlError | WriterError ? &mut WriterEnds 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#
WriterErrorif theWriterfails while the buffer is written out.
Gotchas#
Traps if a collection is still open.
Method finish#
pub effect fn finish(self: &mut Self) -> () ! YamlError | WriterError ? &mut WriterWrites 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#
WriterErrorif theWriterfails. 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.