1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
use std::fmt::Write;
use crate::{CanonicalImport, CanonicalWasi};
mod for_instance;
pub struct WastEncoder<'a, W> {
pub(crate) source: &'a CanonicalWasi,
pub(crate) writer: W,
indent: usize,
indent_text: &'static str,
}
impl<'a, W: Write> WastEncoder<'a, W> {
pub fn new(source: &'a CanonicalWasi, writer: W) -> Self {
Self { source, writer, indent: 0, indent_text: " " }
}
pub fn with_indent_text(self, text: &'static str) -> Self {
Self { indent_text: text, ..self }
}
}
impl<'a, W: Write> Write for WastEncoder<'a, W> {
fn write_str(&mut self, s: &str) -> std::fmt::Result {
self.writer.write_str(s)
}
}
// (component $Root
// (import "wasi:io/error@0.2.0" (instance $wasi:io/error@0.2.0
// (export "error" (type (sub resource)))
// ))
// (alias export $wasi:io/error@0.2.0 "error" (type $io-error))
//
// (type $stream-error (variant
// (case "last-operation-failed" (own $io-error))
// (case "closed")
// ))
// (type $stream-result (result (error $stream-error)))
//
// (import "wasi:io/streams@0.2.0" (instance $wasi:io/streams@0.2.0
// (export $output-stream "output-stream" (type (sub resource)))
// (alias outer $Root $io-error (type $io-error))
//
// (alias outer $Root $stream-error (type $stream-error0))
// (export $stream-error "stream-error" (type (eq $stream-error0)))
// (type $stream-result (result (error $stream-error)))
//
// (export "[method]output-stream.blocking-write-and-flush"
// (func (param "self" (borrow $output-stream)) (param "contents" (list u8)) (result $stream-result))
// )
// ))
// (alias export $wasi:io/streams@0.2.0 "output-stream" (type $output-stream))
// (alias export $wasi:io/streams@0.2.0 "[method]output-stream.blocking-write-and-flush" (func $output-stream.blocking-write-and-flush))
// )
impl<'a, W: Write> WastEncoder<'a, W> {
pub fn encode(&mut self) -> std::fmt::Result {
write!(self.writer, "(component ${}", self.source.name)?;
self.indent(true);
for import in &self.source.imports {
match import {
CanonicalImport::Instance(instance) => self.encode_instance(instance)?,
}
}
self.dedent(true);
self.write_str(")")?;
Ok(())
}
pub(crate) fn write_id(&mut self, id: &str) -> std::fmt::Result {
write!(self.writer, "${}", id)
}
pub fn encode_id(&mut self, id: &str) -> String {
let mut alloc = String::with_capacity(id.len() + 1);
alloc.push('$');
make_kebab(id, &mut alloc);
alloc
}
pub fn encode_kebab(&mut self, id: &str) -> String {
let mut alloc = String::with_capacity(id.len() + 2);
alloc.push('"');
make_kebab(id, &mut alloc);
alloc.push('"');
alloc
}
pub(crate) fn write_name(&mut self, id: &str) -> std::fmt::Result {
write!(self.writer, "\"{}\"", id)
}
pub fn indent(&mut self, newline: bool) {
self.indent += 1;
if newline {
self.newline().ok();
}
}
pub fn dedent(&mut self, newline: bool) {
self.indent -= 1;
if newline {
self.newline().ok();
}
}
pub fn newline(&mut self) -> std::fmt::Result {
self.write_str("\n")?;
let range = (0..self.indent).into_iter();
for _ in range {
let indent = self.indent_text.as_ref();
self.writer.write_str(indent)?;
}
Ok(())
}
}
fn make_kebab(input: &str, buffer: &mut String) {
for c in input.chars() {
match c {
'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' | ':' | '@' | '/' => buffer.push(c),
_ => buffer.push('-'),
}
}
}