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
#![feature(generic_associated_types)]

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "unsafe_speed"), forbid(unsafe_code))]
#![cfg_attr(docsrs, feature(doc_cfg))]

#![deny(missing_docs)]

//! An asynchronous, alloc-free, serialization framework written in 100% safe™ Rust.
//!
//! ### EXPERIMENTAL
//! - `diny` currently requires the nightly Rust toolchain >= 1.56.0 for [GAT](https://github.com/rust-lang/rust/issues/44265) support.
//! - `diny` is still in active design--the API is incomplete and prone to change without notice and without backward compatibility.
//! - no_std support is largely ceremonial at this point as the futures-io _traits_ currently require std.
//! 
//! That being said, it _is_ ready for experimentation and design feedback.
//! # Usage
//!
//! Add a dependency on `diny` and a serializer [format](backend::Format) in `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! diny = { version = "0.2", features = ["derive"] }
//! diny_test = "0.2"
//! ```
//!
//! Add GAT support to your project's main file (e.g. main.rs, lib.rs):
//!
//! ```
//! #![feature(generic_associated_types)]
//! ```
//!
//! Derive [AsyncSerialization] support for the desired data types, or derive just
//! [AsyncSerialize] or [AsyncDeserialize] to limit the support to one-way transfers.
//! 
//! The [Serialize] and [Deserialize] objects returned from the [serializer](serializer::serializer)
//! and [deserializer](deserializer::deserializer) methods implement sinks and streams (respectively)
//! and are the simplest way to serialize and deserialize objects that implement [AsyncSerialization].
//!
//! ```
//! # #![feature(generic_associated_types)]
//! # extern crate futures;
//! # extern crate diny_core;
//! # extern crate diny_test;
//! #
//! use futures::{executor::block_on, SinkExt, StreamExt};
//!
//! #[derive(diny::AsyncSerialization)]
//! pub struct Point {
//!     x: i32,
//!     y: i32,
//! }
//! 
//! # fn main() {
//! let point = Point { x: 1, y: 2 };
//! 
//! // A format can be any implementation of
//! // diny::backend::{FormatSerialize + FormatDeserialize}.
//! let format = diny_test::format();
//! 
//! // A writer can be any implementation of futures::io::AsyncWrite.
//! // In this case, we're using a Vec for simplicity.
//! let writer = vec!();
//! 
//! // A sink is constructible for any implementor of diny::AsyncSerialize
//! let mut sink = diny::serializer(format, writer).into_sink();
//! block_on(sink.send(point)).unwrap();
//! 
//! // Sinks can be destructed back into the inner serializer
//! let diny::Serializer { format, writer } = sink.try_into_inner().unwrap();
//! 
//! // A reader can be any implementation of futures::io::AsyncBufRead.
//! // In this case, we're using a utility module to convert the bytes
//! // written to the vec into an appropriate reader.
//! let reader = diny::util::AsyncSliceReader::from(&writer[..]);
//! 
//! // A stream is constructible for any implementor of diny::AsyncDeserialize
//! let mut stream = diny::deserializer(format, reader).into_stream();
//! let _: Point = block_on(stream.next()).unwrap();
//! # }
//! ```
//! 
//! The [Serializer] and [Deserializer] objects expose `serialize` and
//! `deserialize` methods respecively, which can be used to interleave
//! different [serializable](AsyncSerialization) objects over
//! the same channel.  This has the added benefit of performing the
//! serialization without the overhead of the ownership transfer
//! imposed by sinks and streams.
//! 
//! ```
//! # #![feature(generic_associated_types)]
//! # extern crate futures;
//! # extern crate diny_core;
//! # extern crate diny_test;
//! #
//! # use futures::executor::block_on;
//! # use diny_test::format;
//! #
//! # #[derive(diny::AsyncSerialization)]
//! # pub struct Point {
//! #     x: i32,
//! #     y: i32,
//! # }
//! #
//! # fn main() {
//! let point = Point { x: 1, y: 2 };
//! let slope: i32 = 3;
//!
//! # let writer = vec!();
//! # let format = format();
//! #
//! let mut serializer = diny::serializer(format, writer);
//! # let diny::Serializer { format: _, writer } = 
//! block_on(async {
//!     serializer.serialize(&point).await?;
//!     serializer.serialize(&slope).await?;
//! #   let _ =
//!     serializer.flush().await
//! #   ?;
//! #   let res: Result<diny::Serializer<diny_test::Formatter, Vec<u8>>, <diny_test::Formatter as diny::backend::Format>::Error> = Ok(serializer);
//! #   res
//! }).unwrap();
//! 
//! # let reader = diny::util::AsyncSliceReader::from(&writer[..]);
//! let mut deserializer = diny::deserializer(format, reader);
//! block_on(async {
//!     deserializer.deserialize::<Point>().await?;
//!     deserializer.deserialize::<i32>().await
//! }).unwrap();
//! # }
//! ```
//!
//! The [AsyncSerialize] and [AsyncDeserialize] traits may also be used manually without
//! building an intermediate [Serializer] or [Deserializer] object.
//! 
//! ```
//! # #![feature(generic_associated_types)]
//! # extern crate futures;
//! # extern crate diny_core;
//! # extern crate diny_test;
//! #
//! # use futures::executor::block_on;
//! use futures::io::AsyncWriteExt;
//! use diny::{AsyncDeserialize, AsyncSerialize};
//! # use diny_test::format;
//!
//! # #[derive(diny::AsyncSerialization)]
//! # pub struct Point {
//! #     x: i32,
//! #     y: i32,
//! # }
//! #
//! # fn main() {
//! let point = Point { x: 1, y: 2 };
//!
//! # let format = format();
//! #
//! #   let mut writer = vec!();
//! let write = point.serialize(&format, &mut writer);
//! block_on(write).unwrap();
//! block_on(writer.flush()).unwrap();
//! 
//! #   let mut reader = diny::util::AsyncSliceReader::from(&writer[..]);
//! let read = Point::deserialize(&format, &mut reader);
//! block_on(read).unwrap();
//! # }
//! ```
//! 
//! Additionally, an object's underlying [Encoder](backend::Encodable::Encoder)
//! and [Decoder](backend::Decodable::Decoder) can be easily incorporated into
//! custom futures.  See the [Serialize] and [Deserialize] implementations
//! for an example of embedding them.
//! 
//! The examples directory contains a demonstration of how to use the `async-compat`
//! crate to interoperate with the popular `tokio` library.
//!
//! ## Features
//!
//! By default, `diny` builds with (and currently requires) Rust's standard library.  Importantly,
//! the `derive` proc macros are _not_ built by default, and need to be enabled to
//! become available.
//!
//! | Feature        | Description                                                         | Default                       |
//! |----------------|---------------------------------------------------------------------|:-----------------------------:|
//! | `derive`       | Support for deriving [AsyncSerialize] and [AsyncDeserialize] traits | <font size="5">&#9744;</font> |
//! | `unsafe_speed` | Permit using unsafe code to improve performance                     | <font size="5">&#9744;</font> |
//! | `std`          | Support for Rust's standard library                                 | <font size="5">&#9745;</font> |
//! | `alloc`        | Support for memory allocation without full `std` support            | <font size="5">&#9744;</font> |
//! | `test`         | Build the diny_test formatter and re-export it to diny::test        | <font size="5">&#9744;</font> |
//!
#[cfg(all(not(feature = "std"), feature = "alloc"))]
extern crate alloc;

// Re-export everything from the core module for convenience
pub use diny_core::*;

// If the test serializer is enabled, pull it in as the 'test' module locally.
#[cfg(feature = "test")]
#[doc(hidden)]
pub mod test {
    pub use diny_test::*;
}