1pub const SCHEMA_VERSION: u32 = 1;
5
6mod data {
8 #![allow(clippy::disallowed_macros)]
9
10 #[derive(Clone, Debug, Eq, PartialEq)]
12 #[cfg_attr(feature = "json", derive(serde::Deserialize, serde::Serialize))]
13 #[cfg_attr(feature = "json", serde(tag = "status", rename_all = "snake_case"))]
14 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
15 pub enum Envelope<T> {
16 Ok {
18 schema_version: u32,
20 data: T,
22 },
23 Err {
25 schema_version: u32,
27 error: ErrorBody,
29 },
30 }
31
32 #[derive(Clone, Debug, Eq, PartialEq)]
34 #[cfg_attr(feature = "json", derive(serde::Deserialize, serde::Serialize))]
35 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
36 pub struct ErrorBody {
37 pub bin: String,
39 pub message: String,
41 }
42}
43
44pub use data::{Envelope, ErrorBody};
45
46impl<T> Envelope<T> {
47 #[must_use]
49 pub fn ok(data: T) -> Self {
50 Self::Ok {
51 schema_version: SCHEMA_VERSION,
52 data,
53 }
54 }
55
56 #[must_use]
58 pub fn err(error: ErrorBody) -> Self {
59 Self::Err {
60 schema_version: SCHEMA_VERSION,
61 error,
62 }
63 }
64}
65
66impl ErrorBody {
67 #[must_use]
69 pub fn new(bin: impl Into<String>, message: impl Into<String>) -> Self {
70 Self {
71 bin: bin.into(),
72 message: message.into(),
73 }
74 }
75}
76
77#[cfg(all(test, feature = "json"))]
78mod tests {
79 use indoc::indoc;
80
81 use super::{Envelope, ErrorBody, SCHEMA_VERSION};
82
83 #[test]
84 fn ok_envelope_roundtrip() {
85 let env = Envelope::ok("demo");
86 let json = serde_json::to_string(&env).unwrap();
87 assert!(json.contains("\"schema_version\":1"));
88 let back: Envelope<String> = serde_json::from_str(&json).unwrap();
89 assert_eq!(back, Envelope::ok("demo".to_owned()));
90 assert_eq!(SCHEMA_VERSION, 1);
91 }
92
93 #[test]
94 fn err_envelope_shape() {
95 let env = Envelope::<()>::err(ErrorBody::new("toy", "missing token"));
96 let json = serde_json::to_string_pretty(&env).unwrap();
97 let expected = indoc! {r#"
98 {
99 "status": "err",
100 "schema_version": 1,
101 "error": {
102 "bin": "toy",
103 "message": "missing token"
104 }
105 }
106 "#};
107 let value: serde_json::Value = serde_json::from_str(&json).unwrap();
108 let expect: serde_json::Value = serde_json::from_str(expected).unwrap();
109 assert_eq!(value, expect);
110 }
111}