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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
//! Serde serializer generating Rust code.
//!
//! This crate can be used to "embed" something into code, having only some serialized
//! data, like JSON or YAML. This way, you'll mostly escape runtime cost of deserialization,
//! nearly as if you've written the same data directly in code by hand.
//! Of course, in most cases this cost is already negligible, but for crates which use
//! large blobs of data this crate can come in handy, improving startup times, and can
//! eliminate the need for `serde` as runtime dependency.
//!
//! ## Usage
//! In general, to embed some code into crate, you have to use the build script
//! and [`include!`][include] macro. Inside the build script, you'll generate
//! some code with one of the [functions][funcs] provided by `uneval`,
//! and then include the generated file, like this:
//! ```ignore
//! let value = include!(concat!(env!(OUT_DIR), "/file_name.rs"));
//! ```
//!
//! ## How does it work?
//!
//! Of course, we can't always directly construct the code for the desired value (more on this
//! in the [Limitations](#limitations) section below).
//! However, in many cases the information provided by Serde is enough.
//!
//! For every case, we'll provide an example of how the generated code can look like, as a sequence of
//! `let` statements, where the left part is written by hand and the right one is assumed to be generated.
//!
//! ### Primitives
//!
//! Number literals, such as `i8` or `f32`, are directly written into the output. The only tricky part
//! is that we have to use suffixed literals, e.g. `1u8` or `1.1f64` - otherwise we'd run into the problem
//! with the float values which are in fact integers, since they would be output as integer literals,
//! not as float ones (i.e. `1` and not `1.0`) and so wouldn't typecheck.
//!
//! Boolean and character literals are also simply written directly - no surprises here.
//!
//! Example:
//! ```
//! let _: i8 = 12i8;
//! let _: u128 = 12345u128;
//! let _: f32 = -1f32;
//! let _: f64 = 12345.6789f64;
//! let _: char = 'c';
//! let _: bool = true;
//! ```
//!
//! ### Strings
//! When Serde gives us something string-like, we have to make some kind of conversion, since
//! string literals are of type `&'static str`, and string-like fields in serializable structs are
//! usually of some owned type, like `String`. We assume that every such type would be convertible to
//! `String` using [`Into`][std::convert::Into], so we simply emit a string literal with call to `into`.
//!
//! Example:
//! ```
//! let _: String = "string value".into();
//! ```
//!
//! Byte strings are handled as byte sequences, [as recommended by Serde itself][::serde::Serializer::serialize_bytes],
//! and so we'll discuss them [below](#vec-like-types-sequences).
//!
//! ### Tuple structs and unit values
//!
//! Unit type (`()`), unit structs and unit variants (including `None`) are emitted simply by using
//! the type name. Tuple structs and variants (and newtype-flavored ones, including `Some`)
//! are emitted by writing  their name (with the enum name, if necessary), parenthesis,
//! and serializing the inner values.
//!
//! Example:
//! ```
//! struct TupleStruct((), Option<u8>, Option<u8>);
//! let _: TupleStruct = TupleStruct((), None, Some(1u8));
//! ```
//!
//! ### Vec-like types (sequences)
//!
//! `Vec`-like structures are constructed using the temporary `Vec`. We assume that every such type will
//! implement [`FromIterator`][std::iter::FromIterator], so we emit the call to `vec!` macro,
//! serialize the data and finalize the emit with call to `into_iter().collect()`.
//! This is not exactly zero-cost, but it seems that this is the minimal.
//!
//! Example:
//! ```
//! let _: Vec<u32> = vec![1u32, 2u32, 3u32].into_iter().collect();
//! ```
//!
//! ### Tuples and arrays
//!
//! That's where it becomes tricky.
//!
//! The problem is that Serde doesn't distinguish between this two kinds of values: they both are treated
//! as sequences with known length, called "tuples" internally; as a consequence, we don't know at the emit time,
//! which of them we'll be generating. But in the Rust code, they are created with entirely different syntax,
//! and there's no easy way to convert one into another. So, we decided to emit a little "runtime"
//! (consisting of small `#[inline]` functions, so it should in fact be zero-cost), which will
//! correctly handle the data according to the type being requested.
//!
//! The idea is, in fact, directly borrowed from the [`collect`]/[`FromIterator`] pair: we can call `collect`
//! on every iterator value, and, as long as the target type implements `FromIterator` with the necessary
//! parameters, `collect` will do its job. We're using not the trait method, but the free function (the reason is
//! that with the trait we would sometimes have a chain of type inferences, which Rust is unable to solve);
//! however, this doesn't change the overall picture.
//!
//! [`collect`]: std::iter::Iterator::collect
//! [`FromIterator`]: std::iter::FromIterator
//!
//! In general, here's what being generated:
//! - A `FromTuple<T>` trait with `from_tuple(input: T) -> Self` associated function.
//! - Two implementations: `impl<T> FromTuple<(T,...,T,)> for [T; N]` and
//! `impl<T1, ... TN> FromTuple<(T1,...TN,)> for (T1,...TN,)`.
//! - Function `convert<T1, ... TN, Out: FromTuple<(T1,...TN,)>>(tuple: (T1,...TN,)) -> Out`,
//! which simply calls `Out::from_tuple(tuple)`.
//!
//! Then, the value itself is created by the call to `convert`, with tuple of serialized values as argument.
//! Depending on whether the target expects the array or tuple, `convert` will select one particular implementation.
//!
//! Example:
//! ```
//! let tuple: (i32, f32, String) = {
//!     trait FromTuple<T>: Sized {
//!         fn from_tuple(tuple: T) -> Self;
//!     }
//!
//!     impl<T> FromTuple<(T,T,T,)> for [T; 3] {
//!         #[inline]
//!         fn from_tuple(tuple: (T,T,T,)) -> Self {
//!             [tuple.0,tuple.1,tuple.2]
//!         }
//!     }
//!
//!     impl<T0,T1,T2> FromTuple<(T0,T1,T2,)> for (T0,T1,T2,) {
//!         #[inline]
//!         fn from_tuple(tuple: (T0,T1,T2,)) -> Self {
//!             tuple
//!         }
//!     }
//!
//!     #[inline]
//!     fn convert<T0,T1,T2, Out: FromTuple<(T0,T1,T2,)>>(tuple: (T0,T1,T2,)) -> Out {
//!         Out::from_tuple(tuple)
//!     }
//!
//!     convert((1i32,1f32,"tuple entry".into()))
//! };
//! // Check that the tuple is indeed created as desired.
//! assert_eq!(tuple, (1i32,1f32,"tuple entry".to_string()));
//!
//! let arr: [i32; 4] = {
//!     trait FromTuple<T>: Sized {
//!         fn from_tuple(tuple: T) -> Self;
//!     }
//!
//!     impl<T> FromTuple<(T,T,T,T,)> for [T; 4] {
//!         #[inline]
//!         fn from_tuple(tuple: (T,T,T,T,)) -> Self {
//!             [tuple.0,tuple.1,tuple.2,tuple.3]
//!         }
//!     }
//!
//!     impl<T0,T1,T2,T3> FromTuple<(T0,T1,T2,T3,)> for (T0,T1,T2,T3,) {
//!         #[inline]
//!         fn from_tuple(tuple: (T0,T1,T2,T3,)) -> Self {
//!             tuple
//!         }
//!     }
//!
//!     #[inline]
//!     fn convert<T0,T1,T2,T3, Out: FromTuple<(T0,T1,T2,T3,)>>(tuple: (T0,T1,T2,T3,)) -> Out {
//!         Out::from_tuple(tuple)
//!     }
//!
//!     convert((1,2,3,4))
//! };
//! // Check that the array is indeed created as desired.
//! assert_eq!(arr, [1, 2, 3, 4]);
//! ```
//!
//! #### Zero-sized arrays
//! Since the code presented above would work only for non-empty tuples, we have to handle the "empty tuple" case
//! differently. Fortunately for us, the "real" empty tuple is handled as a unit, so we can directly emit the code
//! which yields an empty array:
//! ```
//! let arr: [i32; 0] = {
//!     #[inline]
//!     fn convert<T>(_: ()) -> [T; 0] {
//!         []
//!     }
//!
//!     convert(())
//! };
//! ```
//!
//! ### Maps
//!
//! Since Rust doesn't have the notion of map literals, we can't construct one directly. However, standard map-like
//! types ([`HashMap`], [`BTreeMap`]) implement `FromIterator<(K, V)>`, i.e. they can be built from the iterator of
//! key-value pairs. `uneval` generates code according to this convention: we create a `Vec` of pairs, which is then
//! converted into map with `into_iter().collect()`.
//!
//! Example:
//! ```
//! let _: std::collections::HashMap<i32, String> = vec![
//!     (1, "first".into()),
//!     (100, "one hundredth".into()),
//! ].into_iter().collect();
//! ```
//!
//! [`HashMap`]: std::collections::HashMap
//! [`BTreeMap`]: std::collections::BTreeMap
//!
//! ### Structs
//!
//! Last but not the least, this case is relatively simple. Emitted code is simply the struct construction -
//! i.e. the struct name, the curly braces and a list of pairs of the form `{field name}: {serialized value}`.
//!
//! Example:
//! ```
//! struct Struct { boolean: bool, number: i32, string: String }
//! let _: Struct = Struct {
//!     boolean: true,
//!     number: 1i32,
//!     string: "string".into()
//! };
//! ```
//!
//! ## Limitations
//! There are some cases when `uneval` will be unable to generate valid code. Namely:
//! 1. Since Serde doesn't provide us the full path to the type in question (and in most cases it's simply unable to),
//! all the structs and enums used during value construction must be in scope.
//! As a consequence, all of them must have distinct names - otherwise, there will be name clashes.
//! 2. This serializer is intended for use with derived implementation. It may return bogus results
//! when used with customized `Serialize`.
//! 3. It is impossible to consume code for the type with private fields outside from the module it is defined in.
//! In fact, to be able to use this type with `uneval`, you'll have to distribute two copies of your crate,
//! one of which would only export the definition with derived `Serialize` to be used by serializer
//! during the build-time of the second copy. (Isn't this a bit too complex?)
//! 4. It is impossible to use empty tuple structs (i.e. `Empty()`).
//! From the Serde's point of view, they are indistinguishable from unit structs (i.e. `Unit`),
//! but the same Rust syntax can't be used for both, and, since ordinary unit structs are much
//! more common, it was decided to correctly handle them.
//!
//! [include]: https://doc.rust-lang.org/stable/std/macro.include.html

mod helpers;

pub mod error;
pub mod funcs;
pub mod ser;

pub use funcs::{to_file, to_out_dir, to_string, write};