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