///|
/// Wire mirror of the host outcome (protocol 1). Failures are values a
/// guest branches on; only transport loss raises.
pub(all) enum Outcome {
Success(content~ : String, structured~ : Json?)
Failure(code~ : String, content~ : String, structured~ : Json?)
} derive(Eq, Debug)
///|
pub extend Outcome with Debug::{to_repr}
///|
pub extend Outcome with Eq::{equal, not_equal}
///|
pub fn Outcome::is_error(self : Outcome) -> Bool {
self is Failure(..)
}
///|
pub fn Outcome::to_json(self : Outcome) -> Json {
let (fields, structured) : (Map[String, Json], Json?) = match self {
Success(content~, structured~) =>
(
{ "kind": Json::string("success"), "content": Json::string(content) },
structured,
)
Failure(code~, content~, structured~) =>
(
{
"kind": Json::string("failure"),
"code": Json::string(code),
"content": Json::string(content),
},
structured,
)
}
match structured {
Some(value) => fields["structured"] = value
None => ()
}
Json::object(fields)
}
///|
/// Lenient inverse of `to_json`: `content` defaults to empty and
/// `structured` to absent, so hosts may omit optional fields.
pub fn Outcome::from_json(value : Json) -> Outcome raise {
guard value is Object(fields) else { fail("ears: outcome must be an object") }
let content = match fields.get("content") {
Some(String(text)) => text
_ => ""
}
let structured = fields.get("structured")
match fields.get("kind") {
Some(String("success")) => Success(content~, structured~)
Some(String("failure")) =>
match fields.get("code") {
Some(String(code)) => Failure(code~, content~, structured~)
_ => fail("ears: failure outcome is missing its code")
}
_ => fail("ears: unknown outcome kind")
}
}