1use crate::sexp::Sexp;
16
17#[must_use]
19pub fn ok(command: &str, fields: Vec<(&str, Sexp)>) -> Sexp {
20 let mut items = Vec::with_capacity(fields.len() + 2);
21 items.push(Sexp::symbol("ok"));
22 items.push(Sexp::symbol(command));
23 for (key, value) in fields {
24 items.push(Sexp::list(vec![Sexp::symbol(key), value]));
25 }
26 Sexp::list(items)
27}
28
29#[must_use]
31pub fn error(command: &str, message: &str) -> Sexp {
32 Sexp::list(vec![
33 Sexp::symbol("error"),
34 Sexp::symbol(command),
35 Sexp::string(message),
36 ])
37}
38
39#[must_use]
41pub const fn flag(value: bool) -> &'static str {
42 if value { "t" } else { "nil" }
43}
44
45#[cfg(test)]
46mod tests {
47 use super::{error, flag, ok};
48 use crate::sexp::Sexp;
49
50 #[test]
51 fn ok_envelope_renders_command_and_fields() {
52 let rendered = ok(
53 "push",
54 vec![
55 ("document-id", Sexp::string("DOC1")),
56 ("created", Sexp::symbol(flag(true))),
57 ],
58 )
59 .render();
60 assert_eq!(rendered, "(ok push (document-id \"DOC1\") (created t))");
61 }
62
63 #[test]
64 fn error_envelope_renders_message() {
65 assert_eq!(
66 error("open", "no linked document").render(),
67 "(error open \"no linked document\")"
68 );
69 }
70}