yew_stdweb/format/macros.rs
1//! Contains three macros for wrapping serde format. Collectively they
2//! allow you to define your own text and binary wrappers.
3
4/// This macro is used for a format that can be encoded as Text. It
5/// is used in conjunction with a type definition for a tuple struct
6/// with one (publically accessible) element of a generic type. Since
7/// any type that can be encoded as Text can also be encoded as Binary,
8/// it should be used with the binary_format macro.
9///
10/// ## Example
11///
12/// ```rust
13/// use yew::{binary_format, text_format};
14///
15/// pub struct Json<T>(pub T);
16///
17/// text_format!(Json based on serde_json);
18/// binary_format!(Json based on serde_json);
19/// ```
20#[macro_export]
21macro_rules! text_format {
22 ($type:ident based on $format:ident) => {
23 impl<'a, T> From<$type<&'a T>> for $crate::format::Text
24 where
25 T: ::serde::Serialize,
26 {
27 fn from(value: $type<&'a T>) -> $crate::format::Text {
28 $format::to_string(&value.0).map_err(::anyhow::Error::from)
29 }
30 }
31
32 impl<T> From<$crate::format::Text> for $type<Result<T, ::anyhow::Error>>
33 where
34 T: for<'de> ::serde::Deserialize<'de>,
35 {
36 fn from(value: $crate::format::Text) -> Self {
37 match value {
38 Ok(data) => $type($format::from_str(&data).map_err(::anyhow::Error::from)),
39 Err(reason) => $type(Err(reason)),
40 }
41 }
42 }
43 };
44}
45
46/// This macro is used for a format that can be encoded as Binary. It
47/// is used in conjunction with a type definition for a tuple struct
48/// with one (publicly accessible) element of a generic type. Not
49/// all types that can be encoded as Binary can be encoded as Text.
50/// As such, this macro should be paired with the text_format macro
51/// where such an encoding works (e.g., JSON), or with the
52/// text_format_is_an_error macro for binary-only formats (e.g.,
53/// MsgPack).
54///
55/// # Rely on serde's `to_vec` and `from_vec`
56/// The simplest form of this macro relegates all the work to serde's
57/// `to_vec` function for serialization and serde's `from_vec` for
58/// deseriaization.
59///
60/// ## Examples
61///
62/// ### Binary that is also Text
63///
64/// ```rust
65/// use yew::{binary_format, text_format};
66///
67/// pub struct Json<T>(pub T);
68///
69/// text_format!(Json based on serde_json);
70/// binary_format!(Json based on serde_json);
71/// ```
72///
73/// ### Binary only
74/// ```rust
75/// # mod to_make_rustdoc_happy {
76/// use rmp_serde;
77/// use yew::{binary_format, text_format_is_an_error};
78///
79/// pub struct MsgPack<T>(pub T);
80///
81/// binary_format!(MsgPack based on rmp_serde);
82/// text_format_is_an_error!(MsgPack);
83/// # }
84/// ```
85///
86/// # Supply serialization and deserialization functions
87///
88/// In addition to the "based on" form of this macro demonstrated above,
89/// you can use the three parameter second form to supply
90/// non-standard (i.e., alternatives to serde's `to_vec` and/or `from_slice`)
91/// helpers as the second and third parameters.
92///
93/// ## Example
94/// ```rust
95/// # mod to_make_rustdoc_happy {
96/// use bincode;
97/// use yew::{binary_format, text_format_is_an_error};
98///
99/// pub struct Bincode<T>(pub T);
100///
101/// binary_format!(Bincode, bincode::serialize, bincode::deserialize);
102/// text_format_is_an_error!(Bincode);
103/// # }
104/// ```
105#[macro_export]
106macro_rules! binary_format {
107 ($type:ident based on $format:ident) => {
108 binary_format!($type, $format::to_vec, $format::from_slice);
109 };
110 ($type:ident, $into:path, $from:path) => {
111 impl<'a, T> From<$type<&'a T>> for $crate::format::Binary
112 where
113 T: ::serde::Serialize,
114 {
115 fn from(value: $type<&'a T>) -> $crate::format::Binary {
116 $into(&value.0).map_err(::anyhow::Error::from)
117 }
118 }
119
120 impl<T> From<$crate::format::Binary> for $type<Result<T, ::anyhow::Error>>
121 where
122 T: for<'de> ::serde::Deserialize<'de>,
123 {
124 fn from(value: $crate::format::Binary) -> Self {
125 match value {
126 Ok(data) => $type($from(&data).map_err(::anyhow::Error::from)),
127 Err(reason) => $type(Err(reason)),
128 }
129 }
130 }
131 };
132}
133
134/// This macro is used for a format that can be encoded as Binary but
135/// can't be encoded as Text. It is used in conjunction with a type
136/// definition for a tuple struct with one (publically accessible)
137/// element of a generic type. This macro should be paired with the
138/// binary_format macro that defines the binary-only format.
139///
140/// ## Example
141/// ```rust
142/// # mod to_make_rustdoc_happy {
143/// use rmp_serde;
144/// use yew::{binary_format, text_format_is_an_error};
145///
146/// pub struct MsgPack<T>(pub T);
147///
148/// binary_format!(MsgPack based on rmp_serde);
149/// text_format_is_an_error!(MsgPack);
150/// # }
151/// ```
152#[macro_export]
153#[cfg(any(feature = "bincode", feature = "cbor", feature = "msgpack"))]
154macro_rules! text_format_is_an_error {
155 ($type:ident) => {
156 use $crate::{format::FormatError, text_format};
157
158 fn to_string<T>(_value: T) -> Result<String, ::anyhow::Error> {
159 Err(FormatError::CantEncodeBinaryAsText.into())
160 }
161
162 fn from_str<T>(_s: &str) -> Result<T, ::anyhow::Error> {
163 Err(FormatError::ReceivedTextForBinary.into())
164 }
165
166 text_format!($type based on self);
167 }
168}