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}