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 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
//! # Serde Flow - Migration Framework
//!
//! **The library assists you in smoothly deserializing the earlier versions of your serialized information.**
//!
//! ## Key Features
//!
//! - Versioning of serialize/deserialize entities
//! - Migration of serialized bytes
//! - Async migration
//! - Zerocopy deserialization
//! - Data Integrity Verification
//!
//! ## Modes of Operation
//!
//! Serde-Flow has two ways of working: File and Bytes. The File mode is good for when you want to work with files directly on your computer, while the Bytes mode is better for when you're working with data in your computer's memory. You can use them both at the same time if you need to.
//!
//! - File Mode
//! - Bytes Mode
//! - Both (use them together``#[flow(variant = 1, file, bytes)]``)
//!
//! #### File Mode
//!
//! The File mode helps you work with files on your computer. It can read data from a certain place on your computer, save and load information in files automatically, and can also help update files to the newest version. To use this mode, add a special instruction called ``#[flow(file)]`` above your code. This tells Serde-Flow to treat that part of your code as working with files.
//!
//! ##### Example Usage:
//!
//! ```rust
//! use serde::{Serialize, Deserialize};
//! use serde_flow::Flow;
//! use serde_flow::encoder::bincode;
//! use serde_flow::flow::{File, FileMigrate};
//! # use tempfile::tempdir;
//!
//! #[derive(Serialize, Deserialize, Flow)]
//! #[flow(variant = 1, file)]
//! struct MyStruct {
//! // Your struct fields here
//! field: String
//! }
//! # fn main() {
//! # let temp_dir = tempdir().unwrap();
//! # let path_buf = temp_dir.path().to_path_buf().join("car");
//! # let path = path_buf.as_path();
//! let object = MyStruct { field: "Something".to_string() };
//!
//! // save your object to path
//! object.save_to_path::<bincode::Encoder>(path).unwrap();
//! // load your object from the path
//! let object = MyStruct::load_from_path::<bincode::Encoder>(path).unwrap();
//! # }
//! ```
//!
//! ### 2. Bytes Mode
//!
//! The Bytes mode is for when you're working with computer memory instead of files. It's good for things like sending information between computers or saving data in a special way. To use this mode, add another special instruction called #[flow(bytes)] above your code. This tells Serde-Flow to treat that part of your code as working with computer memory.
//!
//! #### Example Usage:
//!
//! ```rust
//! use serde::{Serialize, Deserialize};
//! use serde_flow::Flow;
//! use serde_flow::encoder::bincode;
//! use serde_flow::flow::{Bytes};
//!
//! #[derive(Serialize, Deserialize, Flow)]
//! #[flow(variant = 1, bytes)]
//! struct MyStruct {
//! // Your struct fields here
//! field: String
//! }
//! # fn main() {
//! let object = MyStruct { field: "Something".to_string() };
//! // encode the object into bytes
//! let bytes = object.encode::<bincode::Encoder>().unwrap();
//! // decode the object from bytes
//! let object = MyStruct::decode::<bincode::Encoder>(&bytes).unwrap();
//! # }
//! ```
//! # Migrations
//!
//! To use *migrations*, you need to tell the program about different ways your data can be saved (called "variants"). Migrations works well with text formats, like JSON. To do this, add a special instruction called ``[#[variants(StructA, StructB, ...)]`` and list all the ways your data can be saved.
//!
//! ## Setup ``File Mode`` for Serde serialization
//!
//! Implements basic serde struct for serializing and deserializing User with version 1.
//!
//! ```rust
//! use serde::{Deserialize, Serialize};
//! use serde_flow::{Flow};
//!
//! #[derive(Flow, Serialize, Deserialize)]
//! #[flow(variant = 1, file)]
//! struct User {
//! name: String
//! }
//! ```
//!
//! ## Setup *async* ``File Mode`` for Serde serialization
//!
//! To read and write files using Serde asynchronously, add the ``nonblocking`` option to the ``file`` attribute in the flow instruction.
//!
//! ```rust
//! use serde::{Deserialize, Serialize};
//! use serde_flow::{Flow};
//!
//! #[derive(Flow, Serialize, Deserialize)]
//! #[flow(variant = 1, file(nonblocking))]
//! struct User {
//! name: String
//! }
//! ```
//!
//! ## Zerocopy
//!
//! To deserialize files or bytes using SerdeFlow without copying data, use the "rkyv" library in your project. Add three special instructions called ``rkyv::Serialize``, ``rkyv::Deserialize``, and ``rkyv::Archive`` to your code. This can also work asynchronously if needed.
//!
//! ```rust
//! use rkyv::{Archive, Deserialize, Serialize};
//! use serde_flow::{Flow};
//!
//! #[derive(Flow, Archive, Serialize, Deserialize)]
//! #[flow(variant = 1, file, zerocopy)]
//! #[archive(check_bytes)]
//! struct User {
//! name: String
//! }
//! ```
//!
//! ## Verify Write
//!
//! To make sure your files are saved correctly, you can use verification. Serde-Flow will save the information in a file and then check if the data is the same when it's loaded back. To use this, add the special instruction called ``verify_write`` to your code.
//!
//! ```rust
//! use serde::{Deserialize, Serialize};
//! use serde_flow::{Flow};
//!
//! #[derive(Flow, Serialize, Deserialize)]
//! #[flow(variant = 1, file(verify_write))]
//! struct User {
//! name: String
//! }
//! ```
//!
//! ## Usage
//!
//! You have to include some imports to use migrations.
//!
//! ### Blocking
//!
//! ```rust
//! use serde::{Deserialize, Serialize};
//! use serde_flow::{encoder::bincode, flow::File, flow::FileMigrate, Flow};
//! use serde_flow::flow::FlowResult;
//! # use tempfile::tempdir;
//!
//! #[derive(Flow, Serialize, Deserialize)]
//! #[flow(variant = 2, file(verify_write))]
//! #[variants(UserV1)]
//! struct User {
//! name: String
//! }
//!
//! #[derive(Flow, Serialize, Deserialize)]
//! #[flow(variant = 1, file(verify_write))]
//! struct UserV1 {
//! value: u16
//! }
//! impl From<UserV1> for User {
//! fn from(object: UserV1) -> User {
//! User { name: object.value.to_string() }
//! }
//! }
//! # fn main() -> FlowResult<()> {
//! # let temp_dir = tempdir().unwrap();
//! # let path_buf = temp_dir.path().to_path_buf().join("car");
//! # let path = path_buf.as_path();
//! // create an old user
//! let user = UserV1 { value: 123 };
//! user.save_to_path::<bincode::Encoder>(path)?;
//! // loading without updating stored User
//! let user = User::load_from_path::<bincode::Encoder>(path)?;
//! // loading with updating stored User
//! let user = User::load_and_migrate::<bincode::Encoder>(path)?;
//! // only migrating stored User
//! User::migrate::<bincode::Encoder>(path)?;
//!
//! # Ok(())
//! # }
//! ```
//!
//! ### Nonblocking
//!
//! ```rust
//! use serde::{Deserialize, Serialize};
//! use serde_flow::{encoder::bincode, flow::FileAsync, flow::FileMigrateAsync, Flow};
//! use serde_flow::flow::FlowResult;
//! # use tempfile::tempdir;
//! # #[derive(Flow, Serialize, Deserialize)]
//! # #[flow(variant = 2, file(nonblocking))]
//! # #[variants(UserV1)]
//! # struct User {
//! # name: String
//! # }
//! # #[derive(Flow, Serialize, Deserialize)]
//! # #[flow(variant = 1, file(nonblocking))]
//! # struct UserV1 {
//! # value: u16
//! # }
//! # impl From<UserV1> for User {
//! # fn from(object: UserV1) -> User {
//! # User { name: object.value.to_string() }
//! # }
//! # }
//! # #[tokio::main]
//! # async fn main() -> FlowResult<()> {
//! # let temp_dir = tempdir().unwrap();
//! # let path_buf = temp_dir.path().to_path_buf().join("car");
//! # let path = path_buf.as_path();
//!
//! // create an old user
//! let user = UserV1 { value: 123 };
//! user.save_to_path_async::<bincode::Encoder>(path).await?;
//!
//! let user = User::load_from_path_async::<bincode::Encoder>(path).await?;
//! let user = User::load_and_migrate_async::<bincode::Encoder>(path).await?;
//! User::migrate_async::<bincode::Encoder>(path).await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### Zerocopy
//!
//! This function makes a ``Reader<T>`` that can read information from files. Also, if you're using zero-copy, the ``load_from_path`` method updates the saved file automatically when it reads the information. The ``save_to_path`` method is the save.
//!
//! ```rust
//! use serde_flow::{flow::zerocopy::{File, FileMigrate}, Flow};
//! use rkyv::{Archive, Serialize, Deserialize};
//! # use tempfile::tempdir;
//!
//! #[derive(Flow, Archive, Serialize, Deserialize)]
//! #[archive(check_bytes)]
//! #[flow(variant = 1, file, zerocopy)]
//! struct User {
//! name: String
//! }
//!
//! # fn main() {
//! # let temp_dir = tempdir().unwrap();
//! # let path_buf = temp_dir.path().to_path_buf().join("car");
//! # let path = path_buf.as_path();
//! # let user = User { name: "Jan Janssen".to_string() };
//! # user.save_to_path(path).unwrap();
//! // Reader<User>
//! let user = User::load_from_path(path).unwrap();
//! # }
//! ```
//!
//! #### Reader
//!
//! With the ``Reader<T>`` trait, you can do two things: map exact bytes of the loaded file into immutable object (called "archive") or decode and copy information from a loaded file (called "deserialize"). The ``archive`` method uses zero-copy, while ``deserialize`` doesn't use it.
//!
//! ```rust
//! use serde_flow::{flow::zerocopy::File, Flow};
//! use rkyv::{Archive, Serialize, Deserialize};
//! # use serde_flow::flow::FlowResult;
//! # use tempfile::tempdir;
//!
//! #[derive(Flow, Archive, Serialize, Deserialize)]
//! #[archive(check_bytes)]
//! #[flow(variant = 1, file, zerocopy)]
//! struct User {
//! name: String
//! }
//! # fn main() -> FlowResult<()> {
//! # let temp_dir = tempdir().unwrap();
//! # let path_buf = temp_dir.path().to_path_buf().join("car");
//! # let path = path_buf.as_path();
//! # let user = User { name: "Jan Janssen".to_string() };
//! # let _ = user.save_to_path(path)?;
//! let user_reader = User::load_from_path(path)?;
//! let user_archived = user_reader.archive()?;
//!
//! assert_eq!(user_archived.name, "Jan Janssen".to_string());
//! # Ok(())
//! # }
//! ```
//!
//! ### Zerocopy Non-blocking
//!
//! ```rust
//! use serde_flow::{flow::zerocopy::FileAsync, Flow};
//! use rkyv::{Archive, Serialize, Deserialize};
//! # use serde_flow::flow::FlowResult;
//! # use tempfile::tempdir;
//!
//! #[derive(Flow, Archive, Serialize, Deserialize)]
//! #[archive(check_bytes)]
//! #[flow(variant = 1, file(nonblocking), zerocopy)]
//! struct User {
//! name: String
//! }
//!
//! # #[tokio::main]
//! # async fn main() -> FlowResult<()> {
//! # let temp_dir = tempdir().unwrap();
//! # let path_buf = temp_dir.path().to_path_buf().join("car");
//! # let path = path_buf.clone();
//! # let user = User { name: "Jan Janssen".to_string() };
//! # let _ = user.save_to_path_async(path).await?;
//! # let path = path_buf.clone();
//! let user_reader = User::load_from_path_async(path).await?;
//!
//! # Ok(())
//! # }
//! ```
pub mod encoder;
pub mod error;
pub mod flow;
extern crate serde_flow_derive;
pub use serde_flow_derive::Flow;