├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── deltoid-derive ├── .gitignore ├── Cargo.toml ├── src │ ├── error.rs │ ├── gen │ │ ├── enums.rs │ │ ├── markers.rs │ │ ├── mod.rs │ │ └── structs.rs │ └── lib.rs └── tests │ ├── delta.rs │ ├── std__rc.rs │ └── std__sync.rs ├── deltoid-quickcheck-tests ├── Cargo.toml └── src │ └── main.rs └── deltoid ├── Cargo.toml └── src ├── arrays.rs ├── borrow.rs ├── boxed.rs ├── collections ├── btreemap.rs ├── btreeset.rs ├── hashmap.rs ├── hashset.rs ├── mod.rs └── vecdeque.rs ├── core.rs ├── error.rs ├── lib.rs ├── option.rs ├── range.rs ├── rc.rs ├── result.rs ├── snapshot ├── delta.rs ├── full.rs └── mod.rs ├── string.rs ├── sync ├── arc.rs ├── mod.rs └── rwlock.rs ├── tuple.rs └── vec.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Stable with rustfmt and clippy 13 | uses: actions-rs/toolchain@v1 14 | with: 15 | profile: minimal 16 | toolchain: stable 17 | components: rustfmt, clippy 18 | 19 | - name: Build deltoid 20 | working-directory: deltoid 21 | run: cargo build --verbose 22 | 23 | - name: Run tests for deltoid 24 | working-directory: deltoid 25 | run: cargo test --verbose 26 | 27 | - name: Build deltoid (--features="snapshot") 28 | working-directory: deltoid 29 | run: cargo build --verbose --features="snapshot" 30 | 31 | - name: Run tests for deltoid (--features="snapshot") 32 | working-directory: deltoid 33 | run: cargo test --verbose --features="snapshot" 34 | 35 | - name: Build deltoid-derive 36 | working-directory: deltoid-derive 37 | run: cargo build --verbose 38 | 39 | - name: Run tests for deltoid-derive 40 | working-directory: deltoid-derive 41 | run: cargo test --verbose 42 | 43 | # NOTE: Don't perform "snapshot" builds for the `deltoid-derive` crate, 44 | # as that feature is only available for the `deltoid` crate. 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target 2 | deltoid-derive/expanded 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "./deltoid/", 4 | "./deltoid-derive/", 5 | "./deltoid-quickcheck-tests/", 6 | ] 7 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deltoid 2 | 3 | ![Rust](https://github.com/jjpe/deltoid/workflows/Rust/badge.svg) 4 | [![](https://img.shields.io/crates/v/deltoid?label=deltoid)](https://crates.io/crates/deltoid) 5 | [![](https://img.shields.io/crates/v/deltoid-derive?label=deltoid-derive)](https://crates.io/crates/deltoid-derive) 6 | ![](https://img.shields.io/badge/rustc-1.51+-darkcyan.svg) 7 | ![](https://img.shields.io/crates/l/deltoid) 8 | 9 | ## Synopsis 10 | 11 | **Deltoid** is a type-driven rust library that can be used to calculate [deltas]. 12 | A delta `Δ` can be calculated between 2 values `a` and `b` of the same type. 13 | Once calculated, `Δ` can then be applied to the first value `a` to obtain a new 14 | value `c` that is equivalent to the second value `b`. 15 | 16 | A primary use case for calculating delta's is to keep track of a sequence of 17 | related and potentially deeply-nested data trees while making sure to keep 18 | resource consumption (e.g. RAM, network bandwidth) reasonable. Since such a 19 | sequence may be exported for further processing, delta's are by definition 20 | de/serializable. This allows you to collect the data in once place as a 21 | sequence of delta's, export it (perhaps over a network connection), and then 22 | reconstruct the original sequence on the receiving side by successively 23 | applying the delta's in the sequence. 24 | 25 | [deltas]: https://en.wikipedia.org/wiki/Delta_encoding 26 | 27 | ## Usage 28 | 29 | Add this to your `Cargo.toml`: 30 | 31 | ```toml 32 | [dependencies] 33 | deltoid = "0.11.1" 34 | deltoid-derive = "0.11.1" 35 | ``` 36 | 37 | Computing a delta, then applying it: 38 | 39 | ``` rust 40 | use deltoid::Deltoid; 41 | use serde_derive::{Deserialize, Serialize}; 42 | 43 | #[derive(Deserialize, Serialize, Deltoid)] 44 | struct Point { 45 | x: usize, 46 | y: usize, 47 | } 48 | 49 | fn main() { 50 | // Define 2 instances of the same type 51 | let point0 = Point { x: 0, y: 0 }; 52 | let point1 = Point { x: 42, y: 8 }; 53 | 54 | // Calculate the delta between them 55 | let delta = point0.delta(&point1).unwrap(); 56 | 57 | // Apply the delta to `point0` 58 | let point2 = point0.apply(delta).unwrap(); 59 | assert_eq!(point1, point2); 60 | } 61 | ``` 62 | 63 | ## Limitations 64 | 65 | There are some limitations to this library: 66 | 67 | 1. Unions are not supported. Only `struct`s and `enum`s are currently supported. 68 | 69 | 2. The derive macro tries to accommodate generic types, but for types making 70 | use of advanced generics a manual implementation is generally recommended 71 | over using `deltoid-derive` because it allows for finer control. 72 | 73 | 3. Types that have fields that have a borrow type (i.e. `&T` and `&mut T` 74 | for some type `T`) are not currently supported. This limitation *may* 75 | be lifted in the future for mutable borrows, but is pretty fundamental 76 | for immutable borrows. 77 | 78 | 4. It's possible that while developing you notice that a set of impls is missing 79 | for a type in Rust's `stdlib`. If so, this is because support for types that 80 | are a part of `stdlib` must be added manually and simply hasn't been done yet. 81 | You can file an issue for that, or even better, send a PR :) 82 | 83 | 84 | ## Special Thanks 85 | 86 | A special thanks to [Accept B.V.](https://www.acc.nl/) for sponsoring this project. 87 | -------------------------------------------------------------------------------- /deltoid-derive/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /deltoid-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deltoid-derive" 3 | version = "0.12.0" 4 | authors = ["Joey Ezechiels "] 5 | edition = "2018" 6 | description = "Derive macro that generates code to calculate and apply deltas to structs and enums" 7 | repository = "https://github.com/jjpe/deltoid" 8 | license = "MIT OR Apache-2.0" 9 | readme = "../README.md" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | deltoid = { path = "../deltoid", version = "0.12.0" } 15 | proc-macro2 = "1.0.56" 16 | quote = "1.0.26" 17 | serde = "1.0.160" 18 | serde_derive = "1.0.160" 19 | syn = { version = "1.0.109", features = ["extra-traits", "parsing"] } 20 | 21 | [dev-dependencies] 22 | serde_json = "1.0" 23 | 24 | [lib] 25 | proc-macro = true 26 | 27 | [features] 28 | dump-expansions--unstable = [] # Write generated expansions to files. 29 | print-expansions--unstable = [] # Print generated expansions to stdout. 30 | -------------------------------------------------------------------------------- /deltoid-derive/src/error.rs: -------------------------------------------------------------------------------- 1 | //! Defines error infrastructure. 2 | 3 | use serde_derive::{Deserialize, Serialize}; 4 | 5 | #[allow(unused)] 6 | macro_rules! ensure { 7 | ($predicate:expr) => { 8 | if $predicate { 9 | DeriveResult::Ok(()) 10 | } else { 11 | use $crate::error::{DeriveError, DeriveResult}; 12 | DeriveResult::Err(DeriveError::FailedToEnsure { 13 | predicate: stringify!($predicate), 14 | file: file!(), 15 | line: line!(), 16 | column: column!(), 17 | }) 18 | } 19 | }; 20 | } 21 | 22 | 23 | #[allow(unused)] 24 | macro_rules! bug_detected { 25 | () => { 26 | Err($crate::error::DeriveError::BugDetected { 27 | file: file!(), 28 | line: line!(), 29 | column: column!(), 30 | }) 31 | }; 32 | } 33 | 34 | pub type DeriveResult = Result; 35 | 36 | 37 | #[derive(Clone, Debug, Deserialize, Serialize)] 38 | pub enum DeriveError { 39 | BugDetected { 40 | file: &'static str, 41 | line: u32, 42 | column: u32 43 | }, 44 | ExpectedNamedField, 45 | ExpectedPositionalField, 46 | FailedToEnsure { 47 | predicate: &'static str, 48 | file: &'static str, 49 | line: u32, 50 | column: u32 51 | }, 52 | 53 | // Add more error variants here 54 | } 55 | -------------------------------------------------------------------------------- /deltoid-derive/src/gen/markers.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use proc_macro2::{ 4 | Delimiter as Delimiter2, 5 | TokenTree as TokenTree2 6 | }; 7 | use syn::*; 8 | 9 | 10 | /// A `field` in the input struct or input enum variant 11 | /// is marked with #[delta(ignore_field)]. 12 | pub(crate) fn ignore_field(field: &Field) -> bool { 13 | let mut ignore = false; 14 | for attr in field.attrs.iter() { 15 | let attr_segments: Vec = attr.path.segments.iter() 16 | .map(|path_segment| format!("{}", path_segment.ident)) 17 | .collect(); 18 | let is_delta_attr = attr_segments == &["delta"]; 19 | let arg_tokens_iter = attr.tokens.clone().into_iter().next(); 20 | const DELIM: Delimiter2 = Delimiter2::Parenthesis; 21 | let arg_is_ignore_field = match arg_tokens_iter { 22 | Some(TokenTree2::Group(g)) if g.delimiter() == DELIM => { 23 | let tokens: Vec = g.stream().clone().into_iter() 24 | .map(|tt| format!("{}", tt)) 25 | .collect(); 26 | tokens == &["ignore_field"] 27 | }, 28 | _ => false, 29 | }; 30 | ignore = ignore || is_delta_attr && arg_is_ignore_field 31 | } 32 | ignore 33 | } 34 | -------------------------------------------------------------------------------- /deltoid-derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | 3 | #[macro_use] mod error; 4 | mod gen; 5 | 6 | use crate::error::{DeriveError, DeriveResult}; 7 | use crate::gen::InputType; 8 | use proc_macro::TokenStream; 9 | use proc_macro2::{TokenStream as TokenStream2}; 10 | #[cfg(feature = "dump-expansions--unstable")] 11 | use proc_macro2::{Ident as Ident2}; 12 | use quote::quote; 13 | #[cfg(feature = "dump-expansions--unstable")] 14 | use std::fs::{remove_file, File, OpenOptions}; 15 | #[cfg(feature = "dump-expansions--unstable")] 16 | use std::io::Write; 17 | #[cfg(feature = "dump-expansions--unstable")] 18 | use std::path::{Path, PathBuf}; 19 | use syn::{parse_macro_input, DeriveInput}; 20 | 21 | 22 | #[proc_macro_derive(Delta, attributes(delta))] 23 | pub fn derive(input: TokenStream) -> TokenStream { 24 | let input = parse_macro_input!(input as DeriveInput); 25 | let output: TokenStream2 = derive_internal(input).unwrap( 26 | // This is a HACK that allows more ergonomic code for the meat of 27 | // the macro while still conforming to the required macro signature. 28 | ); 29 | TokenStream::from(output) 30 | } 31 | 32 | #[allow(non_snake_case)] 33 | fn derive_internal(input: DeriveInput) -> DeriveResult { 34 | let input_type: InputType = InputType::parse(&input)?; 35 | let delta_type_definition = input_type.define_delta_type()?; 36 | let impl_Debug = input_type.define_Debug_impl()?; 37 | let impl_Core = input_type.define_Core_impl()?; 38 | let impl_Apply = input_type.define_Apply_impl()?; 39 | let impl_Delta = input_type.define_Delta_impl()?; 40 | let impl_FromDelta = input_type.define_FromDelta_impl()?; 41 | let impl_IntoDelta = input_type.define_IntoDelta_impl()?; 42 | let output: TokenStream2 = quote! { 43 | #delta_type_definition 44 | #impl_Debug 45 | #impl_Core 46 | #impl_Apply 47 | #impl_Delta 48 | #impl_FromDelta 49 | #impl_IntoDelta 50 | }; 51 | 52 | #[cfg(feature = "print-expansions--unstable")] 53 | print_generated_code( 54 | &delta_type_definition, 55 | &impl_Debug, 56 | &impl_Core, 57 | &impl_Apply, 58 | &impl_Delta, 59 | &impl_FromDelta, 60 | &impl_IntoDelta, 61 | ); 62 | 63 | #[cfg(feature = "dump-expansions--unstable")] 64 | write_generated_code_to_file( 65 | input_type.type_name()?, 66 | &delta_type_definition, 67 | &impl_Debug, 68 | &impl_Core, 69 | &impl_Apply, 70 | &impl_Delta, 71 | &impl_FromDelta, 72 | &impl_IntoDelta, 73 | ); 74 | 75 | Ok(output) 76 | } 77 | 78 | #[cfg(feature = "print-expansions--unstable")] 79 | #[allow(unused, non_snake_case)] 80 | fn print_generated_code( 81 | delta_type_definition: &TokenStream2, 82 | impl_Debug: &TokenStream2, 83 | impl_Core: &TokenStream2, 84 | impl_Apply: &TokenStream2, 85 | impl_Delta: &TokenStream2, 86 | impl_FromDelta: &TokenStream2, 87 | impl_IntoDelta: &TokenStream2, 88 | ) { 89 | println!("{}\n", delta_type_definition); 90 | println!("{}\n", impl_Debug); 91 | println!("{}\n", impl_Core); 92 | println!("{}\n", impl_Apply); 93 | println!("{}\n", impl_Delta); 94 | println!("{}\n", impl_FromDelta); 95 | println!("{}\n", impl_IntoDelta); 96 | println!("\n\n\n\n"); 97 | } 98 | 99 | #[cfg(feature = "dump-expansions--unstable")] 100 | #[allow(unused, non_snake_case)] 101 | fn write_generated_code_to_file( 102 | type_name: &Ident2, 103 | delta_type_definition: &TokenStream2, 104 | impl_Debug: &TokenStream2, 105 | impl_Core: &TokenStream2, 106 | impl_Apply: &TokenStream2, 107 | impl_Delta: &TokenStream2, 108 | impl_FromDelta: &TokenStream2, 109 | impl_IntoDelta: &TokenStream2, 110 | ) { 111 | let manifest_dir: &Path = Path::new(env!("CARGO_MANIFEST_DIR")); 112 | let expanded_dir: PathBuf = manifest_dir.join("expanded"); 113 | let filename: PathBuf = expanded_dir.join(&format!("{}.rs", type_name)); 114 | 115 | create_dir(&expanded_dir); 116 | let _ = remove_file(&filename); 117 | let mut file: File = open_file(&filename); 118 | println!("wrote {}", filename.display()); 119 | 120 | file.write_all(format!("{}", delta_type_definition).as_bytes()) 121 | .expect("Failed to write delta_type_definition"); 122 | file.write_all("\n\n".as_bytes()).expect("Failed to write newlines"); 123 | 124 | file.write_all(format!("{}", impl_Debug).as_bytes()) 125 | .expect("Failed to write impl_Debug"); 126 | file.write_all("\n\n".as_bytes()).expect("Failed to write newlines"); 127 | 128 | file.write_all(format!("{}", impl_Core).as_bytes()) 129 | .expect("Failed to write impl_Core"); 130 | file.write_all("\n\n".as_bytes()).expect("Failed to write newlines"); 131 | 132 | file.write_all(format!("{}", impl_Apply).as_bytes()) 133 | .expect("Failed to write impl_Apply"); 134 | file.write_all("\n\n".as_bytes()).expect("Failed to write newlines"); 135 | 136 | file.write_all(format!("{}", impl_Delta).as_bytes()) 137 | .expect("Failed to write impl_Delta"); 138 | file.write_all("\n\n".as_bytes()).expect("Failed to write newlines"); 139 | 140 | file.write_all(format!("{}", impl_FromDelta).as_bytes()) 141 | .expect("Failed to write impl_FromDelta"); 142 | file.write_all("\n\n".as_bytes()).expect("Failed to write newlines"); 143 | 144 | file.write_all(format!("{}", impl_IntoDelta).as_bytes()) 145 | .expect("Failed to write impl_IntoDelta"); 146 | file.write_all("\n\n".as_bytes()).expect("Failed to write newlines"); 147 | 148 | file.flush().expect(&format!("Failed to flush {}", filename.display())); 149 | std::process::Command::new("rustfmt") 150 | .args(&[ 151 | "--emit", "files", "--edition", "2018", 152 | &format!("{}", filename.display()) 153 | ]) 154 | .output() 155 | .expect("failed to execute rustfmt;"); 156 | } 157 | 158 | #[cfg(feature = "dump-expansions--unstable")] 159 | fn create_dir>(path: P) { 160 | let path = path.as_ref(); 161 | std::fs::DirBuilder::new() 162 | .recursive(true) 163 | .create(path) 164 | .expect(&format!("Failed to create dir {}", path.display())); 165 | } 166 | 167 | #[cfg(feature = "dump-expansions--unstable")] 168 | fn open_file>(path: P) -> File { 169 | let path = path.as_ref(); 170 | OpenOptions::new() 171 | .create_new(true) 172 | .write(true) 173 | .truncate(true) 174 | .open(path) 175 | .expect(&format!("Failed to open {}", path.display())) 176 | } 177 | -------------------------------------------------------------------------------- /deltoid-derive/tests/delta.rs: -------------------------------------------------------------------------------- 1 | //! 2 | #![allow(non_snake_case)] 3 | 4 | #[allow(unused)] use deltoid::{ 5 | Core, Apply, Delta, DeltaResult, FromDelta, IntoDelta, 6 | BoolDelta, StringDelta, U8Delta, UnitDelta, 7 | }; 8 | use deltoid_derive::Delta; 9 | use serde_derive::{Deserialize, Serialize}; 10 | use std::fmt::Debug; 11 | 12 | 13 | #[derive(Clone, Debug, PartialEq, Delta, Deserialize, Serialize)] 14 | pub enum Qux1 { 15 | Blah { #[delta(ignore_field)] one: u8, two: () }, 16 | Floof(u8, T), 17 | Flah { one: Box> }, 18 | Gah, 19 | } 20 | 21 | #[derive(Clone, Debug, PartialEq, Delta, Deserialize, Serialize)] 22 | pub enum Qux2 { 23 | Floof(#[delta(ignore_field)] u8, T), 24 | Blah { #[delta(ignore_field)] one: u8, two: U }, 25 | Flah { one: Box> }, 26 | Gah, 27 | } 28 | 29 | #[derive(Clone, Debug, PartialEq, Delta, Deserialize, Serialize)] 30 | enum Corge { 31 | Quux, 32 | Grault(u8, T), 33 | Floof { 34 | one: u8, 35 | two: T, 36 | three: U 37 | }, 38 | } 39 | 40 | #[derive(Clone, Debug, PartialEq, Default, Delta, Deserialize, Serialize)] 41 | pub struct Foo0 where F: Copy { 42 | #[delta(ignore_field)] 43 | f0: (), 44 | f1: F, 45 | f2: String, 46 | } 47 | 48 | #[derive(Clone, Debug, PartialEq, Default, Delta, Deserialize, Serialize)] 49 | pub struct Bar(u8, S) 50 | where S: std::fmt::Debug + Default; 51 | 52 | #[derive(Clone, Debug, PartialEq, Default, Delta, Deserialize, Serialize)] 53 | pub struct Baz; 54 | 55 | #[derive(Clone, Debug, PartialEq, Default, Delta, Deserialize, Serialize)] 56 | pub struct Plow(std::borrow::Cow<'static, String>); 57 | 58 | 59 | 60 | 61 | 62 | 63 | #[test] 64 | pub fn enum_struct_variant__delta__same_values() -> DeltaResult<()> { 65 | let val0: Qux2 = Qux2::Blah { one: 42u8, two: () }; 66 | let val1: Qux2 = Qux2::Blah { one: 42u8, two: () }; 67 | let delta = val0.delta(&val1)?; 68 | let expected = Qux2Delta::Blah { one: std::marker::PhantomData, two: None }; 69 | assert_eq!(delta, expected, "{:#?} != {:#?}", delta, expected); 70 | Ok(()) 71 | } 72 | 73 | #[test] 74 | pub fn enum_struct_variant__apply__same_values() -> DeltaResult<()> { 75 | let val0: Qux2 = Qux2::Blah { one: 42u8, two: () }; 76 | let delta = Qux2Delta::Blah { one: std::marker::PhantomData, two: None }; 77 | let val1 = val0.apply(delta)?; 78 | let expected: Qux2 = Qux2::Blah { one: 42u8, two: () }; 79 | assert_eq!(val1, expected, "{:#?} != {:#?}", val1, expected); 80 | Ok(()) 81 | } 82 | 83 | #[test] 84 | pub fn enum_struct_variant__delta__different_values() -> DeltaResult<()> { 85 | let val0: Qux2 = Qux2::Blah { one: 42u8, two: () }; 86 | let val1: Qux2 = Qux2::Blah { one: 100u8, two: () }; 87 | let delta = val0.delta(&val1)?; 88 | let expected = Qux2Delta::Blah { 89 | one: std::marker::PhantomData, 90 | two: None 91 | }; 92 | assert_eq!(delta, expected, "{:#?} != {:#?}", delta, expected); 93 | Ok(()) 94 | } 95 | 96 | #[test] 97 | pub fn enum_struct_variant__apply__different_values() -> DeltaResult<()> { 98 | let val0: Qux2 = Qux2::Blah { one: 42u8, two: () }; 99 | let delta = Qux2Delta::Blah { 100 | one: std::marker::PhantomData, 101 | two: None 102 | }; 103 | let val1 = val0.apply(delta)?; 104 | let expected: Qux2 = Qux2::Blah { one: 42u8, two: () }; 105 | assert_eq!(val1, expected, "{:#?} != {:#?}", val1, expected); 106 | Ok(()) 107 | } 108 | 109 | 110 | 111 | 112 | #[test] 113 | pub fn enum_tuple_struct_variant__delta__same_values() -> DeltaResult<()> { 114 | let val0: Qux2 = Qux2::Floof(42, String::from("foo")); 115 | let val1: Qux2 = Qux2::Floof(42, String::from("foo")); 116 | let delta = val0.delta(&val1)?; 117 | let expected = Qux2Delta::Floof(std::marker::PhantomData, None); 118 | assert_eq!(delta, expected, "{:#?} != {:#?}", delta, expected); 119 | Ok(()) 120 | } 121 | 122 | #[test] 123 | pub fn enum_tuple_struct_variant__apply__same_values() -> DeltaResult<()> { 124 | let val0: Qux2 = Qux2::Floof(42, String::from("foo")); 125 | let delta = Qux2Delta::Floof(std::marker::PhantomData, None); 126 | let val1 = val0.apply(delta)?; 127 | let expected: Qux2 = Qux2::Floof(42, String::from("foo")); 128 | assert_eq!(val1, expected, "{:#?} != {:#?}", val1, expected); 129 | Ok(()) 130 | } 131 | 132 | #[test] 133 | pub fn enum_tuple_struct_variant__delta__different_values() -> DeltaResult<()> { 134 | let val0: Qux2 = Qux2::Floof(42, String::from("foo")); 135 | let val1: Qux2 = Qux2::Floof(50, String::from("bar")); 136 | let delta = val0.delta(&val1)?; 137 | let expected = Qux2Delta::Floof( 138 | std::marker::PhantomData, 139 | Some(StringDelta(Some("bar".into()))) 140 | ); 141 | assert_eq!(delta, expected, "{:#?} != {:#?}", delta, expected); 142 | Ok(()) 143 | } 144 | 145 | #[test] 146 | pub fn enum_tuple_struct_variant__apply__different_values() -> DeltaResult<()> { 147 | let val0: Qux2 = Qux2::Floof(42, String::from("foo")); 148 | let delta = Qux2Delta::Floof( 149 | std::marker::PhantomData, 150 | Some(StringDelta(Some("bar".into()))) 151 | ); 152 | let val1 = val0.apply(delta)?; 153 | let expected: Qux2 = Qux2::Floof(42, String::from("bar")); 154 | assert_eq!(val1, expected, "{:#?} != {:#?}", val1, expected); 155 | Ok(()) 156 | } 157 | 158 | 159 | 160 | 161 | #[test] 162 | pub fn enum_unit_struct_variant__delta() -> DeltaResult<()> { 163 | let val0: Qux2 = Qux2::Gah; 164 | let val1: Qux2 = Qux2::Gah; 165 | let delta = val0.delta(&val1)?; 166 | let expected = Qux2Delta::Gah; 167 | assert_eq!(delta, expected, "{:#?} != {:#?}", delta, expected); 168 | Ok(()) 169 | } 170 | 171 | #[test] 172 | pub fn enum_unit_struct_variant__apply() -> DeltaResult<()> { 173 | let val0: Qux2 = Qux2::Gah; 174 | let delta = Qux2Delta::Gah; 175 | let val1 = val0.apply(delta)?; 176 | let expected: Qux2 = Qux2::Gah; 177 | assert_eq!(val1, expected, "{:#?} != {:#?}", val1, expected); 178 | Ok(()) 179 | } 180 | 181 | 182 | 183 | 184 | #[test] 185 | pub fn struct__delta__same_values() -> DeltaResult<()> { 186 | let val0: Foo0 = Foo0 { 187 | f0: (), 188 | f1: 42 as u16, 189 | f2: "hello world".into() 190 | }; 191 | let val1: Foo0 = Foo0 { 192 | f0: (), 193 | f1: 300, 194 | f2: "hello world!!!".into() 195 | }; 196 | let delta: Foo0Delta = val0.delta(&val1)?; 197 | let expected: Foo0Delta = Foo0Delta { 198 | f0: std::marker::PhantomData, 199 | f1: Some(300u16.into_delta()?), 200 | f2: Some("hello world!!!".to_string().into_delta()?), 201 | }; 202 | assert_eq!(delta, expected, "{:#?} != {:#?}", delta, expected); 203 | Ok(()) 204 | } 205 | 206 | #[test] 207 | pub fn struct__apply__same_values() -> DeltaResult<()> { 208 | let val0: Foo0 = Foo0 { 209 | f0: (), 210 | f1: 42 as u16, 211 | f2: "hello world".into() 212 | }; 213 | let delta: Foo0Delta = Foo0Delta { 214 | f0: std::marker::PhantomData, 215 | f1: Some(300u16.into_delta()?), 216 | f2: Some("hello world!!!".to_string().into_delta()?), 217 | }; 218 | let val1 = val0.apply(delta)?; 219 | let expected: Foo0 = Foo0 { 220 | f0: (), 221 | f1: 300, 222 | f2: String::from("hello world!!!") 223 | }; 224 | assert_eq!(val1, expected, "{:#?} != {:#?}", val1, expected); 225 | Ok(()) 226 | } 227 | 228 | #[test] 229 | pub fn struct__delta__different_values() -> DeltaResult<()> { 230 | let val0: Foo0 = Foo0 { 231 | f0: (), 232 | f1: 42 as u16, 233 | f2: "hello world".into() 234 | }; 235 | let val1: Foo0 = Foo0 { 236 | f0: (), 237 | f1: 300, 238 | f2: "hai world".into() 239 | }; 240 | let delta: Foo0Delta = val0.delta(&val1)?; 241 | let expected: Foo0Delta = Foo0Delta { 242 | f0: std::marker::PhantomData, 243 | f1: Some(300u16.into_delta()?), 244 | f2: Some("hai world".to_string().into_delta()?), 245 | }; 246 | assert_eq!(delta, expected, "{:#?} != {:#?}", delta, expected); 247 | Ok(()) 248 | } 249 | 250 | #[test] 251 | pub fn struct__apply__different_values() -> DeltaResult<()> { 252 | let val0: Foo0 = Foo0 { 253 | f0: (), 254 | f1: 42 as u16, 255 | f2: "hello world".into() 256 | }; 257 | let delta: Foo0Delta = Foo0Delta { 258 | f0: std::marker::PhantomData, 259 | f1: Some(300u16.into_delta()?), 260 | f2: Some("hai world".to_string().into_delta()?), 261 | }; 262 | let val1 = val0.apply(delta)?; 263 | let expected: Foo0 = Foo0 { 264 | f0: (), 265 | f1: 300, 266 | f2: "hai world".into() 267 | }; 268 | assert_eq!(val1, expected, "{:#?} != {:#?}", val1, expected); 269 | Ok(()) 270 | } 271 | 272 | 273 | 274 | 275 | #[test] 276 | pub fn tuple_struct__delta__same_values() -> DeltaResult<()> { 277 | let val0: Bar = Bar(42u8, 70u16); 278 | let val1: Bar = Bar(42u8, 70u16); 279 | let delta: BarDelta = val0.delta(&val1)?; 280 | let expected: BarDelta = BarDelta(None, None); 281 | assert_eq!(delta, expected, "{:#?} != {:#?}", delta, expected); 282 | Ok(()) 283 | } 284 | 285 | #[test] 286 | pub fn tuple_struct__apply__same_values() -> DeltaResult<()> { 287 | let val0: Bar = Bar(42u8, 70u16); 288 | let delta: BarDelta = BarDelta( 289 | Some(100u8.into_delta()?), 290 | Some(300u16.into_delta()?), 291 | ); 292 | let val1: Bar = val0.apply(delta)?; 293 | let expected: Bar = Bar(100u8, 300u16); 294 | assert_eq!(val1, expected, "{:#?} != {:#?}", val1, expected); 295 | Ok(()) 296 | } 297 | 298 | #[test] 299 | pub fn tuple_struct__delta__different_values() -> DeltaResult<()> { 300 | let val0: Bar = Bar( 42u8, 70u16); 301 | let val1: Bar = Bar(100u8, 300u16); 302 | let delta: BarDelta = val0.delta(&val1)?; 303 | let expected: BarDelta = BarDelta( 304 | Some(100u8.into_delta()?), 305 | Some(300u16.into_delta()?), 306 | ); 307 | assert_eq!(delta, expected, "{:#?} != {:#?}", delta, expected); 308 | Ok(()) 309 | } 310 | 311 | #[test] 312 | pub fn tuple_struct__apply__different_values() -> DeltaResult<()> { 313 | let val0: Bar = Bar(42u8, 70u16); 314 | let delta: BarDelta = BarDelta( 315 | Some(100u8.into_delta()?), 316 | Some(300u16.into_delta()?), 317 | ); 318 | let val1: Bar = val0.apply(delta)?; 319 | let expected: Bar = Bar(100u8, 300u16); 320 | assert_eq!(val1, expected, "{:#?} != {:#?}", val1, expected); 321 | Ok(()) 322 | } 323 | 324 | 325 | 326 | 327 | #[test] 328 | pub fn unit_struct__delta() -> DeltaResult<()> { 329 | let val0 = Baz; 330 | let val1 = Baz; 331 | let delta: BazDelta = val0.delta(&val1)?; 332 | let expected = BazDelta; 333 | assert_eq!(delta, expected, "{:#?} != {:#?}", delta, expected); 334 | Ok(()) 335 | } 336 | 337 | #[test] 338 | pub fn unit_struct__apply() -> DeltaResult<()> { 339 | let val0 = Baz; 340 | let delta = BazDelta; 341 | let val1: Baz = val0.apply(delta)?; 342 | let expected = Baz; 343 | assert_eq!(val1, expected, "{:#?} != {:#?}", val1, expected); 344 | Ok(()) 345 | } 346 | 347 | 348 | 349 | 350 | #[test] 351 | pub fn nested_data__delta() -> DeltaResult<()> { 352 | let val0: Corge, ()> = Corge::Grault( 353 | 42u8, 354 | Corge::Floof { one: 100u8, two: (), three: true } 355 | ); 356 | let val1: Corge, ()> = Corge::Grault( 357 | 40u8, 358 | Corge::Floof { one: 72u8, two: (), three: true } 359 | ); 360 | let delta = val0.delta(&val1)?; 361 | let expected: CorgeDelta, ()> = CorgeDelta::Grault( 362 | Some(U8Delta(Some(40u8))), 363 | Some(CorgeDelta::Floof { 364 | one: Some(U8Delta(Some(72u8))), 365 | two: None, 366 | three: None 367 | }) 368 | ); 369 | assert_eq!(delta, expected, "{:#?} != {:#?}", delta, expected); 370 | Ok(()) 371 | } 372 | 373 | #[test] 374 | pub fn nested_data__apply() -> DeltaResult<()> { 375 | let val0: Corge, ()> = Corge::Grault( 376 | 42u8, 377 | Corge::Floof { one: 100u8, two: (), three: true } 378 | ); 379 | let delta: CorgeDelta<_, _> = CorgeDelta::Grault( 380 | Some(U8Delta(Some(40u8))), 381 | Some(CorgeDelta::Floof { 382 | one: Some(U8Delta(Some(72u8))), 383 | two: None, 384 | three: None, 385 | }) 386 | ); 387 | let val1 = val0.apply(delta)?; 388 | let expected: Corge, ()> = Corge::Grault( 389 | 40u8, 390 | Corge::Floof { one: 72u8, two: (), three: true } 391 | ); 392 | assert_eq!(val1, expected, "{:#?} != {:#?}", val1, expected); 393 | Ok(()) 394 | } 395 | -------------------------------------------------------------------------------- /deltoid-derive/tests/std__rc.rs: -------------------------------------------------------------------------------- 1 | //! Tests for the `std::rc` module 2 | #![allow(non_snake_case)] 3 | 4 | use std::rc::Rc; 5 | #[allow(unused)] use deltoid::{ 6 | Apply, Delta, DeltaResult, FromDelta, IntoDelta, RcDelta, StringDelta 7 | }; 8 | use deltoid_derive::Delta; 9 | use serde_derive::{Deserialize, Serialize}; 10 | 11 | 12 | #[derive(Clone, Debug, PartialEq, Eq, Delta, Deserialize, Serialize)] 13 | struct Foo1 { 14 | s: String, 15 | i: usize, 16 | } 17 | 18 | #[test] 19 | fn Rc__delta() -> DeltaResult<()> { 20 | let v0 = Rc::new(Foo1 { s: "hello world".to_string(), i: 42 }); 21 | let v1 = Rc::new(Foo1 { s: "hello world!!".to_string(), i: 42 }); 22 | let delta0 = v0.delta(&v1)?; 23 | println!("delta0: {:#?}", delta0); 24 | let expected = RcDelta(Some(Box::new(Foo1Delta { 25 | s: Some(StringDelta(Some("hello world!!".to_string()))), 26 | i: None, 27 | }))); 28 | assert_eq!(delta0, expected, "{:#?}\n !=\n{:#?}", delta0, expected); 29 | 30 | let v2 = v0.apply(delta0)?; 31 | println!("v2: {:#?}", v2); 32 | assert_eq!(v1, v2); 33 | 34 | let delta1 = v1.delta(&v0)?; 35 | println!("delta1: {:#?}", delta1); 36 | assert_eq!(delta1, RcDelta(Some(Box::new(Foo1Delta { 37 | s: Some(StringDelta(Some("hello world".to_string()))), 38 | i: None, 39 | })))); 40 | let v3 = v1.apply(delta1)?; 41 | println!("v3: {:#?}", v3); 42 | assert_eq!(v0, v3); 43 | 44 | Ok(()) 45 | } 46 | 47 | #[test] 48 | fn Rc__apply() -> DeltaResult<()> { 49 | let v0 = Rc::new(Foo1 { s: "hello world".to_string(), i: 42 }); 50 | let delta = RcDelta(Some(Box::new(Foo1Delta { 51 | s: Some(StringDelta(Some("hello world!!".to_string()))), 52 | i: None, 53 | }))); 54 | let v1 = v0.apply(delta)?; 55 | let expected = Rc::new(Foo1 { s: "hello world!!".to_string(), i: 42 }); 56 | assert_eq!(expected, v1); 57 | 58 | Ok(()) 59 | } 60 | -------------------------------------------------------------------------------- /deltoid-derive/tests/std__sync.rs: -------------------------------------------------------------------------------- 1 | //! These integration tests exist because the Delta derive macro cannot be 2 | //! used within the `struct-delta-trait` crate, where `RwLock` is defined. 3 | 4 | #![allow(non_snake_case)] 5 | 6 | #[allow(unused)] use deltoid::{ 7 | Apply, Delta, DeltaResult, FromDelta, IntoDelta, 8 | ArcDelta, RwLock, RwLockDelta, StringDelta 9 | }; 10 | use deltoid_derive::Delta; 11 | use serde_json; 12 | use serde_derive::{Deserialize, Serialize}; 13 | use std::sync::Arc; 14 | 15 | #[derive(Debug, Clone, PartialEq, Eq, Delta, Deserialize, Serialize)] 16 | struct Foo { 17 | field0: String, 18 | field1: u8 19 | } 20 | 21 | #[test] 22 | fn RwLock__serialize() { 23 | let value: RwLock = RwLock::new(Foo { 24 | field0: "flapjacks are fun".to_string(), 25 | field1: 42, 26 | }); 27 | println!("value: {:#?}", value); 28 | 29 | let serialized: String = serde_json::to_string(&value) 30 | .unwrap(/*TODO*/); 31 | println!("serialized:\n{}", serialized); 32 | 33 | let expected = r#"{"field0":"flapjacks are fun","field1":42}"#; 34 | println!("expected: {:#?}", expected); 35 | 36 | assert_eq!(serialized, expected); 37 | } 38 | 39 | #[test] 40 | fn RwLock__deserialize() { 41 | let serialized = r#"{"field0":"flapjacks are fun","field1":42}"#; 42 | println!("serialized:\n{}", serialized); 43 | 44 | let deserialized: RwLock = serde_json::from_str(&serialized) 45 | .unwrap(/*TODO*/); 46 | println!("deserialized: {:#?}", deserialized); 47 | 48 | let expected: RwLock = RwLock::new(Foo { 49 | field0: "flapjacks are fun".to_string(), 50 | field1: 42, 51 | }); 52 | println!("expected: {:#?}", expected); 53 | 54 | assert_eq!(deserialized, expected); 55 | } 56 | 57 | #[test] 58 | fn RwLock__apply() { 59 | let value0: RwLock = RwLock::new(Foo { 60 | field0: "flapjacks are fun".to_string(), 61 | field1: 42, 62 | }); 63 | println!("value0: {:#?}", value0); 64 | 65 | let delta: RwLockDelta = RwLockDelta(Some(FooDelta { 66 | field0: Some( 67 | "flapjacks are fun?".to_string().into_delta().unwrap() 68 | ), 69 | field1: None, 70 | })); 71 | println!("delta: {:#?}", delta); 72 | 73 | let value1: RwLock = value0.apply(delta).unwrap(); 74 | println!("value1: {:#?}", value1); 75 | 76 | let expected: RwLock = RwLock::new(Foo { 77 | field0: "flapjacks are fun?".to_string(), 78 | field1: 42, 79 | }); 80 | println!("expected: {:#?}", expected); 81 | 82 | assert_eq!(value1, expected); 83 | } 84 | 85 | #[test] 86 | fn RwLock__delta() { 87 | let value0: RwLock = RwLock::new(Foo { 88 | field0: "flapjacks are fun".to_string(), 89 | field1: 42, 90 | }); 91 | println!("value0: {:#?}", value0); 92 | 93 | let value1: RwLock = RwLock::new(Foo { 94 | field0: "flapjacks are fun?".to_string(), 95 | field1: 42, 96 | }); 97 | println!("value1: {:#?}", value1); 98 | 99 | let delta = value0.delta(&value1).unwrap(); 100 | println!("delta: {:#?}", delta); 101 | 102 | let expected: RwLockDelta = RwLockDelta(Some(FooDelta { 103 | field0: Some( 104 | "flapjacks are fun?".to_string().into_delta().unwrap() 105 | ), 106 | field1: None, 107 | })); 108 | println!("expected: {:#?}", expected); 109 | 110 | assert_eq!(delta, expected); 111 | } 112 | 113 | 114 | 115 | 116 | 117 | #[test] 118 | fn Arc__delta() -> DeltaResult<()> { 119 | let v0 = Arc::new(Foo { field0: "hello world".to_string(), field1: 42 }); 120 | let v1 = Arc::new(Foo { field0: "hello world!!".to_string(), field1: 42 }); 121 | let delta0 = v0.delta(&v1)?; 122 | println!("delta0: {:#?}", delta0); 123 | let expected = ArcDelta(Some(Box::new(FooDelta { 124 | field0: Some(StringDelta(Some("hello world!!".to_string()))), 125 | field1: None, 126 | }))); 127 | assert_eq!(delta0, expected, "{:#?}\n !=\n{:#?}", delta0, expected); 128 | 129 | let v2 = v0.apply(delta0)?; 130 | println!("v2: {:#?}", v2); 131 | assert_eq!(v1, v2); 132 | 133 | let delta1 = v1.delta(&v0)?; 134 | println!("delta1: {:#?}", delta1); 135 | assert_eq!(delta1, ArcDelta(Some(Box::new(FooDelta { 136 | field0: Some(StringDelta(Some("hello world".to_string()))), 137 | field1: None, 138 | })))); 139 | let v3 = v1.apply(delta1)?; 140 | println!("v3: {:#?}", v3); 141 | assert_eq!(v0, v3); 142 | 143 | Ok(()) 144 | } 145 | 146 | #[test] 147 | fn Arc__apply() -> DeltaResult<()> { 148 | let v0 = Arc::new(Foo { field0: "hello world".to_string(), field1: 42 }); 149 | let delta = ArcDelta(Some(Box::new(FooDelta { 150 | field0: Some(StringDelta(Some("hello world!!".to_string()))), 151 | field1: None, 152 | }))); 153 | let v1 = v0.apply(delta)?; 154 | let expected = Arc::new(Foo { 155 | field0: "hello world!!".to_string(), 156 | field1: 42 157 | }); 158 | assert_eq!(expected, v1); 159 | 160 | Ok(()) 161 | } 162 | -------------------------------------------------------------------------------- /deltoid-quickcheck-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deltoid-quickcheck" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | deltoid = { path = "../deltoid" } 10 | deltoid-derive = { path = "../deltoid-derive" } 11 | serde_derive = "1.0" 12 | serde = "1.0" 13 | quickcheck = "1.0.3" 14 | quickcheck_macros = "1.0.0" 15 | quickcheck_derive = "0.3.0" 16 | rand = "0.8.5" 17 | -------------------------------------------------------------------------------- /deltoid-quickcheck-tests/src/main.rs: -------------------------------------------------------------------------------- 1 | use deltoid::{Apply, Delta}; 2 | use deltoid_derive::Delta; 3 | use quickcheck::quickcheck; 4 | use quickcheck_derive::Arbitrary; 5 | use serde_derive::{Deserialize, Serialize}; 6 | 7 | #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Delta)] 8 | #[derive(Serialize, Deserialize, Arbitrary)] 9 | pub struct Basic { 10 | pub field: Option, 11 | } 12 | 13 | fn tester(a: Basic, b: Basic) -> bool { 14 | // NOTE: The issue seems to be that currently there is no way to 15 | // tell the difference between these 2 situations after 16 | // calculating `let delta = a.delta(b).unwrap()`: 17 | // 1. There is no `delta` because `a == b` 18 | // 2. There is a delta, and it happens to be `None`. 19 | // This means that, when applied to a scalar value `a`, 20 | // `c` will also take a value which wraps `None`. 21 | // Both situations are currently encoded in `delta` by having 22 | // it wrap `None`. 23 | 24 | println!("a: {:?}", a); 25 | println!("b: {:?}", b); 26 | let delta = a.delta(&b).unwrap(); 27 | println!("delta: {:?}", delta); 28 | let c = a.apply(delta).unwrap(); 29 | println!("c: {:?}", c); 30 | println!("b == c: {:?}", b == c); 31 | println!(); 32 | return b == c; 33 | } 34 | 35 | fn main() { 36 | quickcheck(tester as fn(Basic, Basic) -> bool); 37 | } 38 | -------------------------------------------------------------------------------- /deltoid/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deltoid" 3 | version = "0.12.0" 4 | authors = ["Joey Ezechiels "] 5 | edition = "2018" 6 | description = "A library to calculate and apply deltas to structs and enums" 7 | repository = "https://github.com/jjpe/deltoid" 8 | license = "MIT OR Apache-2.0" 9 | readme = "../README.md" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | serde = { version = "1.0", features = ["rc"] } 15 | serde_derive = "1.0" 16 | 17 | [dependencies.chrono] 18 | version = "0.4.24" 19 | default-features = false 20 | features = ["clock", "serde"] 21 | optional = true 22 | 23 | [build-dependencies] 24 | 25 | [target.'cfg(target_arch = "wasm32")'.dependencies] 26 | wasm-bindgen = { version = "0.2", features = ["serde-serialize"] } 27 | js-sys = "0.3" 28 | web-sys = "0.3" 29 | 30 | [dev-dependencies] 31 | serde_json = "1.0" 32 | 33 | [features] 34 | snapshot = ["chrono"] 35 | -------------------------------------------------------------------------------- /deltoid/src/arrays.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use crate::{Apply, Core, Delta, DeltaResult, FromDelta, IntoDelta}; 4 | use serde::{Deserialize, Serialize}; 5 | use std::fmt::Debug; 6 | use std::mem::{self, MaybeUninit}; 7 | 8 | impl Core for [T; LEN] 9 | where T: Clone + Debug + PartialEq + Core 10 | + for<'de> Deserialize<'de> 11 | + Serialize 12 | { 13 | type Delta = ArrayDelta; 14 | } 15 | 16 | impl Apply for [T; LEN] 17 | where T: Apply + FromDelta 18 | + for<'de> Deserialize<'de> 19 | + Serialize 20 | { 21 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 22 | let mut new: [MaybeUninit; LEN] = 23 | unsafe { MaybeUninit::uninit().assume_init() }; 24 | let initialized: Vec = delta.0.iter() 25 | .map(|edit| edit.index) 26 | .collect(); 27 | // NOTE: initialize the delta `new[index]` cells: 28 | for Edit { delta: d, index } in delta.0 { 29 | new[index] = MaybeUninit::new(self[index].apply(d)?); 30 | } 31 | // NOTE: initialize the non-delta `new[index]` cells: 32 | for index in 0 .. LEN { 33 | if initialized.contains(&index) { continue } 34 | // NOTE: offset `new[index]` not yet initialized: 35 | let elt = unsafe { &mut *new[index].as_mut_ptr() }; 36 | *elt = self[index].clone(); 37 | } 38 | Ok(unsafe { array_assume_init(new) }) 39 | } 40 | } 41 | 42 | impl Delta for [T; LEN] 43 | where T: Delta + IntoDelta 44 | + for<'de> Deserialize<'de> 45 | + Serialize 46 | { 47 | fn delta(&self, rhs: &Self) -> DeltaResult { 48 | let mut delta = ArrayDelta(Vec::with_capacity(LEN)); 49 | for i in 0 .. LEN { 50 | if self[i] == rhs[i] { continue } 51 | delta.0.push(Edit { 52 | delta: self[i].delta(&rhs[i])?, 53 | index: i, 54 | }); 55 | } 56 | Ok(delta) 57 | } 58 | } 59 | 60 | impl FromDelta for [T; LEN] 61 | where T: Clone + Debug + PartialEq + FromDelta 62 | + for<'de> Deserialize<'de> 63 | + Serialize 64 | + Default 65 | { 66 | fn from_delta(delta: ::Delta) -> DeltaResult { 67 | let mut new: [MaybeUninit; LEN] = 68 | unsafe { MaybeUninit::uninit().assume_init() }; 69 | let initialized: Vec = delta.0.iter() 70 | .map(|edit| edit.index) 71 | .collect(); 72 | // NOTE: initialize the delta `new[index]` cells: 73 | for Edit { delta: d, index } in delta.0 { 74 | new[index] = MaybeUninit::new(::from_delta(d)?); 75 | } 76 | // NOTE: initialize the non-delta `new[index]` cells: 77 | for index in 0 .. LEN { 78 | if initialized.contains(&index) { continue } 79 | // NOTE: offset `new[index]` not yet initialized: 80 | let elt = unsafe { &mut *new[index].as_mut_ptr() }; 81 | *elt = T::default(); 82 | } 83 | Ok(unsafe { array_assume_init(new) }) 84 | } 85 | } 86 | 87 | impl IntoDelta for [T; LEN] 88 | where T: Clone + Debug + PartialEq + IntoDelta 89 | + for<'de> Deserialize<'de> 90 | + Serialize 91 | { 92 | fn into_delta(self) -> DeltaResult<::Delta> { 93 | let mut delta = ArrayDelta(Vec::with_capacity(LEN)); 94 | for index in 0 .. LEN { 95 | delta.0.push(Edit { 96 | delta: self[index].clone().into_delta()?, 97 | index, 98 | }); 99 | } 100 | Ok(delta) 101 | } 102 | } 103 | 104 | #[derive(Clone, Debug, PartialEq)] 105 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 106 | pub struct ArrayDelta ( 107 | #[doc(hidden)] pub Vec> 108 | ); 109 | 110 | #[derive(Clone, Debug, PartialEq)] 111 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 112 | pub struct Edit { 113 | delta: ::Delta, 114 | index: usize, 115 | } 116 | 117 | #[inline(never)] 118 | unsafe fn array_assume_init( 119 | array: [MaybeUninit; N] 120 | ) -> [T; N] { 121 | mem::transmute_copy(&array) 122 | } 123 | 124 | 125 | 126 | #[allow(non_snake_case)] 127 | #[cfg(test)] 128 | mod tests { 129 | use serde_json; 130 | use super::*; 131 | 132 | #[test] 133 | fn array_of_len_0__delta() -> DeltaResult<()> { 134 | let array0: [u16; 0] = []; 135 | let array1: [u16; 0] = []; 136 | let delta: <[u16; 0] as Core>::Delta = array0.delta(&array1)?; 137 | let json: String = serde_json::to_string(&delta) 138 | .expect("Could not serialize to json"); 139 | assert_eq!(json, "[]"); 140 | let delta1: <[u16; 0] as Core>::Delta = serde_json::from_str(&json) 141 | .expect("Could not deserialize from json"); 142 | assert_eq!(delta, delta1); 143 | Ok(()) 144 | } 145 | 146 | #[test] 147 | fn array_of_len_0__apply() -> DeltaResult<()> { 148 | let array0: [u16; 0] = []; 149 | let array1: [u16; 0] = []; 150 | let delta: <[u16; 0] as Core>::Delta = array0.delta(&array1)?; 151 | let array2 = array0.apply(delta)?; 152 | assert_eq!(array1, array2); 153 | Ok(()) 154 | } 155 | 156 | #[test] 157 | fn array_of_len_1__delta__same_values() -> DeltaResult<()> { 158 | let array0: [u16; 1] = [42]; 159 | let array1: [u16; 1] = [42]; 160 | let delta: <[u16; 1] as Core>::Delta = array0.delta(&array1)?; 161 | let json: String = serde_json::to_string(&delta) 162 | .expect("Could not serialize to json"); 163 | assert_eq!(json, "[]"); 164 | let delta1: <[u16; 1] as Core>::Delta = serde_json::from_str(&json) 165 | .expect("Could not deserialize from json"); 166 | assert_eq!(delta, delta1); 167 | Ok(()) 168 | } 169 | 170 | #[test] 171 | fn array_of_len_1__delta__different_values() -> DeltaResult<()> { 172 | let array0: [u16; 1] = [10]; 173 | let array1: [u16; 1] = [42]; 174 | let delta: <[u16; 1] as Core>::Delta = array0.delta(&array1)?; 175 | let json: String = serde_json::to_string(&delta) 176 | .expect("Could not serialize to json"); 177 | assert_eq!(json, "[{\"delta\":42,\"index\":0}]"); 178 | let delta1: <[u16; 1] as Core>::Delta = serde_json::from_str(&json) 179 | .expect("Could not deserialize from json"); 180 | assert_eq!(delta, delta1); 181 | Ok(()) 182 | } 183 | 184 | #[test] 185 | fn array_of_len_1__apply__same_values() -> DeltaResult<()> { 186 | let array0: [u16; 1] = [42]; 187 | let array1: [u16; 1] = [42]; 188 | let delta: <[u16; 1] as Core>::Delta = array0.delta(&array1)?; 189 | let array2 = array0.apply(delta)?; 190 | assert_eq!(array1, array2); 191 | Ok(()) 192 | } 193 | 194 | #[test] 195 | fn array_of_len_1__apply__different_values() -> DeltaResult<()> { 196 | let array0: [u16; 1] = [10]; 197 | let array1: [u16; 1] = [42]; 198 | let delta: <[u16; 1] as Core>::Delta = array0.delta(&array1)?; 199 | let array2 = array0.apply(delta)?; 200 | assert_eq!(array1, array2); 201 | Ok(()) 202 | } 203 | 204 | const N: usize = 2; 205 | 206 | #[test] 207 | fn array_of_len_N__delta__same_values() -> DeltaResult<()> { 208 | let array0: [u16; N] = [42, 300]; 209 | let array1: [u16; N] = [42, 300]; 210 | let delta: <[u16; N] as Core>::Delta = array0.delta(&array1)?; 211 | let json: String = serde_json::to_string(&delta) 212 | .expect("Could not serialize to json"); 213 | assert_eq!(json, "[]"); 214 | let delta1: <[u16; N] as Core>::Delta = serde_json::from_str(&json) 215 | .expect("Could not deserialize from json"); 216 | assert_eq!(delta, delta1); 217 | Ok(()) 218 | } 219 | 220 | #[test] 221 | fn array_of_len_N__delta__different_values() -> DeltaResult<()> { 222 | let array0: [u16; N] = [10, 20]; 223 | let array1: [u16; N] = [42, 300]; 224 | let delta: <[u16; N] as Core>::Delta = array0.delta(&array1)?; 225 | let json: String = serde_json::to_string_pretty(&delta) 226 | .expect("Could not serialize to json"); 227 | assert_eq!(json, "[ 228 | { 229 | \"delta\": 42, 230 | \"index\": 0 231 | }, 232 | { 233 | \"delta\": 300, 234 | \"index\": 1 235 | } 236 | ]"); 237 | let delta1: <[u16; N] as Core>::Delta = serde_json::from_str(&json) 238 | .expect("Could not deserialize from json"); 239 | assert_eq!(delta, delta1); 240 | Ok(()) 241 | } 242 | 243 | #[test] 244 | fn array_of_len_N__apply__same_values() -> DeltaResult<()> { 245 | let array0: [u16; N] = [42, 300]; 246 | let array1: [u16; N] = [42, 300]; 247 | let delta: <[u16; N] as Core>::Delta = array0.delta(&array1)?; 248 | let array2 = array0.apply(delta)?; 249 | assert_eq!(array1, array2); 250 | Ok(()) 251 | } 252 | 253 | #[test] 254 | fn array_of_len_N__apply__different_values() -> DeltaResult<()> { 255 | let array0: [u16; N] = [10, 20]; 256 | let array1: [u16; N] = [42, 300]; 257 | let delta: <[u16; N] as Core>::Delta = array0.delta(&array1)?; 258 | let array2 = array0.apply(delta)?; 259 | assert_eq!(array1, array2); 260 | Ok(()) 261 | } 262 | 263 | } 264 | -------------------------------------------------------------------------------- /deltoid/src/borrow.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use crate::{Apply, Core, Delta, DeltaResult, FromDelta, IntoDelta}; 4 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 5 | use serde::de; 6 | use serde::ser::SerializeMap; 7 | use std::borrow::{Borrow, Cow, ToOwned}; 8 | use std::fmt::{self, Debug}; 9 | use std::marker::PhantomData; 10 | 11 | 12 | impl<'a, B> Core for Cow<'a, B> 13 | where B: Clone + Debug + PartialEq + Core + ToOwned 14 | + for<'de> Deserialize<'de> 15 | + Serialize 16 | { 17 | type Delta = CowDelta<'a, B>; 18 | } 19 | 20 | impl<'a, B> Apply for Cow<'a, B> 21 | where B: Apply + FromDelta + ToOwned 22 | + for<'de> Deserialize<'de> 23 | + Serialize, 24 | ::Owned: Debug 25 | { 26 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 27 | let lhs: &B = self.borrow(); 28 | Ok(if let Some(delta) = delta.inner { 29 | Cow::Owned(lhs.apply(delta)?.to_owned()) 30 | } else { 31 | self.clone() 32 | }) 33 | } 34 | } 35 | 36 | impl<'a, B> Delta for Cow<'a, B> 37 | where B: Delta + ToOwned 38 | + for<'de> Deserialize<'de> 39 | + Serialize, 40 | ::Owned: Debug 41 | { 42 | fn delta(&self, other: &Self) -> DeltaResult { 43 | let (lhs, rhs): (&B, &B) = (self.borrow(), other.borrow()); 44 | Ok(CowDelta { 45 | inner: if self == other { 46 | None 47 | } else { 48 | Some(lhs.delta(rhs)?) 49 | }, 50 | _phantom: PhantomData, 51 | }) 52 | } 53 | } 54 | 55 | impl<'a, B> FromDelta for Cow<'a, B> 56 | where B: Clone + Debug + PartialEq + FromDelta 57 | + for<'de> Deserialize<'de> 58 | + Serialize 59 | { 60 | fn from_delta(delta: Self::Delta) -> DeltaResult { 61 | let delta: B::Delta = delta.inner 62 | .ok_or_else(|| ExpectedValue!("CowDelta<'a, B>"))?; 63 | Ok(Cow::Owned(::from_delta(delta)?.to_owned())) 64 | } 65 | } 66 | 67 | impl<'a, B> IntoDelta for Cow<'a, B> 68 | where B: Clone + Debug + PartialEq + IntoDelta 69 | + for<'de> Deserialize<'de> 70 | + Serialize 71 | { 72 | fn into_delta(self) -> DeltaResult { 73 | Ok(CowDelta { 74 | inner: Some((self.borrow() as &B).clone().into_delta()?), 75 | _phantom: PhantomData, 76 | }) 77 | } 78 | } 79 | 80 | 81 | 82 | #[derive(Clone, PartialEq)] 83 | pub struct CowDelta<'a, B: Core> { 84 | #[doc(hidden)] pub inner: Option, 85 | #[doc(hidden)] pub _phantom: PhantomData<&'a B> 86 | } 87 | 88 | impl<'a, B: Core> std::fmt::Debug for CowDelta<'a, B> { 89 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 90 | match &self.inner { 91 | Some(d) => write!(f, "CowDelta({:#?})", d), 92 | None => write!(f, "CowDelta(None)"), 93 | } 94 | } 95 | } 96 | 97 | impl<'a, B> Serialize for CowDelta<'a, B> 98 | where B: Core + for<'de> Deserialize<'de> + Serialize { 99 | fn serialize(&self, serializer: S) -> Result 100 | where S: Serializer { 101 | let mut num_fields = 0; 102 | if self.inner.is_some() { num_fields += 1; } 103 | let mut s = serializer.serialize_map(Some(num_fields))?; 104 | if let Some(inner) = &self.inner { 105 | s.serialize_entry("inner", inner)?; 106 | } 107 | s.end() 108 | } 109 | } 110 | 111 | impl<'de, 'a, B> Deserialize<'de> for CowDelta<'a, B> 112 | where B: Core + Deserialize<'de> + Serialize { 113 | fn deserialize(deserializer: D) -> Result 114 | where D: Deserializer<'de> { 115 | struct DeltaVisitor<'a2, B2>(PhantomData<&'a2 B2>); 116 | 117 | impl<'de, 'a2, B2> de::Visitor<'de> for DeltaVisitor<'a2, B2> 118 | where B2: Core + Deserialize<'de> + Serialize { 119 | type Value = CowDelta<'a2, B2>; 120 | 121 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 122 | formatter.write_str("a CowDelta") 123 | } 124 | 125 | fn visit_map(self, mut map: M) -> Result 126 | where M: de::MapAccess<'de> { 127 | let mut delta: Self::Value = Self::Value { 128 | inner: None, 129 | _phantom: PhantomData, 130 | }; 131 | const EXPECTED_FIELDS: &[&str] = &["inner"]; 132 | while let Some((key, value)) = map.next_entry()? { 133 | match (key, value) { 134 | ("inner", value) => delta.inner = Some(value), 135 | (field_name, _) => return Err(de::Error::unknown_field( 136 | field_name, EXPECTED_FIELDS 137 | ))?, 138 | } 139 | } 140 | Ok(delta) 141 | } 142 | } 143 | 144 | deserializer.deserialize_map(DeltaVisitor(PhantomData)) 145 | } 146 | } 147 | 148 | 149 | #[allow(non_snake_case)] 150 | #[cfg(test)] 151 | mod tests { 152 | use serde_json; 153 | use super::*; 154 | 155 | #[test] 156 | fn Cow__delta___same_values() -> DeltaResult<()> { 157 | let foo = String::from("foo"); 158 | let bar = String::from("foo"); 159 | let cow: Cow = Cow::Borrowed(&foo); 160 | let cow2: Cow = Cow::Borrowed(&bar); 161 | let delta: as Core>::Delta = cow.delta(&cow2)?; 162 | let json_string = serde_json::to_string(&delta) 163 | .expect("Could not serialize to json"); 164 | println!("json_string: {}", json_string); 165 | assert_eq!(json_string, "{}"); 166 | let delta1: as Core>::Delta = serde_json::from_str( 167 | &json_string 168 | ).expect("Could not deserialize from json"); 169 | assert_eq!(delta, delta1); 170 | Ok(()) 171 | } 172 | 173 | #[test] 174 | fn Cow__delta___different_values() -> DeltaResult<()> { 175 | let foo = String::from("foo"); 176 | let bar = String::from("bar"); 177 | let cow: Cow = Cow::Borrowed(&foo); 178 | let cow2: Cow = Cow::Borrowed(&bar); 179 | let delta: as Core>::Delta = cow.delta(&cow2)?; 180 | let json_string = serde_json::to_string(&delta) 181 | .expect("Could not serialize to json"); 182 | println!("json_string: {}", json_string); 183 | assert_eq!(json_string, "{\"inner\":\"bar\"}"); 184 | let delta1: as Core>::Delta = serde_json::from_str( 185 | &json_string 186 | ).expect("Could not deserialize from json"); 187 | assert_eq!(delta, delta1); 188 | Ok(()) 189 | } 190 | 191 | #[test] 192 | fn Cow__apply__same_values() -> DeltaResult<()> { 193 | let foo = String::from("foo"); 194 | let bar = String::from("foo"); 195 | let cow0: Cow = Cow::Owned(foo); 196 | let cow1: Cow = Cow::Owned(bar); 197 | let delta: as Core>::Delta = cow0.delta(&cow1)?; 198 | let cow2 = cow0.apply(delta)?; 199 | assert_eq!(cow1, cow2); 200 | Ok(()) 201 | } 202 | 203 | #[test] 204 | fn Cow__apply__different_values() -> DeltaResult<()> { 205 | let foo = String::from("foo"); 206 | let bar = String::from("bar"); 207 | let cow0: Cow = Cow::Owned(foo); 208 | let cow1: Cow = Cow::Owned(bar); 209 | let delta: as Core>::Delta = cow0.delta(&cow1)?; 210 | let cow2 = cow0.apply(delta)?; 211 | assert_eq!(cow1, cow2); 212 | Ok(()) 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /deltoid/src/boxed.rs: -------------------------------------------------------------------------------- 1 | //! A Deltoid impl for [`Box`] that provides extra functionality in 2 | //! the form of delta support, de/serialization, partial equality and more. 3 | //! 4 | //! [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html 5 | 6 | use crate::{Apply, Core, Delta, DeltaResult, FromDelta, IntoDelta}; 7 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 8 | use serde::de; 9 | use serde::ser::SerializeMap; 10 | use std::fmt::{self, Debug}; 11 | use std::marker::PhantomData; 12 | 13 | 14 | impl Core for Box 15 | where T: Clone + Debug + PartialEq + Core 16 | + for<'de> Deserialize<'de> 17 | + Serialize 18 | { 19 | type Delta = BoxDelta; 20 | } 21 | 22 | impl Apply for Box 23 | where T: Apply 24 | + for<'de> Deserialize<'de> 25 | + Serialize 26 | { 27 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 28 | let lhs: &T = self.as_ref(); 29 | match delta.0 { 30 | None => Ok(self.clone()), 31 | Some(delta) => Ok(Box::new(lhs.apply(*delta)?)), 32 | } 33 | } 34 | } 35 | 36 | impl Delta for Box 37 | where T: Delta 38 | + for<'de> Deserialize<'de> 39 | + Serialize 40 | { 41 | fn delta(&self, rhs: &Self) -> DeltaResult { 42 | let lhs: &T = self.as_ref(); 43 | let rhs: &T = rhs.as_ref(); 44 | Ok(BoxDelta(if lhs == rhs { 45 | None 46 | } else { 47 | Some(Box::new(lhs.delta(rhs)?)) 48 | })) 49 | } 50 | } 51 | 52 | impl FromDelta for Box 53 | where T: Clone + Debug + PartialEq + FromDelta 54 | + for<'de> Deserialize<'de> 55 | + Serialize 56 | { 57 | fn from_delta(delta: Self::Delta) -> DeltaResult { 58 | let delta: T::Delta = *delta.0 59 | .ok_or_else(|| ExpectedValue!("BoxDelta"))?; 60 | ::from_delta(delta).map(Box::new) 61 | } 62 | } 63 | 64 | impl IntoDelta for Box 65 | where T: Clone + Debug + PartialEq + IntoDelta 66 | + for<'de> Deserialize<'de> 67 | + Serialize 68 | { 69 | fn into_delta(self) -> DeltaResult { 70 | let t: T = *self; 71 | Ok(BoxDelta(Some(Box::new(t.into_delta()?)))) 72 | } 73 | } 74 | 75 | 76 | 77 | 78 | #[derive(Clone, PartialEq, Hash)] 79 | pub struct BoxDelta( 80 | #[doc(hidden)] pub Option> 81 | ); 82 | 83 | impl std::fmt::Debug for BoxDelta { 84 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 85 | match &self.0 { 86 | Some(d) => write!(f, "BoxDelta({:#?})", d), 87 | None => write!(f, "BoxDelta(None)"), 88 | } 89 | } 90 | } 91 | 92 | impl Serialize for BoxDelta 93 | where T: Core 94 | + for<'de> Deserialize<'de> 95 | + Serialize 96 | { 97 | fn serialize(&self, serializer: S) -> Result 98 | where S: Serializer { 99 | let mut num_fields = 0; 100 | if self.0.is_some() { num_fields += 1; } 101 | let mut s = serializer.serialize_map(Some(num_fields))?; 102 | if let Some(inner) = &self.0 { 103 | s.serialize_entry("0", inner)?; 104 | } 105 | s.end() 106 | } 107 | } 108 | 109 | impl<'de, T> Deserialize<'de> for BoxDelta 110 | where T: Core 111 | + Deserialize<'de> 112 | + Serialize 113 | { 114 | fn deserialize(deserializer: D) -> Result 115 | where D: Deserializer<'de> { 116 | struct DeltaVisitor(PhantomData); 117 | 118 | impl<'de, T2> de::Visitor<'de> for DeltaVisitor 119 | where T2: Core { 120 | type Value = BoxDelta; 121 | 122 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 123 | formatter.write_str("a BoxDelta") 124 | } 125 | 126 | fn visit_map(self, mut map: M) -> Result 127 | where M: de::MapAccess<'de> { 128 | let mut delta: Self::Value = BoxDelta(None); 129 | const EXPECTED_FIELDS: &[&str] = &["0"]; 130 | while let Some((key, value)) = map.next_entry()? { 131 | match (key, value) { 132 | ("0", value) => delta.0 = Some(value), 133 | (field_name, _) => return Err(de::Error::unknown_field( 134 | field_name, EXPECTED_FIELDS 135 | ))?, 136 | } 137 | } 138 | Ok(delta) 139 | } 140 | } 141 | 142 | deserializer.deserialize_map(DeltaVisitor(PhantomData)) 143 | } 144 | } 145 | 146 | 147 | 148 | #[allow(non_snake_case)] 149 | #[cfg(test)] 150 | mod tests { 151 | use serde_json; 152 | use super::*; 153 | 154 | #[test] 155 | fn Box__delta__same_values() -> DeltaResult<()> { 156 | let foo = String::from("foo"); 157 | let bar = String::from("foo"); 158 | let box0 = Box::new(foo); 159 | let box1 = Box::new(bar); 160 | let delta: as Core>::Delta = box0.delta(&box1)?; 161 | let json_string = serde_json::to_string(&delta) 162 | .expect("Could not serialize to json"); 163 | println!("json_string: \"{}\"", json_string); 164 | assert_eq!(json_string, "{}"); 165 | let delta1: as Core>::Delta = serde_json::from_str( 166 | &json_string 167 | ).expect("Could not deserialize from json"); 168 | assert_eq!(delta, delta1); 169 | Ok(()) 170 | } 171 | 172 | #[test] 173 | fn Box__delta__different_values() -> DeltaResult<()> { 174 | let foo = String::from("foo"); 175 | let bar = String::from("bar"); 176 | let box0 = Box::new(foo); 177 | let box1 = Box::new(bar); 178 | let delta: as Core>::Delta = box0.delta(&box1)?; 179 | let json_string = serde_json::to_string(&delta) 180 | .expect("Could not serialize to json"); 181 | println!("json_string: \"{}\"", json_string); 182 | assert_eq!(json_string, "{\"0\":\"bar\"}"); 183 | let delta1: as Core>::Delta = serde_json::from_str( 184 | &json_string 185 | ).expect("Could not deserialize from json"); 186 | assert_eq!(delta, delta1); 187 | Ok(()) 188 | } 189 | 190 | #[test] 191 | fn Box__apply__same_values() -> DeltaResult<()> { 192 | let foo = String::from("foo"); 193 | let bar = String::from("foo"); 194 | let box0 = Box::new(foo); 195 | let box1 = Box::new(bar); 196 | let delta: as Core>::Delta = box0.delta(&box1)?; 197 | let box2 = box0.apply(delta)?; 198 | assert_eq!(box1, box2); 199 | Ok(()) 200 | } 201 | 202 | #[test] 203 | fn Box__apply__different_values() -> DeltaResult<()> { 204 | let foo = String::from("foo"); 205 | let bar = String::from("bar"); 206 | let box0 = Box::new(foo); 207 | let box1 = Box::new(bar); 208 | let delta: as Core>::Delta = box0.delta(&box1)?; 209 | let box2 = box0.apply(delta)?; 210 | assert_eq!(box1, box2); 211 | Ok(()) 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /deltoid/src/collections/btreemap.rs: -------------------------------------------------------------------------------- 1 | //! A newtype wrapping [`BtreeMap`] that provides extra functionality in 2 | //! the form of delta support, de/serialization, partial equality and more. 3 | //! 4 | //! [`BtreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html 5 | 6 | use crate::{Apply, Core, Delta, DeltaError, DeltaResult, FromDelta, IntoDelta}; 7 | use serde::{Deserialize, Serialize}; 8 | use std::collections::{BTreeSet, BTreeMap}; 9 | use std::fmt::Debug; 10 | 11 | 12 | impl Core for BTreeMap 13 | where K: Clone + Debug + PartialEq + Ord + Core 14 | + for<'de> Deserialize<'de> 15 | + Serialize, 16 | V: Clone + Debug + PartialEq + Ord + Core 17 | + for<'de> Deserialize<'de> 18 | + Serialize, 19 | { 20 | type Delta = BTreeMapDelta; 21 | } 22 | 23 | impl Apply for BTreeMap 24 | where K: Clone + Debug + PartialEq + Ord + Apply 25 | + for<'de> Deserialize<'de> 26 | + Serialize, 27 | V: Clone + Debug + PartialEq + Ord + Apply + FromDelta 28 | + for<'de> Deserialize<'de> 29 | + Serialize, 30 | { 31 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 32 | let mut new: Self = self.clone(); 33 | for change in delta.into_iter() { match change { 34 | EntryDelta::Edit { key, value } => { 35 | let place: &mut V = &mut *new.get_mut(&key) 36 | .ok_or_else(|| ExpectedValue!("BTreeMapDelta"))?; 37 | *place = ::from_delta(value)?; 38 | }, 39 | EntryDelta::Add { key, value } => { 40 | new.insert(key, ::from_delta(value)?); 41 | }, 42 | EntryDelta::Remove { key } => { new.remove(&key); }, 43 | }} 44 | Ok(new) 45 | } 46 | } 47 | 48 | impl Delta for BTreeMap 49 | where K: Clone + Debug + PartialEq + Ord + Delta 50 | + for<'de> Deserialize<'de> 51 | + Serialize, 52 | V: Clone + Debug + PartialEq + Ord + Delta + IntoDelta 53 | + for<'de> Deserialize<'de> 54 | + Serialize, 55 | { 56 | fn delta(&self, rhs: &Self) -> DeltaResult { 57 | let lkeys: BTreeSet<&K> = self.keys().collect(); 58 | let rkeys: BTreeSet<&K> = rhs.keys().collect(); 59 | let edited_keys = lkeys.intersection(&rkeys) 60 | .filter(|key| self[key] != rhs[key]); 61 | let removed_keys = lkeys.difference(&rkeys); 62 | let added_keys = rkeys.difference(&lkeys); 63 | let mut changes: Vec> = vec![]; 64 | for key in edited_keys { 65 | let (lhs_val, rhs_val): (&V, &V) = (&self[key], &rhs[key]); 66 | let delta: ::Delta = lhs_val.delta(rhs_val)?; 67 | changes.push(EntryDelta::Edit { key: (*key).clone(), value: delta }); 68 | } 69 | for key in added_keys { 70 | changes.push(EntryDelta::Add { 71 | key: (*key).clone(), 72 | value: rhs[key].clone().into_delta()?, 73 | }); 74 | } 75 | for key in removed_keys { 76 | changes.push(EntryDelta::Remove { key: (*key).clone() }); 77 | } 78 | Ok(BTreeMapDelta(if !changes.is_empty() { 79 | Some(changes) 80 | } else { 81 | None 82 | })) 83 | } 84 | } 85 | 86 | impl FromDelta for BTreeMap 87 | where K: Clone + Debug + PartialEq + Ord + FromDelta 88 | + for<'de> Deserialize<'de> 89 | + Serialize, 90 | V: Clone + Debug + PartialEq + Ord + FromDelta 91 | + for<'de> Deserialize<'de> 92 | + Serialize, 93 | { 94 | fn from_delta(delta: Self::Delta) -> DeltaResult { 95 | let mut map: Self = Self::new(); 96 | if let Some(delta) = delta.0 { 97 | for (index, element) in delta.into_iter().enumerate() { 98 | match element { 99 | EntryDelta::Add { key, value } => 100 | map.insert(key, ::from_delta(value)?), 101 | _ => return Err(DeltaError::IllegalDelta { index })?, 102 | }; 103 | } 104 | } 105 | Ok(map) 106 | } 107 | } 108 | 109 | impl IntoDelta for BTreeMap 110 | where K: Clone + Debug + PartialEq + Ord + IntoDelta 111 | + for<'de> Deserialize<'de> 112 | + Serialize, 113 | V: Clone + Debug + PartialEq + Ord + IntoDelta 114 | + for<'de> Deserialize<'de> 115 | + Serialize, 116 | { 117 | fn into_delta(self) -> DeltaResult { 118 | let mut changes: Vec> = vec![]; 119 | for (key, val) in self { 120 | changes.push(EntryDelta::Add { key, value: val.into_delta()? }); 121 | } 122 | Ok(BTreeMapDelta(if !changes.is_empty() { 123 | Some(changes) 124 | } else { 125 | None 126 | })) 127 | } 128 | } 129 | 130 | 131 | 132 | 133 | #[derive(Clone, PartialEq)] 134 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 135 | pub struct BTreeMapDelta( 136 | #[doc(hidden)] pub Option>>, 137 | ); 138 | 139 | impl BTreeMapDelta 140 | where K: Clone + Debug + PartialEq + Ord + Core 141 | + for<'de> Deserialize<'de> 142 | + Serialize, 143 | V: Core 144 | + for<'de> Deserialize<'de> 145 | + Serialize, 146 | { 147 | pub fn iter<'d>(&'d self) -> Box> + 'd> { 148 | match &self.0 { 149 | Some(delta) => Box::new(delta.iter()), 150 | None => Box::new(std::iter::empty()), 151 | } 152 | } 153 | 154 | pub fn into_iter<'d>(self) -> Box> + 'd> 155 | where Self: 'd { 156 | match self.0 { 157 | Some(delta) => Box::new(delta.into_iter()), 158 | None => Box::new(std::iter::empty()), 159 | } 160 | } 161 | 162 | pub fn len(&self) -> usize { 163 | match &self.0 { 164 | Some(delta) => delta.len(), 165 | None => 0, 166 | } 167 | } 168 | } 169 | 170 | impl std::fmt::Debug for BTreeMapDelta 171 | where K: std::fmt::Debug + Core, 172 | V: std::fmt::Debug + Core 173 | { 174 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 175 | write!(f, "BTreeMapDelta ")?; 176 | let mut buf = f.debug_list(); 177 | if let Some(d) = &self.0 { 178 | buf.entries(d.iter()); 179 | } else { 180 | buf.entries(std::iter::empty::>>()); 181 | } 182 | buf.finish() 183 | } 184 | } 185 | 186 | 187 | 188 | #[derive(Clone, PartialEq)] 189 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 190 | pub enum EntryDelta { 191 | /// Edit a `value` of a given `key` 192 | Edit { key: K, value: ::Delta }, 193 | /// Add a given `key` and `value` entry. 194 | Add { key: K, value: ::Delta }, 195 | /// Remove the entry with a given `key` from the map. 196 | Remove { key: K }, 197 | } 198 | 199 | impl std::fmt::Debug for EntryDelta 200 | where K: std::fmt::Debug, 201 | V: std::fmt::Debug + Core 202 | { 203 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 204 | match &self { 205 | Self::Edit { key, value } => f.debug_struct("Edit") 206 | .field("key", key) 207 | .field("value", value) 208 | .finish(), 209 | Self::Add { key, value } => f.debug_struct("Add") 210 | .field("key", key) 211 | .field("value", value) 212 | .finish(), 213 | Self::Remove { key } => f.debug_struct("Remove") 214 | .field("key", key) 215 | .finish(), 216 | } 217 | } 218 | } 219 | 220 | 221 | 222 | 223 | 224 | 225 | #[allow(non_snake_case)] 226 | #[cfg(test)] 227 | mod tests { 228 | use super::*; 229 | use std::collections::BTreeMap; 230 | 231 | macro_rules! map { 232 | ($($key:expr => $val:expr),* $(,)?) => {{ 233 | let mut map = BTreeMap::new(); 234 | $( map.insert($key, $val); )* 235 | map 236 | }} 237 | } 238 | 239 | #[test] 240 | fn BTreeMap__delta__same_values() -> DeltaResult<()> { 241 | let map0: BTreeMap = map! { 242 | "bar".into() => 300usize, 243 | "foo".into() => 42usize, 244 | "floozie".into() => 0usize, 245 | "quux".into() => 16000usize, 246 | }; 247 | let map1: BTreeMap = map! { 248 | "bar".into() => 300usize, 249 | "foo".into() => 42usize, 250 | "floozie".into() => 0usize, 251 | "quux".into() => 16000usize, 252 | }; 253 | let delta = map0.delta(&map1)?; 254 | let expected = BTreeMapDelta(None); 255 | assert_eq!(delta, expected); 256 | let map2 = map0.apply(delta)?; 257 | assert_eq!(map0, map2); 258 | assert_eq!(map1, map2); 259 | 260 | let delta = map1.delta(&map0)?; 261 | assert_eq!(delta, BTreeMapDelta(None)); 262 | let map3 = map1.apply(delta)?; 263 | assert_eq!(map0, map3); 264 | assert_eq!(map1, map3); 265 | 266 | Ok(()) 267 | } 268 | 269 | #[test] 270 | fn BTreeMap__delta__different_values() -> DeltaResult<()> { 271 | let map0: BTreeMap = map! { 272 | "bar".into() => 300usize, 273 | "foo".into() => 42usize, 274 | "floozie".into() => 0usize, 275 | "quux".into() => 16000usize, 276 | }; 277 | let map1: BTreeMap = map! { 278 | "bar".into() => 350usize, 279 | "baz".into() => 9000usize, 280 | "foo".into() => 42usize, 281 | "quux".into() => 16000usize, 282 | }; 283 | let delta0 = map0.delta(&map1)?; 284 | let expected = BTreeMapDelta(Some(vec![ 285 | EntryDelta::Edit { key: "bar".into(), value: 350usize.into_delta()? }, 286 | EntryDelta::Add { key: "baz".into(), value: 9000usize.into_delta()? }, 287 | EntryDelta::Remove { key: "floozie".into() }, 288 | ])); 289 | assert_eq!(delta0, expected); 290 | let map2 = map0.apply(delta0)?; 291 | assert_eq!(map1, map2); 292 | 293 | let delta1 = map1.delta(&map0)?; 294 | assert_eq!(delta1, BTreeMapDelta(Some(vec![ 295 | EntryDelta::Edit { key: "bar".into(), value: 300usize.into_delta()? }, 296 | EntryDelta::Add { key: "floozie".into(), value: 0usize.into_delta()? }, 297 | EntryDelta::Remove { key: "baz".into() }, 298 | ]))); 299 | let map3 = map1.apply(delta1)?; 300 | assert_eq!(map0, map3); 301 | 302 | Ok(()) 303 | } 304 | 305 | #[test] 306 | fn BTreeMap__apply__same_values() -> DeltaResult<()> { 307 | let map0: BTreeMap = map! { 308 | "bar".into() => 300usize, 309 | "foo".into() => 42usize, 310 | "floozie".into() => 0usize, 311 | "quux".into() => 16000usize, 312 | }; 313 | let map1: BTreeMap = map! { 314 | "bar".into() => 300usize, 315 | "foo".into() => 42usize, 316 | "floozie".into() => 0usize, 317 | "quux".into() => 16000usize, 318 | }; 319 | let delta = map0.delta(&map1)?; 320 | assert_eq!(delta, BTreeMapDelta(None)); 321 | let map2 = map0.apply(delta)?; 322 | assert_eq!(map1, map2); 323 | Ok(()) 324 | } 325 | 326 | #[test] 327 | fn BTreeMap__apply__different_values() -> DeltaResult<()> { 328 | let map0: BTreeMap = map! { 329 | "bar".into() => 300usize, 330 | "foo".into() => 42usize, 331 | "floozie".into() => 0usize, 332 | "quux".into() => 16000usize, 333 | }; 334 | let map1: BTreeMap = map! { 335 | "bar".into() => 350usize, 336 | "baz".into() => 9000usize, 337 | "foo".into() => 42usize, 338 | "quux".into() => 16000usize, 339 | }; 340 | let delta = map0.delta(&map1)?; 341 | assert_eq!(delta, BTreeMapDelta(Some(vec![ 342 | EntryDelta::Edit { key: "bar".into(), value: 350usize.into_delta()? }, 343 | EntryDelta::Add { key: "baz".into(), value: 9000usize.into_delta()? }, 344 | EntryDelta::Remove { key: "floozie".into() }, 345 | ]))); 346 | let map2 = map0.apply(delta)?; 347 | assert_eq!(map1, map2); 348 | Ok(()) 349 | } 350 | 351 | } 352 | -------------------------------------------------------------------------------- /deltoid/src/collections/btreeset.rs: -------------------------------------------------------------------------------- 1 | //! A newtype wrapping [`BTreeSet`] that provides extra functionality in 2 | //! the form of delta support, de/serialization, partial equality and more. 3 | //! 4 | //! [`BTreeSet`]: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html 5 | 6 | use crate::{Apply, Core, Delta, DeltaResult, FromDelta, IntoDelta}; 7 | use serde::{Deserialize, Serialize}; 8 | use std::collections::BTreeSet; 9 | use std::fmt::Debug; 10 | 11 | 12 | impl Core for BTreeSet 13 | where T: Clone + Debug + PartialEq + Ord + Core 14 | + for<'de> Deserialize<'de> 15 | + Serialize, 16 | { 17 | type Delta = BTreeSetDelta; 18 | } 19 | 20 | impl Apply for BTreeSet 21 | where T: Clone + Debug + PartialEq + Ord + Apply + FromDelta 22 | + for<'de> Deserialize<'de> 23 | + Serialize, 24 | { 25 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 26 | match delta.0 { 27 | None => Ok(self.clone()), 28 | Some(entry_deltas) => { 29 | let mut new: Self = self.clone(); 30 | for entry_delta in entry_deltas { match entry_delta { 31 | EntryDelta::Add { item } => { 32 | new.insert(::from_delta(item)?); 33 | }, 34 | EntryDelta::Remove { item } => { 35 | new.remove(&(::from_delta(item)?)); 36 | }, 37 | }} 38 | Ok(new) 39 | }, 40 | } 41 | } 42 | } 43 | 44 | impl Delta for BTreeSet 45 | where T: Clone + Debug + PartialEq + Ord + Delta + IntoDelta 46 | + for<'de> Deserialize<'de> 47 | + Serialize, 48 | { 49 | fn delta(&self, rhs: &Self) -> DeltaResult { 50 | Ok(BTreeSetDelta(if self == rhs { 51 | None 52 | } else { 53 | let mut entry_deltas: Vec> = vec![]; 54 | for addition in rhs.difference(&self) { 55 | let addition = addition.clone().into_delta()?; 56 | entry_deltas.push(EntryDelta::Add { item: addition }); 57 | } 58 | for removal in self.difference(&rhs) { 59 | let removal = removal.clone().into_delta()?; 60 | entry_deltas.push(EntryDelta::Remove { item: removal }); 61 | } 62 | Some(entry_deltas) 63 | })) 64 | } 65 | } 66 | 67 | impl FromDelta for BTreeSet 68 | where T: Clone + Debug + PartialEq + Ord + FromDelta 69 | + for<'de> Deserialize<'de> 70 | + Serialize, 71 | { 72 | fn from_delta(delta: Self::Delta) -> DeltaResult { 73 | let mut map = Self::new(); 74 | if let Some(delta_entries) = delta.0 { 75 | for entry in delta_entries { match entry { 76 | EntryDelta::Add { item } => { 77 | map.insert(::from_delta(item)?); 78 | }, 79 | EntryDelta::Remove { item } => { 80 | let item = ::from_delta(item)?; 81 | map.remove(&item); 82 | }, 83 | }} 84 | } 85 | Ok(map) 86 | } 87 | } 88 | 89 | impl IntoDelta for BTreeSet 90 | where T: Clone + Debug + PartialEq + Ord + IntoDelta 91 | + for<'de> Deserialize<'de> 92 | + Serialize, 93 | { 94 | fn into_delta(self) -> DeltaResult { 95 | Ok(BTreeSetDelta(if self.is_empty() { 96 | None 97 | } else { 98 | let mut changes: Vec> = vec![]; 99 | for item in self { 100 | changes.push(EntryDelta::Add { item: item.into_delta()? }); 101 | } 102 | Some(changes) 103 | })) 104 | } 105 | } 106 | 107 | 108 | 109 | 110 | #[derive(Clone, PartialEq)] 111 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 112 | pub struct BTreeSetDelta( 113 | #[doc(hidden)] pub Option>>, 114 | ); 115 | 116 | impl BTreeSetDelta 117 | where T: Clone + Debug + PartialEq + Ord + Core 118 | + for<'de> Deserialize<'de> 119 | + Serialize, 120 | { 121 | pub fn iter<'d>(&'d self) -> Box> + 'd> { 122 | match &self.0 { 123 | Some(deltas) => Box::new(deltas.iter()), 124 | None => Box::new(std::iter::empty()), 125 | } 126 | } 127 | 128 | pub fn into_iter<'d>(self) -> Box> + 'd> 129 | where Self: 'd { 130 | match self.0 { 131 | Some(delta) => Box::new(delta.into_iter()), 132 | None => Box::new(std::iter::empty()), 133 | } 134 | } 135 | 136 | pub fn len(&self) -> usize { 137 | match &self.0 { 138 | Some(deltas) => deltas.len(), 139 | None => 0, 140 | } 141 | } 142 | } 143 | 144 | impl std::fmt::Debug for BTreeSetDelta 145 | where T: std::fmt::Debug + Core { 146 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 147 | write!(f, "BTreeSetDelta ")?; 148 | let mut buf = f.debug_list(); 149 | if let Some(d) = &self.0 { 150 | buf.entries(d.iter()); 151 | } else { 152 | buf.entries(std::iter::empty::>>()); 153 | } 154 | buf.finish() 155 | } 156 | } 157 | 158 | 159 | 160 | #[derive(Clone, PartialEq)] 161 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 162 | pub enum EntryDelta { 163 | Add { item: ::Delta }, 164 | Remove { item: ::Delta }, 165 | } 166 | 167 | impl std::fmt::Debug for EntryDelta 168 | where T: std::fmt::Debug + Core { 169 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 170 | match &self { 171 | Self::Add { item } => f.debug_struct("Add") 172 | .field("item", item) 173 | .finish(), 174 | Self::Remove { item } => f.debug_struct("Remove") 175 | .field("item", item) 176 | .finish(), 177 | } 178 | } 179 | } 180 | 181 | 182 | 183 | #[allow(non_snake_case)] 184 | #[cfg(test)] 185 | mod tests { 186 | use super::*; 187 | use std::collections::BTreeSet; 188 | 189 | macro_rules! set { 190 | ($($val:expr),* $(,)?) => {{ #[allow(redundant_semicolons)] { 191 | let mut set = BTreeSet::new(); 192 | $( set.insert($val); )* ; 193 | set 194 | }}} 195 | } 196 | 197 | #[test] 198 | fn BTreeSet__delta__same_values() -> DeltaResult<()> { 199 | let set0: BTreeSet = set! { 200 | "bar".into(), 201 | "foo".into(), 202 | "floozie".into(), 203 | "quux".into(), 204 | }; 205 | let set1: BTreeSet = set! { 206 | "bar".into(), 207 | "foo".into(), 208 | "floozie".into(), 209 | "quux".into(), 210 | }; 211 | let delta = set0.delta(&set1)?; 212 | let expected = BTreeSetDelta(None); 213 | assert_eq!(delta, expected); 214 | let set2 = set0.apply(delta)?; 215 | assert_eq!(set0, set2); 216 | assert_eq!(set1, set2); 217 | 218 | let delta = set1.delta(&set0)?; 219 | assert_eq!(delta, BTreeSetDelta(None)); 220 | let set3 = set1.apply(delta)?; 221 | assert_eq!(set0, set3); 222 | assert_eq!(set1, set3); 223 | 224 | Ok(()) 225 | } 226 | 227 | #[test] 228 | fn BTreeSet__delta__different_values() -> DeltaResult<()> { 229 | let set0: BTreeSet = set! { 230 | "bar".into(), 231 | "foo".into(), 232 | "floozie".into(), 233 | "quux".into(), 234 | }; 235 | let set1: BTreeSet = set! { 236 | "bar".into(), 237 | "baz".into(), 238 | "foo".into(), 239 | "quux".into(), 240 | }; 241 | let delta0 = set0.delta(&set1)?; 242 | let expected = BTreeSetDelta(Some(vec![ 243 | EntryDelta::Add { item: "baz".to_string().into_delta()? }, 244 | EntryDelta::Remove { item: "floozie".to_string().into_delta()? }, 245 | ])); 246 | assert_eq!(delta0, expected); 247 | let set2 = set0.apply(delta0)?; 248 | assert_eq!(set1, set2); 249 | 250 | let delta1 = set1.delta(&set0)?; 251 | assert_eq!(delta1, BTreeSetDelta(Some(vec![ 252 | EntryDelta::Add { item: "floozie".to_string().into_delta()? }, 253 | EntryDelta::Remove { item: "baz".to_string().into_delta()? }, 254 | ]))); 255 | let set3 = set1.apply(delta1)?; 256 | assert_eq!(set0, set3); 257 | 258 | Ok(()) 259 | } 260 | 261 | #[test] 262 | fn BTreeSet__apply__same_values() -> DeltaResult<()> { 263 | let set0: BTreeSet = set! { 264 | "bar".into(), 265 | "foo".into(), 266 | "floozie".into(), 267 | "quux".into(), 268 | }; 269 | let set1: BTreeSet = set! { 270 | "bar".into(), 271 | "foo".into(), 272 | "floozie".into(), 273 | "quux".into(), 274 | }; 275 | let delta = set0.delta(&set1)?; 276 | assert_eq!(delta, BTreeSetDelta(None)); 277 | let set2 = set0.apply(delta)?; 278 | assert_eq!(set1, set2); 279 | Ok(()) 280 | } 281 | 282 | #[test] 283 | fn BTreeSet__apply__different_values() -> DeltaResult<()> { 284 | let set0: BTreeSet = set! { 285 | "bar".into(), 286 | "foo".into(), 287 | "floozie".into(), 288 | "quux".into(), 289 | }; 290 | let set1: BTreeSet = set! { 291 | "bar".into(), 292 | "baz".into(), 293 | "foo".into(), 294 | "quux".into(), 295 | }; 296 | let delta = set0.delta(&set1)?; 297 | assert_eq!(delta, BTreeSetDelta(Some(vec![ 298 | EntryDelta::Add { item: "baz".to_string().into_delta()? }, 299 | EntryDelta::Remove { item: "floozie".to_string().into_delta()? }, 300 | ]))); 301 | let set2 = set0.apply(delta)?; 302 | assert_eq!(set1, set2); 303 | Ok(()) 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /deltoid/src/collections/hashmap.rs: -------------------------------------------------------------------------------- 1 | //! A newtype wrapping [`HashMap`] that provides extra functionality in 2 | //! the form of delta support, de/serialization, partial equality and more. 3 | //! 4 | //! [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html 5 | 6 | use crate::{Apply, Core, Delta, DeltaError, DeltaResult, FromDelta, IntoDelta}; 7 | use serde::{Deserialize, Serialize}; 8 | use std::collections::{HashMap, HashSet}; 9 | use std::fmt::Debug; 10 | use std::hash::Hash; 11 | 12 | 13 | impl Core for HashMap 14 | where K: Clone + Debug + PartialEq + Ord + Hash + Core 15 | + for<'de> Deserialize<'de> 16 | + Serialize, 17 | V: Clone + Debug + PartialEq + Ord + Core 18 | + for<'de> Deserialize<'de> 19 | + Serialize, 20 | { 21 | type Delta = HashMapDelta; 22 | } 23 | 24 | impl Apply for HashMap 25 | where K: Clone + Debug + PartialEq + Ord + Hash + Apply 26 | + for<'de> Deserialize<'de> 27 | + Serialize, 28 | V: Clone + Debug + PartialEq + Ord + Apply + FromDelta 29 | + for<'de> Deserialize<'de> 30 | + Serialize, 31 | { 32 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 33 | let mut new: Self = self.clone(); 34 | for change in delta.into_iter() { match change { 35 | EntryDelta::Edit { key, value } => { 36 | let place: &mut V = &mut *new.get_mut(&key) 37 | .ok_or_else(|| ExpectedValue!("HashMapDelta"))?; 38 | *place = ::from_delta(value)?; 39 | }, 40 | EntryDelta::Add { key, value } => { 41 | new.insert(key, ::from_delta(value)?); 42 | }, 43 | EntryDelta::Remove { key } => { new.remove(&key); }, 44 | }} 45 | Ok(new) 46 | } 47 | } 48 | 49 | impl Delta for HashMap 50 | where K: Clone + Debug + PartialEq + Ord + Hash + Delta 51 | + for<'de> Deserialize<'de> 52 | + Serialize, 53 | V: Clone + Debug + PartialEq + Ord + Delta + IntoDelta 54 | + for<'de> Deserialize<'de> 55 | + Serialize, 56 | { 57 | fn delta(&self, rhs: &Self) -> DeltaResult { 58 | let lkeys: HashSet<&K> = self.keys().collect(); 59 | let rkeys: HashSet<&K> = rhs.keys().collect(); 60 | let edited_keys = lkeys.intersection(&rkeys) 61 | .filter(|key| self[key] != rhs[key]); 62 | let removed_keys = lkeys.difference(&rkeys); 63 | let added_keys = rkeys.difference(&lkeys); 64 | let mut changes: Vec> = vec![]; 65 | for key in edited_keys { 66 | let (lhs_val, rhs_val): (&V, &V) = (&self[key], &rhs[key]); 67 | let delta: ::Delta = lhs_val.delta(rhs_val)?; 68 | changes.push(EntryDelta::Edit { key: (*key).clone(), value: delta }); 69 | } 70 | for key in added_keys { 71 | changes.push(EntryDelta::Add { 72 | key: (*key).clone(), 73 | value: rhs[key].clone().into_delta()?, 74 | }); 75 | } 76 | for key in removed_keys { 77 | changes.push(EntryDelta::Remove { key: (*key).clone() }); 78 | } 79 | Ok(HashMapDelta(if !changes.is_empty() { 80 | Some(changes) 81 | } else { 82 | None 83 | })) 84 | } 85 | } 86 | 87 | impl FromDelta for HashMap 88 | where K: Clone + Debug + PartialEq + Ord + Hash + FromDelta 89 | + for<'de> Deserialize<'de> 90 | + Serialize, 91 | V: Clone + Debug + PartialEq + Ord + FromDelta 92 | + for<'de> Deserialize<'de> 93 | + Serialize, 94 | { 95 | fn from_delta(delta: Self::Delta) -> DeltaResult { 96 | let mut map: Self = Self::new(); 97 | if let Some(delta) = delta.0 { 98 | for (index, element) in delta.into_iter().enumerate() { 99 | match element { 100 | EntryDelta::Add { key, value } => 101 | map.insert(key, ::from_delta(value)?), 102 | _ => return Err(DeltaError::IllegalDelta { index })?, 103 | }; 104 | } 105 | } 106 | Ok(map) 107 | } 108 | } 109 | 110 | impl IntoDelta for HashMap 111 | where K: Clone + Debug + PartialEq + Ord + Hash + IntoDelta 112 | + for<'de> Deserialize<'de> 113 | + Serialize, 114 | V: Clone + Debug + PartialEq + Ord + IntoDelta 115 | + for<'de> Deserialize<'de> 116 | + Serialize, 117 | { 118 | fn into_delta(self) -> DeltaResult { 119 | let mut changes: Vec> = vec![]; 120 | for (key, val) in self { 121 | changes.push(EntryDelta::Add { key, value: val.into_delta()? }); 122 | } 123 | Ok(HashMapDelta(if !changes.is_empty() { 124 | Some(changes) 125 | } else { 126 | None 127 | })) 128 | } 129 | } 130 | 131 | 132 | #[derive(Clone, PartialEq)] 133 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 134 | pub struct HashMapDelta( 135 | #[doc(hidden)] 136 | pub Option>>, 137 | ); 138 | 139 | impl HashMapDelta 140 | where K: Clone + Debug + PartialEq + Ord + Hash + Core 141 | + for<'de> Deserialize<'de> 142 | + Serialize, 143 | V: Clone + Debug + PartialEq + Ord + Core 144 | + for<'de> Deserialize<'de> 145 | + Serialize, 146 | { 147 | pub fn iter<'d>(&'d self) -> Box> + 'd> { 148 | match &self.0 { 149 | Some(delta) => Box::new(delta.iter()), 150 | None => Box::new(std::iter::empty()), 151 | } 152 | } 153 | 154 | pub fn into_iter<'d>(self) -> Box> + 'd> 155 | where Self: 'd { 156 | match self.0 { 157 | Some(delta) => Box::new(delta.into_iter()), 158 | None => Box::new(std::iter::empty()), 159 | } 160 | } 161 | 162 | pub fn len(&self) -> usize { 163 | match &self.0 { 164 | Some(delta) => delta.len(), 165 | None => 0, 166 | } 167 | } 168 | } 169 | 170 | impl std::fmt::Debug for HashMapDelta 171 | where K: std::fmt::Debug + Core, 172 | V: std::fmt::Debug + Core 173 | { 174 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 175 | write!(f, "HashMapDelta ")?; 176 | let mut buf = f.debug_list(); 177 | if let Some(d) = &self.0 { 178 | buf.entries(d.iter()); 179 | } else { 180 | buf.entries(std::iter::empty::>>()); 181 | } 182 | buf.finish() 183 | } 184 | } 185 | 186 | 187 | #[derive(Clone, PartialEq)] 188 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 189 | pub enum EntryDelta { 190 | /// Edit a `value` of a given `key` 191 | Edit { key: K, value: ::Delta }, 192 | /// Add a given `key` and `value` entry. 193 | Add { key: K, value: ::Delta }, 194 | /// Remove the entry with a given `key` from the map. 195 | Remove { key: K }, 196 | } 197 | 198 | impl std::fmt::Debug for EntryDelta 199 | where K: std::fmt::Debug, 200 | V: std::fmt::Debug + Core 201 | { 202 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 203 | match &self { 204 | Self::Edit { key, value } => f.debug_struct("Edit") 205 | .field("key", key) 206 | .field("value", value) 207 | .finish(), 208 | Self::Add { key, value } => f.debug_struct("Add") 209 | .field("key", key) 210 | .field("value", value) 211 | .finish(), 212 | Self::Remove { key } => f.debug_struct("Remove") 213 | .field("key", key) 214 | .finish(), 215 | } 216 | } 217 | } 218 | 219 | 220 | 221 | #[allow(non_snake_case)] 222 | #[cfg(test)] 223 | mod tests { 224 | use super::*; 225 | use std::collections::HashMap; 226 | 227 | macro_rules! map { 228 | ($($key:expr => $val:expr),* $(,)?) => {{ 229 | let mut map = HashMap::new(); 230 | $( map.insert($key, $val); )* 231 | map 232 | }} 233 | } 234 | 235 | #[test] 236 | fn HashMap__delta__same_values() -> DeltaResult<()> { 237 | let map0: HashMap = map! { 238 | "bar".into() => 300usize, 239 | "foo".into() => 42usize, 240 | "floozie".into() => 0usize, 241 | "quux".into() => 16000usize, 242 | }; 243 | let map1: HashMap = map! { 244 | "bar".into() => 300usize, 245 | "foo".into() => 42usize, 246 | "floozie".into() => 0usize, 247 | "quux".into() => 16000usize, 248 | }; 249 | let delta = map0.delta(&map1)?; 250 | let expected = HashMapDelta(None); 251 | assert_eq!(delta, expected); 252 | let map2 = map0.apply(delta)?; 253 | assert_eq!(map0, map2); 254 | assert_eq!(map1, map2); 255 | 256 | let delta = map1.delta(&map0)?; 257 | assert_eq!(delta, HashMapDelta(None)); 258 | let map3 = map1.apply(delta)?; 259 | assert_eq!(map0, map3); 260 | assert_eq!(map1, map3); 261 | 262 | Ok(()) 263 | } 264 | 265 | #[test] 266 | fn HashMap__delta__different_values() -> DeltaResult<()> { 267 | let map0: HashMap = map! { 268 | "bar".into() => 300usize, 269 | "foo".into() => 42usize, 270 | "floozie".into() => 0usize, 271 | "quux".into() => 16000usize, 272 | }; 273 | let map1: HashMap = map! { 274 | "bar".into() => 350usize, 275 | "baz".into() => 9000usize, 276 | "foo".into() => 42usize, 277 | "quux".into() => 16000usize, 278 | }; 279 | let delta0 = map0.delta(&map1)?; 280 | let expected = HashMapDelta(Some(vec![ 281 | EntryDelta::Edit { key: "bar".into(), value: 350usize.into_delta()? }, 282 | EntryDelta::Add { key: "baz".into(), value: 9000usize.into_delta()? }, 283 | EntryDelta::Remove { key: "floozie".into() }, 284 | ])); 285 | assert_eq!(delta0, expected); 286 | let map2 = map0.apply(delta0)?; 287 | assert_eq!(map1, map2); 288 | 289 | let delta1 = map1.delta(&map0)?; 290 | assert_eq!(delta1, HashMapDelta(Some(vec![ 291 | EntryDelta::Edit { key: "bar".into(), value: 300usize.into_delta()? }, 292 | EntryDelta::Add { key: "floozie".into(), value: 0usize.into_delta()? }, 293 | EntryDelta::Remove { key: "baz".into() }, 294 | ]))); 295 | let map3 = map1.apply(delta1)?; 296 | assert_eq!(map0, map3); 297 | 298 | Ok(()) 299 | } 300 | 301 | #[test] 302 | fn HashMap__apply__same_values() -> DeltaResult<()> { 303 | let map0: HashMap = map! { 304 | "bar".into() => 300usize, 305 | "foo".into() => 42usize, 306 | "floozie".into() => 0usize, 307 | "quux".into() => 16000usize, 308 | }; 309 | let map1: HashMap = map! { 310 | "bar".into() => 300usize, 311 | "foo".into() => 42usize, 312 | "floozie".into() => 0usize, 313 | "quux".into() => 16000usize, 314 | }; 315 | let delta = map0.delta(&map1)?; 316 | assert_eq!(delta, HashMapDelta(None)); 317 | let map2 = map0.apply(delta)?; 318 | assert_eq!(map1, map2); 319 | Ok(()) 320 | } 321 | 322 | #[test] 323 | fn HashMap__apply__different_values() -> DeltaResult<()> { 324 | let map0: HashMap = map! { 325 | "bar".into() => 300usize, 326 | "foo".into() => 42usize, 327 | "floozie".into() => 0usize, 328 | "quux".into() => 16000usize, 329 | }; 330 | let map1: HashMap = map! { 331 | "bar".into() => 350usize, 332 | "baz".into() => 9000usize, 333 | "foo".into() => 42usize, 334 | "quux".into() => 16000usize, 335 | }; 336 | let delta = map0.delta(&map1)?; 337 | assert_eq!(delta, HashMapDelta(Some(vec![ 338 | EntryDelta::Edit { key: "bar".into(), value: 350usize.into_delta()? }, 339 | EntryDelta::Add { key: "baz".into(), value: 9000usize.into_delta()? }, 340 | EntryDelta::Remove { key: "floozie".into() }, 341 | ]))); 342 | let map2 = map0.apply(delta)?; 343 | assert_eq!(map1, map2); 344 | Ok(()) 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /deltoid/src/collections/hashset.rs: -------------------------------------------------------------------------------- 1 | //! A newtype wrapping [`HashSet`] that provides extra functionality in 2 | //! the form of delta support, de/serialization, partial equality and more. 3 | //! 4 | //! [`HashSet`]: https://doc.rust-lang.org/std/collections/struct.HashSet.html 5 | 6 | use crate::{Apply, Core, Delta, DeltaResult, FromDelta, IntoDelta}; 7 | use serde::{Deserialize, Serialize}; 8 | use std::collections::HashSet; 9 | use std::fmt::Debug; 10 | use std::hash::Hash; 11 | 12 | 13 | impl Core for HashSet 14 | where T: Clone + Debug + PartialEq + Ord + Core 15 | + for<'de> Deserialize<'de> 16 | + Serialize, 17 | { 18 | type Delta = HashSetDelta; 19 | } 20 | 21 | impl Apply for HashSet 22 | where T: Clone + Debug + PartialEq + Ord + Hash + Apply + FromDelta 23 | + for<'de> Deserialize<'de> 24 | + Serialize, 25 | { 26 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 27 | match delta.0 { 28 | None => Ok(self.clone()), 29 | Some(entry_deltas) => { 30 | let mut new: Self = self.clone(); 31 | for entry_delta in entry_deltas { match entry_delta { 32 | EntryDelta::Add { item } => { 33 | new.insert(::from_delta(item)?); 34 | }, 35 | EntryDelta::Remove { item } => { 36 | new.remove(&(::from_delta(item)?)); 37 | }, 38 | }} 39 | Ok(new) 40 | }, 41 | } 42 | } 43 | } 44 | 45 | impl Delta for HashSet 46 | where T: Clone + Debug + PartialEq + Ord + Hash + Delta + IntoDelta 47 | + for<'de> Deserialize<'de> 48 | + Serialize, 49 | { 50 | fn delta(&self, rhs: &Self) -> DeltaResult { 51 | Ok(HashSetDelta(if self == rhs { 52 | None 53 | } else { 54 | let mut entry_deltas: Vec> = vec![]; 55 | for addition in rhs.difference(&self) { 56 | let addition = addition.clone().into_delta()?; 57 | entry_deltas.push(EntryDelta::Add { item: addition }); 58 | } 59 | for removal in self.difference(&rhs) { 60 | let removal = removal.clone().into_delta()?; 61 | entry_deltas.push(EntryDelta::Remove { item: removal }); 62 | } 63 | Some(entry_deltas) 64 | })) 65 | } 66 | } 67 | 68 | impl FromDelta for HashSet 69 | where T: Clone + Debug + PartialEq + Ord + Hash + FromDelta 70 | + for<'de> Deserialize<'de> 71 | + Serialize, 72 | { 73 | fn from_delta(delta: Self::Delta) -> DeltaResult { 74 | let mut map = Self::new(); 75 | if let Some(delta_entries) = delta.0 { 76 | for entry in delta_entries { match entry { 77 | EntryDelta::Add { item } => { 78 | map.insert(::from_delta(item)?); 79 | }, 80 | EntryDelta::Remove { item } => { 81 | let item = ::from_delta(item)?; 82 | map.remove(&item); 83 | }, 84 | }} 85 | } 86 | Ok(map) 87 | } 88 | } 89 | 90 | impl IntoDelta for HashSet 91 | where T: Clone + Debug + PartialEq + Ord + IntoDelta 92 | + for<'de> Deserialize<'de> 93 | + Serialize, 94 | { 95 | fn into_delta(self) -> DeltaResult { 96 | Ok(HashSetDelta(if self.is_empty() { 97 | None 98 | } else { 99 | let mut changes: Vec> = vec![]; 100 | for item in self { 101 | changes.push(EntryDelta::Add { item: item.into_delta()? }); 102 | } 103 | Some(changes) 104 | })) 105 | } 106 | } 107 | 108 | 109 | 110 | 111 | #[derive(Clone, PartialEq)] 112 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 113 | pub struct HashSetDelta( 114 | #[doc(hidden)] pub Option>>, 115 | ); 116 | 117 | impl HashSetDelta 118 | where T: Clone + Debug + PartialEq + Ord + Core 119 | + for<'de> Deserialize<'de> 120 | + Serialize, 121 | { 122 | pub fn iter<'d>(&'d self) -> Box> + 'd> { 123 | match &self.0 { 124 | Some(deltas) => Box::new(deltas.iter()), 125 | None => Box::new(std::iter::empty()), 126 | } 127 | } 128 | 129 | pub fn into_iter<'d>(self) -> Box> + 'd> 130 | where Self: 'd { 131 | match self.0 { 132 | Some(delta) => Box::new(delta.into_iter()), 133 | None => Box::new(std::iter::empty()), 134 | } 135 | } 136 | 137 | pub fn len(&self) -> usize { 138 | match &self.0 { 139 | Some(deltas) => deltas.len(), 140 | None => 0, 141 | } 142 | } 143 | } 144 | 145 | impl std::fmt::Debug for HashSetDelta 146 | where T: std::fmt::Debug + Core { 147 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 148 | write!(f, "HashSetDelta ")?; 149 | let mut buf = f.debug_list(); 150 | if let Some(d) = &self.0 { 151 | buf.entries(d.iter()); 152 | } else { 153 | buf.entries(std::iter::empty::>>()); 154 | } 155 | buf.finish() 156 | } 157 | } 158 | 159 | 160 | 161 | #[derive(Clone, PartialEq)] 162 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 163 | pub enum EntryDelta { 164 | Add { item: ::Delta }, 165 | Remove { item: ::Delta }, 166 | } 167 | 168 | impl std::fmt::Debug for EntryDelta 169 | where T: std::fmt::Debug + Core { 170 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 171 | match &self { 172 | Self::Add { item } => f.debug_struct("Add") 173 | .field("item", item) 174 | .finish(), 175 | Self::Remove { item } => f.debug_struct("Remove") 176 | .field("item", item) 177 | .finish(), 178 | } 179 | } 180 | } 181 | 182 | 183 | 184 | 185 | #[allow(non_snake_case)] 186 | #[cfg(test)] 187 | mod tests { 188 | use super::*; 189 | use std::collections::HashSet; 190 | 191 | macro_rules! set { 192 | ($($val:expr),* $(,)?) => {{ #[allow(redundant_semicolons)] { 193 | let mut set = HashSet::new(); 194 | $( set.insert($val); )* ; 195 | set 196 | }}} 197 | } 198 | 199 | #[test] 200 | fn HashSet__delta__same_values() -> DeltaResult<()> { 201 | let set0: HashSet = set! { 202 | "bar".into(), 203 | "foo".into(), 204 | "floozie".into(), 205 | "quux".into(), 206 | }; 207 | let set1: HashSet = set! { 208 | "bar".into(), 209 | "foo".into(), 210 | "floozie".into(), 211 | "quux".into(), 212 | }; 213 | let delta = set0.delta(&set1)?; 214 | let expected = HashSetDelta(None); 215 | assert_eq!(delta, expected); 216 | let set2 = set0.apply(delta)?; 217 | assert_eq!(set0, set2); 218 | assert_eq!(set1, set2); 219 | 220 | let delta = set1.delta(&set0)?; 221 | assert_eq!(delta, HashSetDelta(None)); 222 | let set3 = set1.apply(delta)?; 223 | assert_eq!(set0, set3); 224 | assert_eq!(set1, set3); 225 | 226 | Ok(()) 227 | } 228 | 229 | #[test] 230 | fn HashSet__delta__different_values() -> DeltaResult<()> { 231 | let set0: HashSet = set! { 232 | "bar".into(), 233 | "foo".into(), 234 | "floozie".into(), 235 | "quux".into(), 236 | }; 237 | let set1: HashSet = set! { 238 | "bar".into(), 239 | "baz".into(), 240 | "foo".into(), 241 | "quux".into(), 242 | }; 243 | let delta0 = set0.delta(&set1)?; 244 | let expected = HashSetDelta(Some(vec![ 245 | EntryDelta::Add { item: "baz".to_string().into_delta()? }, 246 | EntryDelta::Remove { item: "floozie".to_string().into_delta()? }, 247 | ])); 248 | assert_eq!(delta0, expected); 249 | let set2 = set0.apply(delta0)?; 250 | assert_eq!(set1, set2); 251 | 252 | let delta1 = set1.delta(&set0)?; 253 | assert_eq!(delta1, HashSetDelta(Some(vec![ 254 | EntryDelta::Add { item: "floozie".to_string().into_delta()? }, 255 | EntryDelta::Remove { item: "baz".to_string().into_delta()? }, 256 | ]))); 257 | let set3 = set1.apply(delta1)?; 258 | assert_eq!(set0, set3); 259 | 260 | Ok(()) 261 | } 262 | 263 | #[test] 264 | fn HashSet__apply__same_values() -> DeltaResult<()> { 265 | let set0: HashSet = set! { 266 | "bar".into(), 267 | "foo".into(), 268 | "floozie".into(), 269 | "quux".into(), 270 | }; 271 | let set1: HashSet = set! { 272 | "bar".into(), 273 | "foo".into(), 274 | "floozie".into(), 275 | "quux".into(), 276 | }; 277 | let delta = set0.delta(&set1)?; 278 | assert_eq!(delta, HashSetDelta(None)); 279 | let set2 = set0.apply(delta)?; 280 | assert_eq!(set1, set2); 281 | Ok(()) 282 | } 283 | 284 | #[test] 285 | fn HashSet__apply__different_values() -> DeltaResult<()> { 286 | let set0: HashSet = set! { 287 | "bar".into(), 288 | "foo".into(), 289 | "floozie".into(), 290 | "quux".into(), 291 | }; 292 | let set1: HashSet = set! { 293 | "bar".into(), 294 | "baz".into(), 295 | "foo".into(), 296 | "quux".into(), 297 | }; 298 | let delta = set0.delta(&set1)?; 299 | assert_eq!(delta, HashSetDelta(Some(vec![ 300 | EntryDelta::Add { item: "baz".to_string().into_delta()? }, 301 | EntryDelta::Remove { item: "floozie".to_string().into_delta()? }, 302 | ]))); 303 | let set2 = set0.apply(delta)?; 304 | assert_eq!(set1, set2); 305 | Ok(()) 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /deltoid/src/collections/mod.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | mod btreemap; 4 | mod btreeset; 5 | mod hashmap; 6 | mod hashset; 7 | mod vecdeque; 8 | 9 | pub use btreemap::*; 10 | pub use btreeset::*; 11 | pub use hashmap::*; 12 | pub use hashset::*; 13 | pub use vecdeque::*; 14 | -------------------------------------------------------------------------------- /deltoid/src/collections/vecdeque.rs: -------------------------------------------------------------------------------- 1 | //! A newtype wrapping [`VecDeque`] that provides extra functionality in 2 | //! the form of delta support, de/serialization, partial equality and more. 3 | //! 4 | //! [`VecDeque`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html 5 | 6 | use crate::{Apply, Core, Delta, DeltaError, DeltaResult, FromDelta, IntoDelta}; 7 | use serde::{Deserialize, Serialize}; 8 | use std::collections::VecDeque; 9 | use std::fmt::Debug; 10 | 11 | 12 | 13 | impl Core for VecDeque 14 | where T: Clone + Debug + PartialEq + Ord + Core 15 | + for<'de> Deserialize<'de> 16 | + Serialize, 17 | { 18 | type Delta = VecDequeDelta; 19 | } 20 | 21 | impl Apply for VecDeque 22 | where T: Clone + Debug + PartialEq + Ord + Apply + FromDelta 23 | + for<'de> Deserialize<'de> 24 | + Serialize, 25 | { 26 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 27 | let mut new: Self = self.clone(); 28 | for change in delta.into_iter() { match change { 29 | EltDelta::Edit { index, item } => { 30 | // NOTE: If self.len() == 0, the Edit should have been an Add: 31 | ensure_gt![self.len(), 0]?; 32 | // NOTE: Ensure index is within bounds: 33 | ensure_lt![index, self.len()]?; 34 | new[index] = self[index].apply(item)?; 35 | }, 36 | EltDelta::Add(delta) => new.push_back(::from_delta(delta)?), 37 | EltDelta::Remove { count } => for _ in 0 .. count { 38 | new.pop_back().ok_or_else(|| ExpectedValue!("VecDelta"))?; 39 | }, 40 | }} 41 | Ok(new) 42 | } 43 | } 44 | 45 | impl Delta for VecDeque 46 | where T: Clone + Debug + PartialEq + Ord + Delta + IntoDelta 47 | + for<'de> Deserialize<'de> 48 | + Serialize, 49 | { 50 | fn delta(&self, rhs: &Self) -> DeltaResult { 51 | let (lhs_len, rhs_len) = (self.len(), rhs.len()); 52 | let max_len = usize::max(lhs_len, rhs_len); 53 | let mut changes: VecDeque> = VecDeque::new(); 54 | for index in 0 .. max_len { match (self.get(index), rhs.get(index)) { 55 | (None, None) => return bug_detected!(), 56 | (Some(l), Some(r)) if l == r => {/*NOP*/}, 57 | (Some(l), Some(r)) => 58 | changes.push_back(EltDelta::Edit { index, item: l.delta(r)? }), 59 | (None, Some(r)) => 60 | changes.push_back(EltDelta::Add(r.clone().into_delta()?)), 61 | (Some(_), None) => { 62 | let last_change_idx = changes.len() - 1; 63 | match changes.get_mut(last_change_idx) { 64 | Some(EltDelta::Remove { ref mut count }) => *count += 1, 65 | _ => changes.push_back(EltDelta::Remove { count: 1 }), 66 | } 67 | }, 68 | }} 69 | Ok(VecDequeDelta(changes)) 70 | } 71 | } 72 | 73 | impl FromDelta for VecDeque 74 | where T: Clone + Debug + PartialEq + Ord + FromDelta 75 | + for<'de> Deserialize<'de> 76 | + Serialize 77 | { 78 | fn from_delta(delta: Self::Delta) -> DeltaResult { 79 | let mut changes: VecDeque = VecDeque::new(); 80 | for (index, element) in delta.0.into_iter().enumerate() { 81 | match element { 82 | EltDelta::Add(elt) => changes.push_back(::from_delta(elt)?), 83 | _ => return Err(DeltaError::IllegalDelta { index })?, 84 | } 85 | } 86 | Ok(changes) 87 | } 88 | } 89 | 90 | impl IntoDelta for VecDeque 91 | where T: Clone + Debug + PartialEq + Ord + IntoDelta 92 | + for<'de> Deserialize<'de> 93 | + Serialize 94 | { 95 | fn into_delta(self) -> DeltaResult { 96 | let mut changes: VecDeque> = VecDeque::new(); 97 | for elt in self { 98 | changes.push_back(EltDelta::Add(elt.into_delta()?)); 99 | } 100 | Ok(VecDequeDelta(changes)) 101 | } 102 | } 103 | 104 | 105 | 106 | 107 | #[derive(Clone, PartialEq)] 108 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 109 | pub struct VecDequeDelta(#[doc(hidden)] pub VecDeque>); 110 | 111 | impl VecDequeDelta { 112 | pub fn iter<'d>(&'d self) -> impl Iterator> + 'd { 113 | self.0.iter() 114 | } 115 | 116 | // pub fn iter<'d>(&'d self) -> Box> + 'd> { 117 | // Box::new(self.0.iter()) 118 | // } 119 | 120 | pub fn into_iter<'d>(self) -> impl Iterator> + 'd 121 | where Self: 'd { 122 | self.0.into_iter() 123 | } 124 | 125 | // pub fn into_iter<'d>(self) -> Box> + 'd> 126 | // where Self: 'd { 127 | // Box::new(self.0.into_iter()) 128 | // } 129 | 130 | pub fn len(&self) -> usize { self.0.len() } 131 | } 132 | 133 | impl std::fmt::Debug for VecDequeDelta 134 | where T: std::fmt::Debug + Core { 135 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 136 | write!(f, "VecDequeDelta ")?; 137 | f.debug_list().entries(self.0.iter()).finish() 138 | } 139 | } 140 | 141 | 142 | 143 | #[derive(Clone, PartialEq)] 144 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 145 | pub enum EltDelta { 146 | /// Edit a value at a given `index`. 147 | Edit { 148 | /// The location of the edit 149 | index: usize, 150 | /// The new value of the item 151 | item: ::Delta, 152 | }, 153 | /// Remove `count` elements from the end of the Vec. 154 | Remove { count: usize }, 155 | /// Add a value. 156 | Add(::Delta), 157 | } 158 | 159 | impl std::fmt::Debug for EltDelta { 160 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 161 | match &self { 162 | Self::Edit { index, item } => f.debug_struct("Edit") 163 | .field("index", index) 164 | .field("item", item) 165 | .finish(), 166 | Self::Remove { count } => f.debug_struct("Remove") 167 | .field("count", count) 168 | .finish(), 169 | Self::Add(delta) => write!(f, "Add({:#?})", delta), 170 | } 171 | } 172 | } 173 | 174 | 175 | 176 | 177 | 178 | 179 | #[cfg(test)] 180 | mod tests { 181 | use super::*; 182 | use std::collections::VecDeque; 183 | 184 | macro_rules! vecdeque { 185 | ($($item:expr),* $(,)?) => {{ 186 | #[allow(unused_mut)] 187 | let mut v = VecDeque::new(); 188 | $( v.push_back($item); )* 189 | v 190 | }} 191 | } 192 | 193 | #[allow(non_snake_case)] 194 | #[test] 195 | fn VecDeque__delta__same_values() -> DeltaResult<()> { 196 | let vecdeque0: VecDeque = vecdeque![ 197 | "bar".into(), 198 | "foo".into(), 199 | "floozie".into(), 200 | "quux".into(), 201 | ]; 202 | let vecdeque1: VecDeque = vecdeque![ 203 | "bar".into(), 204 | "foo".into(), 205 | "floozie".into(), 206 | "quux".into(), 207 | ]; 208 | let delta = vecdeque0.delta(&vecdeque1)?; 209 | let expected = VecDequeDelta(vecdeque![]); 210 | assert_eq!(delta, expected); 211 | let vecdeque2 = vecdeque0.apply(delta)?; 212 | assert_eq!(vecdeque0, vecdeque2); 213 | assert_eq!(vecdeque1, vecdeque2); 214 | 215 | let delta = vecdeque1.delta(&vecdeque0)?; 216 | assert_eq!(delta, VecDequeDelta(vecdeque![])); 217 | let vecdeque3 = vecdeque1.apply(delta)?; 218 | assert_eq!(vecdeque0, vecdeque3); 219 | assert_eq!(vecdeque1, vecdeque3); 220 | 221 | Ok(()) 222 | } 223 | 224 | #[allow(non_snake_case)] 225 | #[test] 226 | fn VecDeque__delta__different_values() -> DeltaResult<()> { 227 | let vecdeque0: VecDeque = vecdeque![ 228 | "bar".into(), 229 | "foo".into(), 230 | "floozie".into(), 231 | "quux".into(), 232 | ]; 233 | let vecdeque1: VecDeque = vecdeque![ 234 | "bar".into(), 235 | "baz".into(), 236 | "foo".into(), 237 | "quux".into(), 238 | "corge".into(), 239 | ]; 240 | let delta0 = vecdeque0.delta(&vecdeque1)?; 241 | let expected = VecDequeDelta(vecdeque![ // TODO 242 | EltDelta::Edit { index: 1, item: "baz".to_string().into_delta()? }, 243 | EltDelta::Edit { index: 2, item: "foo".to_string().into_delta()? }, 244 | EltDelta::Add("corge".to_string().into_delta()?), 245 | ]); 246 | assert_eq!(delta0, expected); 247 | let vecdeque2 = vecdeque0.apply(delta0)?; 248 | assert_eq!(vecdeque1, vecdeque2); 249 | 250 | let delta1 = vecdeque1.delta(&vecdeque0)?; 251 | assert_eq!(delta1, VecDequeDelta(vecdeque![ 252 | EltDelta::Edit { index: 1, item: "foo".to_string().into_delta()? }, 253 | EltDelta::Edit { index: 2, item: "floozie".to_string().into_delta()? }, 254 | EltDelta::Remove { count: 1 }, 255 | ])); 256 | let vecdeque3 = vecdeque1.apply(delta1)?; 257 | assert_eq!(vecdeque0, vecdeque3); 258 | 259 | Ok(()) 260 | } 261 | 262 | #[allow(non_snake_case)] 263 | #[test] 264 | fn VecDeque__apply__same_values() -> DeltaResult<()> { 265 | let vecdeque0: VecDeque = vecdeque![ 266 | "bar".into(), 267 | "foo".into(), 268 | "floozie".into(), 269 | "quux".into(), 270 | ]; 271 | let vecdeque1: VecDeque = vecdeque![ 272 | "bar".into(), 273 | "foo".into(), 274 | "floozie".into(), 275 | "quux".into(), 276 | ]; 277 | let delta = vecdeque0.delta(&vecdeque1)?; 278 | assert_eq!(delta, VecDequeDelta(vecdeque![])); 279 | let vecdeque2 = vecdeque0.apply(delta)?; 280 | assert_eq!(vecdeque1, vecdeque2); 281 | Ok(()) 282 | } 283 | 284 | #[allow(non_snake_case)] 285 | #[test] 286 | fn VecDeque__apply__different_values() -> DeltaResult<()> { 287 | let vecdeque0: VecDeque = vecdeque![ 288 | "bar".into(), 289 | "foo".into(), 290 | "floozie".into(), 291 | "quux".into(), 292 | ]; 293 | let vecdeque1: VecDeque = vecdeque![ 294 | "bar".into(), 295 | "baz".into(), 296 | "foo".into(), 297 | "quux".into(), 298 | ]; 299 | let delta = vecdeque0.delta(&vecdeque1)?; 300 | assert_eq!(delta, VecDequeDelta(vecdeque![ 301 | EltDelta::Edit { index: 1, item: "baz".to_string().into_delta()? }, 302 | EltDelta::Edit { index: 2, item: "foo".to_string().into_delta()? }, 303 | ])); 304 | let vecdeque2 = vecdeque0.apply(delta)?; 305 | assert_eq!(vecdeque1, vecdeque2); 306 | Ok(()) 307 | } 308 | 309 | } 310 | -------------------------------------------------------------------------------- /deltoid/src/core.rs: -------------------------------------------------------------------------------- 1 | //! Core definitions 2 | 3 | use crate::error::DeltaResult; 4 | use serde::{Deserialize, Serialize}; 5 | use std::fmt::Debug; 6 | 7 | /// Defines an associated Delta type. This is used by the other core traits 8 | /// to agree on a common Delta definition for each implementing type. 9 | pub trait Core { 10 | type Delta: Sized + Clone + Debug + PartialEq 11 | + for<'de> Deserialize<'de> 12 | + Serialize; 13 | } 14 | 15 | pub trait Apply: Core + Clone + Debug + PartialEq { 16 | /// Calculate a new instance of `Self` based on `self` and `delta` 17 | /// i.e. calculate `self --[delta]--> other`. 18 | /// ^^^^^ 19 | fn apply(&self, delta: Self::Delta) -> DeltaResult; 20 | } 21 | 22 | pub trait Delta: Core + Clone + Debug + PartialEq { 23 | /// Calculate `self --[delta]--> other`. 24 | /// ^^^^^ 25 | fn delta(&self, other: &Self) -> DeltaResult; 26 | } 27 | 28 | /// Conversion from type *Delta to type * 29 | pub trait FromDelta: Core + Sized { 30 | /// Convert `Self::Delta` to `Self`. 31 | fn from_delta(delta: Self::Delta) -> DeltaResult; 32 | } 33 | 34 | /// Conversion from type * to type *Delta 35 | pub trait IntoDelta: Core { 36 | /// Convert `Self` to `Self::Delta`. 37 | fn into_delta(self) -> DeltaResult; 38 | } 39 | 40 | 41 | macro_rules! impl_delta_trait_for_primitive_types { 42 | ( $($type:ty => $delta:ident $(: $($traits:ident),+)?);* $(;)? ) => { 43 | $( 44 | $( #[derive( $($traits),+ )] )? 45 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 46 | pub struct $delta(#[doc(hidden)] pub Option<$type>); 47 | 48 | impl Core for $type { 49 | type Delta = $delta; 50 | } 51 | 52 | impl Apply for $type { 53 | #[inline(always)] 54 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 55 | Self::from_delta(delta) 56 | } 57 | } 58 | 59 | impl Delta for $type { 60 | #[inline(always)] 61 | fn delta(&self, rhs: &Self) -> DeltaResult { 62 | rhs.clone().into_delta() 63 | } 64 | } 65 | 66 | impl FromDelta for $type { 67 | #[inline(always)] 68 | fn from_delta(delta: Self::Delta) -> DeltaResult { 69 | // TODO: perhaps turn the option to choose either returning 70 | // an error or a `Default` value into a policy? 71 | // match delta.0 { 72 | // Some(value) => Ok(value), 73 | // None => Ok(Self::default()), 74 | // } 75 | delta.0.ok_or_else(|| ExpectedValue!(stringify!($delta))) 76 | } 77 | } 78 | 79 | impl IntoDelta for $type { 80 | #[inline(always)] 81 | fn into_delta(self) -> DeltaResult { 82 | Ok($delta(Some(self))) 83 | } 84 | } 85 | 86 | impl std::fmt::Debug for $delta { 87 | fn fmt(&self, f: &mut std::fmt::Formatter) 88 | -> Result<(), std::fmt::Error> 89 | { 90 | match self.0 { 91 | None => 92 | write!(f, "{}(None)", stringify!($delta)), 93 | Some(prim) => 94 | write!(f, "{}({:#?})", stringify!($delta), prim), 95 | } 96 | } 97 | } 98 | )* 99 | }; 100 | } 101 | 102 | impl_delta_trait_for_primitive_types! { 103 | i8 => I8Delta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 104 | i16 => I16Delta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 105 | i32 => I32Delta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 106 | i64 => I64Delta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 107 | i128 => I128Delta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 108 | isize => IsizeDelta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 109 | 110 | u8 => U8Delta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 111 | u16 => U16Delta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 112 | u32 => U32Delta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 113 | u64 => U64Delta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 114 | u128 => U128Delta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 115 | usize => UsizeDelta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 116 | 117 | f32 => F32Delta: Clone, Copy, PartialEq, PartialOrd ; 118 | f64 => F64Delta: Clone, Copy, PartialEq, PartialOrd ; 119 | bool => BoolDelta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 120 | char => CharDelta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 121 | () => UnitDelta: Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash; 122 | } 123 | -------------------------------------------------------------------------------- /deltoid/src/error.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use crate::{Core, Apply, Delta, FromDelta, IntoDelta}; 4 | use serde_derive::{Deserialize, Serialize}; 5 | use std::sync::TryLockError; 6 | 7 | 8 | #[macro_export] 9 | macro_rules! ensure_eq { 10 | ($left:expr, $right:expr) => {{ 11 | let (lstr, rstr) = (stringify!($left), stringify!($right)); 12 | ensure!( 13 | $left == $right, 14 | "violation: {} == {}\n{} == {}\n{} == {}", 15 | lstr, rstr, 16 | lstr, $left, 17 | rstr, $right 18 | ) 19 | }}; 20 | } 21 | 22 | #[macro_export] 23 | macro_rules! ensure_ne { 24 | ($left:expr, $right:expr) => {{ 25 | let (lstr, rstr) = (stringify!($left), stringify!($right)); 26 | ensure!( 27 | $left != $right, 28 | "violation: {} != {}\n{} == {}\n{} == {}", 29 | lstr, rstr, 30 | lstr, $left, 31 | rstr, $right 32 | ) 33 | }}; 34 | } 35 | 36 | #[macro_export] 37 | macro_rules! ensure_gt { 38 | ($left:expr, $right:expr) => {{ 39 | let (lstr, rstr) = (stringify!($left), stringify!($right)); 40 | ensure!( 41 | $left > $right, 42 | "violation: {} > {}\n{} == {}\n{} == {}", 43 | lstr, rstr, 44 | lstr, $left, 45 | rstr, $right 46 | ) 47 | }}; 48 | } 49 | 50 | #[macro_export] 51 | macro_rules! ensure_lt { 52 | ($left:expr, $right:expr) => {{ 53 | let (lstr, rstr) = (stringify!($left), stringify!($right)); 54 | ensure!( 55 | $left < $right, 56 | "violation: {} < {}\n{} == {}\n{} == {}", 57 | lstr, rstr, 58 | lstr, $left, 59 | rstr, $right 60 | ) 61 | }}; 62 | } 63 | 64 | #[macro_export] 65 | macro_rules! ensure_ge { 66 | ($left:expr, $right:expr) => {{ 67 | let (lstr, rstr) = (stringify!($left), stringify!($right)); 68 | ensure!( 69 | $left >= $right, 70 | "violation: {} >= {}\n{} == {}\n{} == {}", 71 | lstr, rstr, 72 | lstr, $left, 73 | rstr, $right 74 | ) 75 | }}; 76 | } 77 | 78 | #[macro_export] 79 | macro_rules! ensure_le { 80 | ($left:expr, $right:expr) => {{ 81 | let (lstr, rstr) = (stringify!($left), stringify!($right)); 82 | ensure!( 83 | $left <= $right, 84 | "violation: {} <= {}\n{} == {}\n{} == {}", 85 | lstr, rstr, 86 | lstr, $left, 87 | rstr, $right 88 | ) 89 | }}; 90 | } 91 | 92 | #[macro_export] 93 | macro_rules! ensure { 94 | ($predicate:expr $(, $fmt:expr $(, $args:expr)*)? ) => { 95 | if $predicate { 96 | $crate::error::DeltaResult::Ok(()) 97 | } else { 98 | Err($crate::error::DeltaError::FailedToEnsure { 99 | predicate: stringify!($predicate).to_string(), 100 | msg: { 101 | #[allow(unused)] let mut msg = String::new(); 102 | $( msg = format!($fmt $(, $args)*); )? 103 | msg 104 | }, 105 | file: file!().to_string(), 106 | line: line!(), 107 | column: column!(), 108 | }) 109 | } 110 | }; 111 | } 112 | 113 | #[macro_export] 114 | macro_rules! bug_detected { 115 | ($($fmt:expr $(, $args:expr)*)?) => { 116 | Err($crate::error::DeltaError::BugDetected { 117 | msg: { #[allow(redundant_semicolons)] { 118 | #[allow(unused)] let mut msg = String::new(); 119 | $( msg = format!($fmt $(, $args)*); )? ; 120 | msg 121 | }}, 122 | file: file!().to_string(), 123 | line: line!(), 124 | column: column!(), 125 | }) 126 | }; 127 | } 128 | 129 | #[macro_export] 130 | macro_rules! ExpectedValue { 131 | ($name:expr) => { 132 | $crate::error::DeltaError::ExpectedValue { 133 | type_name: $name.to_string(), 134 | file: file!().to_string(), 135 | line: line!(), 136 | column: column!(), 137 | } 138 | }; 139 | } 140 | 141 | 142 | 143 | pub type DeltaResult = Result; 144 | 145 | #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 146 | #[derive(Deserialize, Serialize)] 147 | pub enum DeltaError { 148 | BugDetected { 149 | msg: String, 150 | file: String, 151 | line: u32, 152 | column: u32 153 | }, 154 | ExpectedValue { 155 | type_name: String, 156 | file: String, 157 | line: u32, 158 | column: u32 159 | }, 160 | FailedToEnsure { 161 | predicate: String, 162 | msg: String, 163 | file: String, 164 | line: u32, 165 | column: u32, 166 | }, 167 | FailedToApplyDelta { reason: String }, 168 | FailedToConvertFromDelta { reason: String }, 169 | IllegalDelta { index: usize }, 170 | RwLockAccessWouldBlock, 171 | RwLockPoisoned(String) 172 | } 173 | 174 | impl From> for DeltaError { 175 | fn from(err: TryLockError) -> DeltaError { 176 | match err { 177 | TryLockError::WouldBlock => 178 | DeltaError::RwLockAccessWouldBlock, 179 | TryLockError::Poisoned(psn_err) => 180 | DeltaError::RwLockPoisoned(format!("{}", psn_err)), 181 | } 182 | } 183 | } 184 | 185 | 186 | #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] 187 | pub struct DeltaErrorDelta(Option); 188 | 189 | impl Core for DeltaError { 190 | type Delta = DeltaErrorDelta; 191 | } 192 | 193 | impl Apply for DeltaError { 194 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 195 | match delta { 196 | DeltaErrorDelta(Some(derr)) => Ok(derr), 197 | DeltaErrorDelta(None) => Ok(self.clone()), 198 | } 199 | } 200 | } 201 | 202 | impl Delta for DeltaError { 203 | fn delta(&self, rhs: &Self) -> DeltaResult { 204 | Ok(DeltaErrorDelta(Some(rhs.clone()))) 205 | } 206 | } 207 | 208 | impl FromDelta for DeltaError { 209 | fn from_delta(delta: Self::Delta) -> DeltaResult { 210 | match delta { 211 | DeltaErrorDelta(Some(derr)) => Ok(derr), 212 | DeltaErrorDelta(None) => Err(DeltaError::FailedToConvertFromDelta { 213 | reason: format!("Got no delta to convert from"), 214 | }) 215 | } 216 | } 217 | } 218 | 219 | impl IntoDelta for DeltaError { 220 | fn into_delta(self) -> DeltaResult { 221 | Ok(DeltaErrorDelta(Some(self))) 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /deltoid/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | // TODO: 4 | // Can a delta be applied to a value of: 5 | // + a slice type e.g. &[T] and &str? (Very unlikely for borrowed types) 6 | 7 | #[macro_use] pub mod error; 8 | #[macro_use] pub mod snapshot; 9 | pub mod core; 10 | 11 | pub mod arrays; 12 | pub mod borrow; 13 | pub mod boxed; 14 | pub mod collections; 15 | pub mod option; 16 | pub mod range; 17 | pub mod result; 18 | pub mod rc; 19 | pub mod string; 20 | pub mod sync; 21 | pub mod tuple; 22 | pub mod vec; 23 | 24 | 25 | pub use crate::core::*; 26 | pub use crate::borrow::CowDelta; 27 | pub use crate::boxed::*; 28 | pub use crate::collections::*; 29 | pub use crate::error::{DeltaError, DeltaResult}; 30 | pub use crate::option::OptionDelta; 31 | pub use crate::range::RangeDelta; 32 | pub use crate::rc::*; 33 | pub use crate::string::{Str, StringDelta}; 34 | pub use crate::sync::*; 35 | pub use crate::tuple::*; 36 | pub use crate::vec::{EltDelta, VecDelta}; 37 | -------------------------------------------------------------------------------- /deltoid/src/option.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use crate::{Apply, Core, Delta, DeltaResult, FromDelta, IntoDelta}; 4 | use std::fmt::Debug; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | impl Core for Option 8 | where T: Clone + Debug + PartialEq + Core 9 | + for<'de> Deserialize<'de> 10 | + Serialize 11 | { 12 | type Delta = OptionDelta; 13 | } 14 | 15 | impl Apply for Option 16 | where T: Apply + FromDelta 17 | + for<'de> Deserialize<'de> 18 | + Serialize 19 | { 20 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 21 | Ok(match (&self, delta) { 22 | (None, Self::Delta::None) => None, 23 | (Some(_), Self::Delta::None) => self.clone(), 24 | (None, Self::Delta::Some(ref d)) => Some( 25 | ::from_delta(d.clone(/*TODO: rm clone for more efficiency*/))? 26 | ), 27 | (Some(t), Self::Delta::Some(ref d)) => 28 | Some(t.apply(d.clone(/*TODO: rm clone for more efficiency*/))?), 29 | }) 30 | } 31 | } 32 | 33 | impl Delta for Option 34 | where T: Delta + IntoDelta 35 | + for<'de> Deserialize<'de> 36 | + Serialize 37 | { 38 | fn delta(&self, rhs: &Self) -> DeltaResult { 39 | Ok(match (self, rhs) { 40 | (Some(lhs), Some(rhs)) => Self::Delta::Some(lhs.delta(&rhs)?), 41 | (None, Some(rhs)) => Self::Delta::Some(rhs.clone().into_delta()?), 42 | (Some(_), None) => Self::Delta::None, 43 | (None, None) => Self::Delta::None, 44 | }) 45 | } 46 | } 47 | 48 | impl FromDelta for Option 49 | where T: Clone + Debug + PartialEq + FromDelta 50 | + for<'de> Deserialize<'de> 51 | + Serialize 52 | { 53 | fn from_delta(delta: ::Delta) -> DeltaResult { 54 | Ok(match delta { 55 | Self::Delta::None => None, 56 | Self::Delta::Some(delta) => Some(::from_delta(delta)?), 57 | }) 58 | } 59 | } 60 | 61 | impl IntoDelta for Option 62 | where T: Clone + Debug + PartialEq + IntoDelta 63 | + for<'de> Deserialize<'de> 64 | + Serialize 65 | { 66 | fn into_delta(self) -> DeltaResult<::Delta> { 67 | Ok(match self { 68 | Self::None => OptionDelta::None, 69 | Self::Some(t) => OptionDelta::Some(t.into_delta()?), 70 | }) 71 | } 72 | } 73 | 74 | 75 | 76 | #[derive(Clone, PartialEq)] 77 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 78 | pub enum OptionDelta { 79 | None, 80 | Some(::Delta), 81 | } 82 | 83 | impl std::fmt::Debug for OptionDelta { 84 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 85 | match &self { 86 | Self::Some(d) => write!(f, "OptionDelta::Some({:#?})", d), 87 | Self::None => write!(f, "OptionDelta::None"), 88 | } 89 | } 90 | } 91 | 92 | 93 | #[allow(non_snake_case)] 94 | #[cfg(test)] 95 | mod tests { 96 | use serde_json; 97 | use super::*; 98 | 99 | #[test] 100 | fn Option__delta__same_values() -> DeltaResult<()> { 101 | let foo = String::from("foo"); 102 | let bar = String::from("foo"); 103 | let option0 = Some(foo); 104 | let option1 = Some(bar); 105 | let delta: as Core>::Delta = option0.delta(&option1)?; 106 | let json_string = serde_json::to_string(&delta) 107 | .expect("Could not serialize to json"); 108 | println!("json_string: \"{}\"", json_string); 109 | assert_eq!(json_string, "{\"Some\":\"foo\"}"); 110 | let delta1: as Core>::Delta = serde_json::from_str( 111 | &json_string 112 | ).expect("Could not deserialize from json"); 113 | assert_eq!(delta, delta1); 114 | Ok(()) 115 | } 116 | 117 | #[test] 118 | fn Option__delta__different_values() -> DeltaResult<()> { 119 | let foo = String::from("foo"); 120 | let bar = String::from("bar"); 121 | let option0 = Some(foo); 122 | let option1 = Some(bar); 123 | let delta: as Core>::Delta = option0.delta(&option1)?; 124 | let json_string = serde_json::to_string(&delta) 125 | .expect("Could not serialize to json"); 126 | println!("json_string: \"{}\"", json_string); 127 | assert_eq!(json_string, "{\"Some\":\"bar\"}"); 128 | let delta1: as Core>::Delta = serde_json::from_str( 129 | &json_string 130 | ).expect("Could not deserialize from json"); 131 | assert_eq!(delta, delta1); 132 | Ok(()) 133 | } 134 | 135 | #[test] 136 | fn Option__apply__same_values() -> DeltaResult<()> { 137 | let foo = String::from("foo"); 138 | let bar = String::from("foo"); 139 | let option0 = Some(foo); 140 | let option1 = Some(bar); 141 | let delta: as Core>::Delta = option0.delta(&option1)?; 142 | let option2 = option0.apply(delta)?; 143 | assert_eq!(option1, option2); 144 | Ok(()) 145 | } 146 | 147 | #[test] 148 | fn Option__apply__different_values() -> DeltaResult<()> { 149 | let foo = String::from("foo"); 150 | let bar = String::from("bar"); 151 | let option0 = Some(foo); 152 | let option1 = Some(bar); 153 | let delta: as Core>::Delta = option0.delta(&option1)?; 154 | let option2 = option0.apply(delta)?; 155 | assert_eq!(option1, option2); 156 | Ok(()) 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /deltoid/src/range.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use crate::{Apply, Core, Delta, DeltaResult, FromDelta, IntoDelta}; 4 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 5 | use serde::de; 6 | use serde::ser::SerializeMap; 7 | use std::fmt::{self, Debug}; 8 | use std::marker::PhantomData; 9 | use std::ops::Range; 10 | 11 | 12 | impl Core for Range 13 | where T: Clone + Debug + PartialEq + Core 14 | + for<'de> Deserialize<'de> 15 | + Serialize 16 | { 17 | type Delta = RangeDelta; 18 | } 19 | 20 | impl Apply for Range 21 | where T: Apply 22 | + for<'de> Deserialize<'de> 23 | + Serialize 24 | { 25 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 26 | match delta.0 { 27 | Some(range) => Ok(range.start .. range.end), 28 | None => Ok(self.start.clone() .. self.end.clone()), 29 | } 30 | } 31 | } 32 | 33 | impl Delta for Range 34 | where T: Delta 35 | + for<'de> Deserialize<'de> 36 | + Serialize 37 | { 38 | fn delta(&self, rhs: &Self) -> DeltaResult { 39 | Ok(RangeDelta(if self == rhs { 40 | None 41 | } else { 42 | Some(rhs.clone()) 43 | })) 44 | } 45 | } 46 | 47 | impl FromDelta for Range 48 | where T: Clone + Debug + PartialEq + FromDelta 49 | + for<'de> Deserialize<'de> 50 | + Serialize 51 | { 52 | fn from_delta(delta: Self::Delta) -> DeltaResult { 53 | Ok(delta.0.ok_or_else(|| ExpectedValue!("RangeDelta"))?) 54 | } 55 | } 56 | 57 | impl IntoDelta for Range 58 | where T: Clone + Debug + PartialEq + IntoDelta 59 | + for<'de> Deserialize<'de> 60 | + Serialize 61 | { 62 | fn into_delta(self) -> DeltaResult { 63 | Ok(RangeDelta(Some(self))) 64 | } 65 | } 66 | 67 | 68 | 69 | #[derive(Clone, PartialEq, Hash)] 70 | pub struct RangeDelta(#[doc(hidden)] pub Option>); 71 | 72 | impl std::fmt::Debug for RangeDelta 73 | where T: Core + std::fmt::Debug { 74 | fn fmt(&self, f: &mut std::fmt::Formatter) 75 | -> Result<(), std::fmt::Error> 76 | { 77 | match &self.0 { 78 | Some(field) => write!(f, "RangeDelta({:#?})", field), 79 | None => write!(f, "RangeDelta(None)"), 80 | } 81 | } 82 | } 83 | 84 | impl Serialize for RangeDelta 85 | where T: Core 86 | + Clone 87 | + Serialize 88 | { 89 | fn serialize(&self, serializer: S) -> Result 90 | where S: Serializer { 91 | let mut num_fields = 0; 92 | if self.0.is_some() { num_fields += 1; } 93 | let mut s = serializer.serialize_map(Some(num_fields))?; 94 | if let Some(inner) = &self.0 { 95 | s.serialize_entry("0", inner)?; 96 | } 97 | s.end() 98 | } 99 | } 100 | 101 | impl<'de, T> Deserialize<'de> for RangeDelta 102 | where T: Core 103 | + Clone 104 | + Deserialize<'de> 105 | { 106 | fn deserialize(deserializer: D) -> Result 107 | where D: Deserializer<'de> { 108 | struct DeltaVisitor(PhantomData); 109 | 110 | impl<'de, T2> de::Visitor<'de> for DeltaVisitor 111 | where T2: Core 112 | + Clone 113 | + Deserialize<'de> 114 | { 115 | type Value = RangeDelta; 116 | 117 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 118 | formatter.write_str("a RangeDelta") 119 | } 120 | 121 | fn visit_map(self, mut map: M) -> Result 122 | where M: de::MapAccess<'de> { 123 | let mut delta: Self::Value = RangeDelta(None); 124 | const EXPECTED_FIELDS: &[&str] = &["0"]; 125 | while let Some((key, value)) = map.next_entry()? { 126 | match (key, value) { 127 | ("0", value) => delta.0 = Some(value), 128 | (field_name, _) => return Err(de::Error::unknown_field( 129 | field_name, EXPECTED_FIELDS 130 | ))?, 131 | } 132 | } 133 | Ok(delta) 134 | } 135 | } 136 | 137 | deserializer.deserialize_map(DeltaVisitor(PhantomData)) 138 | } 139 | } 140 | 141 | 142 | 143 | #[allow(non_snake_case)] 144 | #[cfg(test)] 145 | mod tests { 146 | use serde_json; 147 | use super::*; 148 | 149 | #[test] 150 | fn Range__delta___same_values() -> DeltaResult<()> { 151 | let range0 = 1..10; 152 | let range1 = 1..10; 153 | let delta: as Core>::Delta = range0.delta(&range1)?; 154 | let json_string = serde_json::to_string(&delta) 155 | .expect("Could not serialize to json"); 156 | println!("json_string: \"{}\"", json_string); 157 | assert_eq!(json_string, "{}"); 158 | let delta1: as Core>::Delta = serde_json::from_str( 159 | &json_string 160 | ).expect("Could not deserialize from json"); 161 | assert_eq!(delta, delta1); 162 | Ok(()) 163 | } 164 | 165 | #[test] 166 | fn Range__delta___different_values() -> DeltaResult<()> { 167 | let range0 = 1..10; 168 | let range1 = 1..11; 169 | let delta: as Core>::Delta = range0.delta(&range1)?; 170 | let json_string = serde_json::to_string(&delta) 171 | .expect("Could not serialize to json"); 172 | println!("json_string: \"{}\"", json_string); 173 | assert_eq!(json_string, "{\"0\":{\"start\":1,\"end\":11}}"); 174 | let delta1: as Core>::Delta = serde_json::from_str( 175 | &json_string 176 | ).expect("Could not deserialize from json"); 177 | assert_eq!(delta, delta1); 178 | Ok(()) 179 | } 180 | 181 | #[test] 182 | fn Range__apply__same_values() -> DeltaResult<()> { 183 | let range0 = 1..10; 184 | let range1 = 1..10; 185 | let delta: as Core>::Delta = range0.delta(&range1)?; 186 | let range2 = range0.apply(delta)?; 187 | assert_eq!(range0, range2); 188 | Ok(()) 189 | } 190 | 191 | #[test] 192 | fn Range__apply__different_values() -> DeltaResult<()> { 193 | let range0 = 1..10; 194 | let range1 = 1..11; 195 | let delta: as Core>::Delta = range0.delta(&range1)?; 196 | let range2 = range0.apply(delta)?; 197 | assert_eq!(range1, range2); 198 | Ok(()) 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /deltoid/src/rc.rs: -------------------------------------------------------------------------------- 1 | //! A Deltoid impl for [`Rc`] that provides extra functionality in 2 | //! the form of delta support, de/serialization, partial equality and more. 3 | //! 4 | //! [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html 5 | 6 | use crate::{Apply, Core, Delta, DeltaResult, FromDelta, IntoDelta}; 7 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 8 | use serde::de; 9 | use serde::ser::SerializeMap; 10 | use std::fmt::{self, Debug}; 11 | use std::marker::PhantomData; 12 | use std::rc::Rc; 13 | 14 | 15 | impl Core for Rc 16 | where T: Clone + Debug + PartialEq + Core 17 | + for<'de> Deserialize<'de> 18 | + Serialize 19 | { 20 | type Delta = RcDelta; 21 | } 22 | 23 | impl Apply for Rc 24 | where T: Apply 25 | + for<'de> Deserialize<'de> 26 | + Serialize 27 | { 28 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 29 | let lhs: &T = self.as_ref(); 30 | match delta.0 { 31 | None => Ok(self.clone()), 32 | Some(delta) => lhs.apply(*delta).map(Rc::new), 33 | } 34 | } 35 | } 36 | 37 | impl Delta for Rc 38 | where T: Delta 39 | + for<'de> Deserialize<'de> 40 | + Serialize 41 | { 42 | fn delta(&self, rhs: &Self) -> DeltaResult { 43 | let lhs: &T = self.as_ref(); 44 | let rhs: &T = rhs.as_ref(); 45 | Ok(RcDelta(if lhs == rhs { 46 | None 47 | } else { 48 | Some(Box::new(lhs.delta(rhs)?)) 49 | })) 50 | } 51 | } 52 | 53 | impl FromDelta for Rc 54 | where T: Clone + Debug + PartialEq + FromDelta 55 | + for<'de> Deserialize<'de> 56 | + Serialize 57 | { 58 | fn from_delta(delta: ::Delta) -> DeltaResult { 59 | let delta = delta.0.ok_or_else(|| ExpectedValue!("RcDelta"))?; 60 | ::from_delta(*delta).map(Rc::new) 61 | } 62 | } 63 | 64 | impl IntoDelta for Rc 65 | where T: Clone + Debug + PartialEq + IntoDelta 66 | + for<'de> Deserialize<'de> 67 | + Serialize 68 | { 69 | fn into_delta(self) -> DeltaResult<::Delta> { 70 | let thing: T = self.as_ref().clone(); 71 | thing.into_delta().map(Box::new).map(Some).map(RcDelta) 72 | } 73 | } 74 | 75 | 76 | 77 | #[derive(Clone, PartialEq)] 78 | pub struct RcDelta( 79 | #[doc(hidden)] pub Option::Delta>> 80 | ); 81 | 82 | impl std::fmt::Debug for RcDelta { 83 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 84 | match &self.0 { 85 | Some(d) => write!(f, "RcDelta({:#?})", d), 86 | None => write!(f, "RcDelta(None)"), 87 | } 88 | } 89 | } 90 | 91 | impl Serialize for RcDelta { 92 | fn serialize(&self, serializer: S) -> Result 93 | where S: Serializer { 94 | let mut num_fields = 0; 95 | if self.0.is_some() { num_fields += 1; } 96 | let mut s = serializer.serialize_map(Some(num_fields))?; 97 | if let Some(inner) = &self.0 { 98 | s.serialize_entry("0", inner)?; 99 | } 100 | s.end() 101 | } 102 | } 103 | 104 | impl<'de, T: Core + Clone> Deserialize<'de> for RcDelta { 105 | fn deserialize(deserializer: D) -> Result 106 | where D: Deserializer<'de> { 107 | struct DeltaVisitor(PhantomData); 108 | 109 | impl<'de, T2> de::Visitor<'de> for DeltaVisitor 110 | where T2: Core + Clone { 111 | type Value = RcDelta; 112 | 113 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 114 | formatter.write_str("a RcDelta") 115 | } 116 | 117 | fn visit_map(self, mut map: M) -> Result 118 | where M: de::MapAccess<'de> { 119 | let mut delta: Self::Value = RcDelta(None); 120 | const EXPECTED_FIELDS: &[&str] = &["0"]; 121 | while let Some((key, value)) = map.next_entry()? { 122 | match (key, value) { 123 | ("0", value) => delta.0 = Some(value), 124 | (field_name, _) => return Err(de::Error::unknown_field( 125 | field_name, EXPECTED_FIELDS 126 | ))?, 127 | } 128 | } 129 | Ok(delta) 130 | } 131 | } 132 | 133 | deserializer.deserialize_map(DeltaVisitor(PhantomData)) 134 | } 135 | } 136 | 137 | 138 | 139 | #[allow(non_snake_case)] 140 | #[cfg(test)] 141 | mod tests { 142 | use serde_json; 143 | use super::*; 144 | 145 | #[test] 146 | fn Rc__delta___same_values() -> DeltaResult<()> { 147 | let foo = String::from("foo"); 148 | let bar = String::from("foo"); 149 | let box0 = Rc::new(foo); 150 | let box1 = Rc::new(bar); 151 | let delta: as Core>::Delta = box0.delta(&box1)?; 152 | let json_string = serde_json::to_string(&delta) 153 | .expect("Could not serialize to json"); 154 | println!("json_string: \"{}\"", json_string); 155 | assert_eq!(json_string, "{}"); 156 | let delta1: as Core>::Delta = serde_json::from_str( 157 | &json_string 158 | ).expect("Could not deserialize from json"); 159 | assert_eq!(delta, delta1); 160 | Ok(()) 161 | } 162 | 163 | #[test] 164 | fn Rc__delta___different_values() -> DeltaResult<()> { 165 | let foo = String::from("foo"); 166 | let bar = String::from("bar"); 167 | let box0 = Rc::new(foo); 168 | let box1 = Rc::new(bar); 169 | let delta: as Core>::Delta = box0.delta(&box1)?; 170 | let json_string = serde_json::to_string(&delta) 171 | .expect("Could not serialize to json"); 172 | println!("json_string: \"{}\"", json_string); 173 | assert_eq!(json_string, "{\"0\":\"bar\"}"); 174 | let delta1: as Core>::Delta = serde_json::from_str( 175 | &json_string 176 | ).expect("Could not deserialize from json"); 177 | assert_eq!(delta, delta1); 178 | Ok(()) 179 | } 180 | 181 | #[test] 182 | fn Rc__apply__same_values() -> DeltaResult<()> { 183 | let foo = String::from("foo"); 184 | let bar = String::from("foo"); 185 | let box0 = Rc::new(foo); 186 | let box1 = Rc::new(bar); 187 | let delta: as Core>::Delta = box0.delta(&box1)?; 188 | let box2 = box0.apply(delta)?; 189 | assert_eq!(box1, box2); 190 | Ok(()) 191 | } 192 | 193 | #[test] 194 | fn Rc__apply__different_values() -> DeltaResult<()> { 195 | let foo = String::from("foo"); 196 | let bar = String::from("bar"); 197 | let box0 = Rc::new(foo); 198 | let box1 = Rc::new(bar); 199 | let delta: as Core>::Delta = box0.delta(&box1)?; 200 | let box2 = box0.apply(delta)?; 201 | assert_eq!(box1, box2); 202 | Ok(()) 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /deltoid/src/result.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use crate::{Apply, Core, Delta, DeltaResult, FromDelta, IntoDelta}; 4 | use serde::{Deserialize, Serialize}; 5 | use std::fmt::Debug; 6 | 7 | impl Core for Result 8 | where T: Clone + Debug + PartialEq + Core + for<'de> Deserialize<'de> + Serialize, 9 | E: Clone + Debug + PartialEq + Core + for<'de> Deserialize<'de> + Serialize, 10 | { 11 | type Delta = ResultDelta; 12 | } 13 | 14 | impl Apply for Result 15 | where T: Apply + FromDelta + for<'de> Deserialize<'de> + Serialize, 16 | E: Apply + FromDelta + for<'de> Deserialize<'de> + Serialize 17 | { 18 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 19 | match (self, &delta/*TODO: match by value*/) { 20 | (Result::Ok(ok), ResultDelta::None) => Ok(Ok(ok.clone())), 21 | (Result::Ok(ok), ResultDelta::OkDelta(delta)) => { 22 | Ok(Ok(ok.apply(delta.clone(/*TODO: rm*/))?)) 23 | }, 24 | (Result::Ok(_ok), delta @ ResultDelta::ErrDelta(_)) => { 25 | Ok(Self::from_delta(delta.clone())?) 26 | }, 27 | (Result::Err(err), ResultDelta::None) => Ok(Err(err.clone())), 28 | (Result::Err(_err), delta @ ResultDelta::OkDelta(_)) => { 29 | Ok(Self::from_delta(delta.clone())?) 30 | }, 31 | (Result::Err(err), ResultDelta::ErrDelta(delta)) => { 32 | Ok(Err(err.apply(delta.clone(/*TODO: rm*/))?)) 33 | }, 34 | } 35 | } 36 | } 37 | 38 | impl Delta for Result 39 | where T: Delta + IntoDelta + for<'de> Deserialize<'de> + Serialize, 40 | E: Delta + IntoDelta + for<'de> Deserialize<'de> + Serialize 41 | { 42 | fn delta(&self, rhs: &Self) -> DeltaResult { 43 | match (self, rhs) { 44 | (Ok(lhs), Ok(rhs)) if lhs == rhs => Ok(ResultDelta::None), 45 | (Ok(lhs), Ok(rhs)) => 46 | Ok(ResultDelta::OkDelta(lhs.delta(rhs)?)), 47 | (Ok(_lhs), Err(rhs)) => 48 | Ok(ResultDelta::ErrDelta(rhs.clone().into_delta()?)), 49 | (Err(_lhs), Ok(rhs)) => 50 | Ok(ResultDelta::OkDelta(rhs.clone().into_delta()?)), 51 | (Err(lhs), Err(rhs)) if lhs == rhs => Ok(ResultDelta::None), 52 | (Err(_lhs), Err(rhs)) => 53 | Ok(ResultDelta::ErrDelta(rhs.clone().into_delta()?)), 54 | } 55 | } 56 | } 57 | 58 | impl FromDelta for Result 59 | where T: Clone + Debug + PartialEq + FromDelta 60 | + for<'de> Deserialize<'de> 61 | + Serialize, 62 | E: Clone + Debug + PartialEq + FromDelta 63 | + for<'de> Deserialize<'de> 64 | + Serialize 65 | { 66 | fn from_delta(delta: Self::Delta) -> DeltaResult { 67 | match delta { 68 | ResultDelta::None => Err(ExpectedValue!("ResultDelta")), 69 | ResultDelta::OkDelta(delta) => 70 | Ok(Self::Ok(::from_delta(delta)?)), 71 | ResultDelta::ErrDelta(delta) => 72 | Ok(Self::Err(::from_delta(delta)?)), 73 | } 74 | } 75 | } 76 | 77 | impl IntoDelta for Result 78 | where T: Clone + Debug + PartialEq + IntoDelta 79 | + for<'de> Deserialize<'de> 80 | + Serialize, 81 | E: Clone + Debug + PartialEq + IntoDelta 82 | + for<'de> Deserialize<'de> 83 | + Serialize 84 | { 85 | fn into_delta(self) -> DeltaResult { 86 | match self { 87 | Ok(ok) => Ok(ResultDelta::OkDelta(ok.into_delta()?)), 88 | Err(err) => Ok(ResultDelta::ErrDelta(err.into_delta()?)), 89 | } 90 | } 91 | } 92 | 93 | 94 | 95 | #[derive(Clone, PartialEq)] 96 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 97 | pub enum ResultDelta { 98 | OkDelta(::Delta), 99 | ErrDelta(::Delta), 100 | None 101 | } 102 | 103 | impl std::fmt::Debug for ResultDelta 104 | where T: Core, E: Core { 105 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 106 | match &self { 107 | Self::OkDelta(ok) => write!(f, "ResultDelta::Ok({:#?})", ok), 108 | Self::ErrDelta(err) => write!(f, "ResultDelta::Err({:#?})", err), 109 | Self::None => write!(f, "ResultDelta::None"), 110 | } 111 | } 112 | } 113 | 114 | 115 | #[allow(non_snake_case)] 116 | #[cfg(test)] 117 | mod tests { 118 | use serde_json; 119 | use super::*; 120 | 121 | #[test] 122 | fn Result_Ok__delta__same_values() -> DeltaResult<()> { 123 | let foo = String::from("foo"); 124 | let bar = String::from("foo"); 125 | let box0 = Ok(foo); 126 | let box1 = Ok(bar); 127 | let delta: as Core>::Delta = box0.delta(&box1)?; 128 | let json_string = serde_json::to_string(&delta) 129 | .expect("Could not serialize to json"); 130 | println!("json_string: \"{}\"", json_string); 131 | assert_eq!(json_string, "\"None\""); 132 | let delta1: as Core>::Delta = serde_json::from_str( 133 | &json_string 134 | ).expect("Could not deserialize from json"); 135 | assert_eq!(delta, delta1); 136 | Ok(()) 137 | } 138 | 139 | #[test] 140 | fn Result_Ok__delta__different_values() -> DeltaResult<()> { 141 | let foo = String::from("foo"); 142 | let bar = String::from("bar"); 143 | let box0 = Ok(foo); 144 | let box1 = Ok(bar); 145 | let delta: as Core>::Delta = box0.delta(&box1)?; 146 | let json_string = serde_json::to_string(&delta) 147 | .expect("Could not serialize to json"); 148 | println!("json_string: \"{}\"", json_string); 149 | assert_eq!(json_string, "{\"OkDelta\":\"bar\"}"); 150 | let delta1: as Core>::Delta = serde_json::from_str( 151 | &json_string 152 | ).expect("Could not deserialize from json"); 153 | assert_eq!(delta, delta1); 154 | Ok(()) 155 | } 156 | 157 | #[test] 158 | fn Result_Ok__apply__same_values() -> DeltaResult<()> { 159 | let foo = String::from("foo"); 160 | let bar = String::from("foo"); 161 | let box0 = Ok(foo); 162 | let box1 = Ok(bar); 163 | let delta: as Core>::Delta = box0.delta(&box1)?; 164 | let box2 = box0.apply(delta)?; 165 | assert_eq!(box1, box2); 166 | Ok(()) 167 | } 168 | 169 | #[test] 170 | fn Result_Ok__apply__different_values() -> DeltaResult<()> { 171 | let foo = String::from("foo"); 172 | let bar = String::from("bar"); 173 | let box0 = Ok(foo); 174 | let box1 = Ok(bar); 175 | let delta: as Core>::Delta = box0.delta(&box1)?; 176 | let box2 = box0.apply(delta)?; 177 | assert_eq!(box1, box2); 178 | Ok(()) 179 | } 180 | 181 | #[test] 182 | fn Result_Err__delta__same_values() -> DeltaResult<()> { 183 | let foo = String::from("foo"); 184 | let bar = String::from("foo"); 185 | let box0 = Err(foo); 186 | let box1 = Err(bar); 187 | let delta: as Core>::Delta = box0.delta(&box1)?; 188 | let json_string = serde_json::to_string(&delta) 189 | .expect("Could not serialize to json"); 190 | println!("json_string: \"{}\"", json_string); 191 | assert_eq!(json_string, "\"None\""); 192 | let delta1: as Core>::Delta = serde_json::from_str( 193 | &json_string 194 | ).expect("Could not deserialize from json"); 195 | assert_eq!(delta, delta1); 196 | Ok(()) 197 | } 198 | 199 | #[test] 200 | fn Result_Err__delta__different_values() -> DeltaResult<()> { 201 | let foo = String::from("foo"); 202 | let bar = String::from("bar"); 203 | let box0 = Err(foo); 204 | let box1 = Err(bar); 205 | let delta: as Core>::Delta = box0.delta(&box1)?; 206 | let json_string = serde_json::to_string(&delta) 207 | .expect("Could not serialize to json"); 208 | println!("json_string: \"{}\"", json_string); 209 | assert_eq!(json_string, "{\"ErrDelta\":\"bar\"}"); 210 | let delta1: as Core>::Delta = serde_json::from_str( 211 | &json_string 212 | ).expect("Could not deserialize from json"); 213 | assert_eq!(delta, delta1); 214 | Ok(()) 215 | } 216 | 217 | #[test] 218 | fn Result_Err__apply__same_values() -> DeltaResult<()> { 219 | let foo = String::from("foo"); 220 | let bar = String::from("foo"); 221 | let box0 = Err(foo); 222 | let box1 = Err(bar); 223 | let delta: as Core>::Delta = box0.delta(&box1)?; 224 | let box2 = box0.apply(delta)?; 225 | assert_eq!(box1, box2); 226 | Ok(()) 227 | } 228 | 229 | #[test] 230 | fn Result_Err__apply__different_values() -> DeltaResult<()> { 231 | let foo = String::from("foo"); 232 | let bar = String::from("bar"); 233 | let box0 = Err(foo); 234 | let box1 = Err(bar); 235 | let delta: as Core>::Delta = box0.delta(&box1)?; 236 | let box2 = box0.apply(delta)?; 237 | assert_eq!(box1, box2); 238 | Ok(()) 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /deltoid/src/snapshot/delta.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use chrono::prelude::{DateTime, Utc}; 4 | use crate::{Apply, Core, Delta, DeltaError, DeltaResult}; 5 | use crate::snapshot::SnapshotCtx; 6 | use crate::snapshot::full::{FullSnapshot, FullSnapshots}; 7 | use serde_derive::{Deserialize, Serialize}; 8 | use std::cmp::Ordering; 9 | use std::hash::{Hash, Hasher}; 10 | 11 | #[macro_export] 12 | macro_rules! delta_snapshot { 13 | ( 14 | use result type $result_type:ty; 15 | [$($origin:ident)::*] $($new_state:expr),+ => $ctx:expr 16 | $(; $fmt:expr $(, $arg:expr)* )? 17 | ) => { loop { 18 | #[cfg(feature = "snapshot")] 19 | #[allow(redundant_semicolons, unused)] { 20 | let mut origin = String::new(); 21 | $( 22 | if !origin.is_empty() { origin.push_str("::"); } 23 | origin.push_str(stringify!($origin)); 24 | )* ; 25 | let mut msg: Option = None; 26 | $( 27 | msg = Some(format!($fmt $(, $arg)*)); 28 | )? ; 29 | $( 30 | let result = $crate::snapshot::delta::delta_snapshot( 31 | $ctx, 32 | origin.clone(), 33 | msg.clone(), 34 | $new_state 35 | ); 36 | if let Err(err) = result { 37 | break Err(err) as $result_type; 38 | } 39 | )+ ; 40 | } 41 | #[cfg(not(feature = "snapshot"))] { 42 | $( 43 | let _ = $new_state; 44 | )+ ; 45 | let _ = $ctx; 46 | $( 47 | let _ = $fmt; 48 | $( 49 | let _ = $arg; 50 | )* 51 | )? ; 52 | } 53 | break Ok(()) as $result_type 54 | }} 55 | } 56 | 57 | #[cfg(feature = "snapshot")] 58 | #[inline(always)] 59 | pub fn delta_snapshot( 60 | ctx: &mut C, 61 | origin: String, 62 | msg: Option, 63 | new_state: &S, 64 | ) -> Result<(), E> 65 | where 66 | S: Delta + Apply + Default, 67 | E: From, 68 | C: SnapshotCtx>, 69 | { 70 | let history: &mut >::History = ctx.history(); 71 | let old_state: &S = &history.current().state; 72 | let delta: ::Delta = old_state.delta(new_state)?; 73 | history.update_current(origin.clone(), new_state); 74 | let timestamp = history.current().timestamp.clone(); 75 | history.add_snapshot(DeltaSnapshot { timestamp, origin, msg, delta }); 76 | Ok(()) 77 | } 78 | 79 | 80 | 81 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] 82 | pub struct DeltaSnapshots { 83 | pub(crate) snapshots: Vec>, 84 | pub(crate) current: FullSnapshot, 85 | } 86 | 87 | impl DeltaSnapshots { 88 | #[inline(always)] 89 | pub fn current(&self) -> &FullSnapshot { &self.current } 90 | 91 | pub fn update_current(&mut self, origin: String, state: &T) { 92 | self.current.state = state.clone(); 93 | self.current.origin = origin; 94 | self.current.timestamp = Utc::now(); 95 | } 96 | 97 | pub fn clear(&mut self) { 98 | self.snapshots.clear(); 99 | self.current = Default::default(); 100 | } 101 | 102 | #[inline(always)] 103 | pub fn len(&self) -> usize { self.snapshots.len() } 104 | 105 | #[inline(always)] 106 | pub fn is_empty(&self) -> bool { self.snapshots.is_empty() } 107 | 108 | pub fn push_snapshot( 109 | &mut self, 110 | origin: String, 111 | msg: Option, 112 | state: T 113 | ) -> DeltaResult<()> { 114 | let old: &T = &self.current.state; 115 | let delta = old.delta(&state)?; 116 | let full = FullSnapshot { timestamp: Utc::now(), origin, msg, state }; 117 | self.add_snapshot(DeltaSnapshot { 118 | timestamp: full.timestamp.clone(), 119 | origin: full.origin.clone(), 120 | msg: full.msg.clone(), 121 | delta, 122 | }); 123 | self.current = full; 124 | Ok(()) 125 | } 126 | 127 | #[inline(always)] 128 | pub fn add_snapshot(&mut self, snapshot: DeltaSnapshot) { 129 | self.snapshots.push(snapshot); 130 | } 131 | 132 | #[inline(always)] 133 | pub fn take_snapshots(&mut self) -> Vec> { 134 | self.snapshots.drain(..).collect() 135 | } 136 | 137 | pub fn to_full_snapshots(self) -> DeltaResult> { 138 | let initial = FullSnapshot::default(); 139 | let mut uncompressed: Vec> = vec![]; 140 | for snapshot in self.snapshots { 141 | let old: &T = &uncompressed.last().unwrap_or(&initial).state; 142 | let new: T = old.apply(snapshot.delta)?; 143 | uncompressed.push(FullSnapshot { 144 | timestamp: snapshot.timestamp, 145 | origin: snapshot.origin, 146 | msg: snapshot.msg.clone(), 147 | state: new, 148 | }); 149 | } 150 | Ok(FullSnapshots(uncompressed)) 151 | } 152 | 153 | #[inline(always)] 154 | pub fn into_iter(self) -> impl Iterator> { 155 | self.snapshots.into_iter() 156 | } 157 | 158 | #[inline(always)] 159 | pub fn iter(&self) -> impl Iterator> { 160 | self.snapshots.iter() 161 | } 162 | } 163 | 164 | impl Default for DeltaSnapshots { 165 | fn default() -> Self { 166 | Self { 167 | snapshots: vec![], 168 | current: FullSnapshot::default(), 169 | } 170 | } 171 | } 172 | 173 | impl Hash for DeltaSnapshots 174 | where ::Delta: Hash 175 | { 176 | fn hash(&self, state: &mut H) { 177 | self.snapshots.hash(state); 178 | self.current.hash(state); 179 | } 180 | } 181 | 182 | 183 | 184 | 185 | #[derive(Clone, Debug, Deserialize, Serialize)] 186 | pub struct DeltaSnapshot { 187 | pub timestamp: DateTime, 188 | pub origin: String, 189 | pub msg: Option, 190 | pub delta: ::Delta, 191 | } 192 | 193 | impl DeltaSnapshot { 194 | pub fn new( 195 | origin: String, 196 | msg: Option, 197 | delta: ::Delta 198 | ) -> Self { 199 | Self { timestamp: Utc::now(), origin, msg, delta } 200 | } 201 | } 202 | 203 | impl Hash for DeltaSnapshot 204 | where ::Delta: Hash { 205 | fn hash(&self, state: &mut H) { 206 | self.timestamp.hash(state); 207 | self.origin.hash(state); 208 | self.msg.hash(state); 209 | self.delta.hash(state); 210 | } 211 | } 212 | 213 | impl PartialEq for DeltaSnapshot { 214 | fn eq(&self, rhs: &Self) -> bool { 215 | if self.timestamp != rhs.timestamp { return false; } 216 | if self.origin != rhs.origin { return false; } 217 | true 218 | } 219 | } 220 | 221 | impl Eq for DeltaSnapshot {} 222 | 223 | impl PartialOrd for DeltaSnapshot { 224 | fn partial_cmp(&self, rhs: &Self) -> Option { 225 | let timestamp_cmp = self.timestamp.partial_cmp(&rhs.timestamp); 226 | if timestamp_cmp != Some(Ordering::Equal) { return timestamp_cmp } 227 | let origin_cmp = self.origin.partial_cmp(&rhs.origin); 228 | if origin_cmp != Some(Ordering::Equal) { return origin_cmp } 229 | Some(Ordering::Equal) 230 | } 231 | } 232 | 233 | impl Ord for DeltaSnapshot { 234 | fn cmp(&self, rhs: &Self) -> Ordering { 235 | let timestamp_cmp = self.timestamp.cmp(&rhs.timestamp); 236 | if timestamp_cmp != Ordering::Equal { return timestamp_cmp } 237 | let origin_cmp = self.origin.cmp(&rhs.origin); 238 | if origin_cmp != Ordering::Equal { return origin_cmp } 239 | Ordering::Equal 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /deltoid/src/snapshot/full.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use chrono::prelude::{DateTime, Utc}; 4 | use crate::{Apply, Core, Delta, DeltaError, DeltaResult}; 5 | use crate::snapshot::SnapshotCtx; 6 | use crate::snapshot::delta::{DeltaSnapshot, DeltaSnapshots}; 7 | use serde_derive::{Deserialize, Serialize}; 8 | use std::cmp::Ordering; 9 | use std::hash::{Hash, Hasher}; 10 | 11 | #[macro_export] 12 | macro_rules! full_snapshot { 13 | ( 14 | use result type $result_type:ty; 15 | [$($origin:ident)::*] $($new_state:expr),+ => $ctx:expr 16 | $(; $fmt:expr $(, $arg:expr)* )? 17 | ) => { loop { 18 | #[cfg(feature = "snapshot")] 19 | #[allow(redundant_semicolons, unused)] { 20 | let mut origin = String::new(); 21 | $( 22 | if !origin.is_empty() { origin.push_str("::"); } 23 | origin.push_str(stringify!($origin)); 24 | )* ; 25 | let mut msg: Option = None; 26 | $( 27 | msg = Some(format!($fmt $(, $arg)*)); 28 | )? ; 29 | $( 30 | let result = $crate::snapshot::full::full_snapshot( 31 | $ctx, 32 | origin.clone(), 33 | msg.clone(), 34 | $new_state.clone() 35 | ); 36 | if let Err(err) = result { 37 | break Err(err) as $result_type; 38 | } 39 | )+ ; 40 | } 41 | #[cfg(not(feature = "snapshot"))] { 42 | $( 43 | let _ = $new_state; 44 | )+ ; 45 | let _ = $ctx; 46 | $( 47 | let _ = $fmt; 48 | $( 49 | let _ = $arg; 50 | )* 51 | )? ; 52 | } 53 | break Ok(()) as $result_type; 54 | }} 55 | } 56 | 57 | #[cfg(feature = "snapshot")] 58 | #[inline(always)] 59 | pub fn full_snapshot( 60 | ctx: &mut C, 61 | origin: String, 62 | msg: Option, 63 | state: S, 64 | ) -> Result<(), E> 65 | where 66 | S: Delta + Apply + Default, 67 | E: From, 68 | C: SnapshotCtx> 69 | { 70 | let history: &mut >::History = ctx.history(); 71 | let timestamp: DateTime = Utc::now(); 72 | history.add_snapshot(FullSnapshot { timestamp, origin, msg, state }); 73 | Ok(()) 74 | } 75 | 76 | 77 | 78 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] 79 | pub struct FullSnapshots(pub(crate) Vec>); 80 | 81 | impl Default for FullSnapshots { 82 | fn default() -> Self { 83 | Self(vec![ FullSnapshot::default() ]) 84 | } 85 | } 86 | 87 | impl FullSnapshots { 88 | #[inline(always)] 89 | pub fn current(&self) -> &FullSnapshot { 90 | self.0.last().unwrap(/*safe b/c there's always at least 1 snapshot*/) 91 | } 92 | 93 | #[inline(always)] 94 | pub fn clear(&mut self) { self.0.clear(); } 95 | 96 | #[inline(always)] 97 | pub fn len(&self) -> usize { self.0.len() } 98 | 99 | #[inline(always)] 100 | pub fn is_empty(&self) -> bool { self.0.is_empty() } 101 | 102 | pub fn push_snapshot( 103 | &mut self, 104 | origin: String, 105 | msg: Option, 106 | state: T 107 | ) -> DeltaResult<()> { 108 | let timestamp = Utc::now(); 109 | self.add_snapshot(FullSnapshot { timestamp, origin, msg, state }); 110 | Ok(()) 111 | } 112 | 113 | #[inline(always)] 114 | pub fn add_snapshot(&mut self, snapshot: FullSnapshot) { 115 | self.0.push(snapshot); 116 | } 117 | 118 | #[inline(always)] 119 | pub fn snapshot_ref(&self, idx: usize) -> DeltaResult<&FullSnapshot> { 120 | self.0.get(idx).ok_or_else(|| ExpectedValue!("FullSnapshot")) 121 | } 122 | 123 | pub fn to_delta_snapshots(mut self) -> DeltaResult> { 124 | let initial = FullSnapshot::default(); 125 | let mut deltas: Vec> = vec![]; 126 | for (sidx, snapshot) in self.0.iter().enumerate() { 127 | let old: &T = 128 | if sidx == 0 { &initial.state } 129 | else { &self.0[sidx - 1].state }; 130 | let new: &T = &snapshot.state; 131 | deltas.push(DeltaSnapshot { 132 | timestamp: snapshot.timestamp.clone(), 133 | origin: snapshot.origin.clone(), 134 | msg: snapshot.msg.clone(), 135 | delta: old.delta(new)?, 136 | }); 137 | } 138 | Ok(DeltaSnapshots { 139 | snapshots: deltas, 140 | current: self.0.pop().unwrap_or(initial), 141 | }) 142 | } 143 | 144 | #[inline(always)] 145 | pub fn into_iter(self) -> impl Iterator> { 146 | self.0.into_iter() 147 | } 148 | 149 | #[inline(always)] 150 | pub fn iter(&self) -> impl Iterator> { 151 | self.0.iter() 152 | } 153 | } 154 | 155 | impl Hash for FullSnapshots { 156 | fn hash(&self, state: &mut H) { 157 | self.0.hash(state); 158 | } 159 | } 160 | 161 | 162 | 163 | 164 | #[derive(Clone, Debug, Deserialize, Serialize)] 165 | pub struct FullSnapshot { 166 | pub timestamp: DateTime, 167 | pub origin: String, 168 | pub msg: Option, 169 | pub state: T, 170 | } 171 | 172 | impl FullSnapshot { 173 | pub fn new( 174 | origin: String, 175 | msg: Option, 176 | state: T 177 | ) -> Self { 178 | Self { timestamp: Utc::now(), origin, msg, state } 179 | } 180 | } 181 | 182 | impl Default for FullSnapshot { 183 | fn default() -> Self { 184 | Self { 185 | timestamp: Utc::now(), 186 | origin: "default".to_string(), 187 | msg: None, 188 | state: Default::default(), 189 | } 190 | } 191 | } 192 | 193 | impl Hash for FullSnapshot { 194 | fn hash(&self, state: &mut H) { 195 | self.timestamp.hash(state); 196 | self.origin.hash(state); 197 | self.msg.hash(state); 198 | self.state.hash(state); 199 | } 200 | } 201 | 202 | impl PartialEq for FullSnapshot { 203 | fn eq(&self, rhs: &Self) -> bool { 204 | if self.timestamp != rhs.timestamp { return false; } 205 | if self.origin != rhs.origin { return false; } 206 | true 207 | } 208 | } 209 | 210 | impl Eq for FullSnapshot {} 211 | 212 | impl PartialOrd for FullSnapshot { 213 | fn partial_cmp(&self, rhs: &Self) -> Option { 214 | let timestamp_cmp = self.timestamp.partial_cmp(&rhs.timestamp); 215 | if timestamp_cmp != Some(Ordering::Equal) { return timestamp_cmp } 216 | let origin_cmp = self.origin.partial_cmp(&rhs.origin); 217 | if origin_cmp != Some(Ordering::Equal) { return origin_cmp } 218 | Some(Ordering::Equal) 219 | } 220 | } 221 | 222 | impl Ord for FullSnapshot { 223 | fn cmp(&self, rhs: &Self) -> Ordering { 224 | let timestamp_cmp = self.timestamp.cmp(&rhs.timestamp); 225 | if timestamp_cmp != Ordering::Equal { return timestamp_cmp } 226 | let origin_cmp = self.origin.cmp(&rhs.origin); 227 | if origin_cmp != Ordering::Equal { return origin_cmp } 228 | Ordering::Equal 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /deltoid/src/snapshot/mod.rs: -------------------------------------------------------------------------------- 1 | //! Snapshotting infrastructure. 2 | 3 | #[cfg(feature = "snapshot")] pub mod delta; 4 | #[cfg(feature = "snapshot")] pub mod full; 5 | 6 | #[cfg(feature = "snapshot")] use crate::core::Core; 7 | #[cfg(feature = "snapshot")] pub use crate::snapshot::delta::*; 8 | #[cfg(feature = "snapshot")] pub use crate::snapshot::full::*; 9 | 10 | #[cfg(feature = "snapshot")] 11 | pub trait SnapshotCtx 12 | where T: Core + Default { 13 | // NOTE: Ideally `Self::History` would be a GAT defined ± as follows: 14 | // ``` 15 | // type History: Default = FullSnapshots; 16 | // ``` 17 | // Note the absence of `S` in the type level generic parameter set. 18 | // Defining it as above would have the effect that `History` merely 19 | // becomes a way to specify whether to use delta's or not, while `T` 20 | // becomes the sole way to specify what the snapshot's state type is. 21 | type History: Default; 22 | 23 | fn history(&mut self) -> &mut Self::History; 24 | 25 | #[inline] 26 | fn take_history(&mut self) -> Self::History { 27 | std::mem::take(self.history()) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /deltoid/src/string.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use crate::{Apply, Core, Delta, DeltaResult, FromDelta, IntoDelta}; 4 | use std::borrow::Cow; 5 | 6 | impl Core for String { 7 | type Delta = StringDelta; 8 | } 9 | 10 | impl Apply for String { 11 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 12 | Self::from_delta(delta) 13 | } 14 | } 15 | 16 | impl Delta for String { 17 | fn delta(&self, rhs: &Self) -> DeltaResult { 18 | rhs.clone().into_delta() 19 | } 20 | } 21 | 22 | impl FromDelta for String { 23 | fn from_delta(delta: Self::Delta) -> DeltaResult { 24 | delta.0.ok_or_else(|| ExpectedValue!("StringDelta")) 25 | } 26 | } 27 | 28 | impl IntoDelta for String { 29 | fn into_delta(self) -> DeltaResult { 30 | Ok(StringDelta(Some(self))) 31 | } 32 | } 33 | 34 | 35 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 36 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 37 | pub struct StringDelta( // TODO: Improve delta space efficiency 38 | #[doc(hidden)] pub Option 39 | ); 40 | 41 | impl std::fmt::Debug for StringDelta { 42 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 43 | match &self.0 { 44 | Some(field) => write!(f, "StringDelta({:#?})", field), 45 | None => write!(f, "StringDelta(None)"), 46 | } 47 | } 48 | } 49 | 50 | 51 | 52 | #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] 53 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 54 | pub struct Str<'s>(pub Cow<'s, str>); 55 | 56 | impl<'s> std::fmt::Debug for Str<'s> { 57 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 58 | write!(f, "{}", self.0) 59 | } 60 | } 61 | 62 | impl<'s> std::ops::Deref for Str<'s> { 63 | type Target = str; 64 | 65 | fn deref(&self) -> &Self::Target { &self.0 } 66 | } 67 | 68 | impl<'s> Default for Str<'s> { 69 | fn default() -> Self { Self(Cow::Borrowed("")) } 70 | } 71 | 72 | impl<'s> std::clone::Clone for Str<'s> { 73 | fn clone(&self) -> Self { Self(self.0.to_owned()) } 74 | } 75 | 76 | impl<'s> From<&'s str> for Str<'s> { 77 | fn from(s: &'s str) -> Self { Self(Cow::Borrowed(s)) } 78 | } 79 | 80 | impl<'s> From for Str<'s> { 81 | fn from(s: String) -> Self { Self(Cow::Owned(s)) } 82 | } 83 | 84 | 85 | impl<'s> Core for Str<'s> { 86 | type Delta = StrDelta; 87 | } 88 | 89 | impl<'s> Apply for Str<'s> { 90 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 91 | Ok(match delta.0 { 92 | Some(d) => Self(std::borrow::Cow::Owned(d)), 93 | None => self.clone(), 94 | }) 95 | } 96 | } 97 | 98 | impl<'s> Delta for Str<'s> { 99 | fn delta(&self, rhs: &Self) -> DeltaResult { 100 | rhs.clone().into_delta() 101 | } 102 | } 103 | 104 | impl<'s> FromDelta for Str<'s> { 105 | fn from_delta(delta: Self::Delta) -> DeltaResult { 106 | delta.0 107 | .map(|s| Self(Cow::Owned(s))) 108 | .ok_or_else(|| ExpectedValue!("StrDelta")) 109 | } 110 | } 111 | 112 | impl<'s> IntoDelta for Str<'s> { 113 | fn into_delta(self) -> DeltaResult { 114 | match self.0 { 115 | Cow::Borrowed(b) => Ok(StrDelta(Some(b.to_owned()))), 116 | Cow::Owned(o) => Ok(StrDelta(Some(o))), 117 | } 118 | } 119 | } 120 | 121 | 122 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 123 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 124 | pub struct StrDelta( // TODO: Improve delta space efficiency 125 | #[doc(hidden)] pub Option 126 | ); 127 | 128 | impl std::fmt::Debug for StrDelta { 129 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 130 | match &self.0 { 131 | Some(field) => write!(f, "StrDelta({:#?})", field), 132 | None => write!(f, "StrDelta(None)"), 133 | } 134 | } 135 | } 136 | 137 | 138 | 139 | #[allow(non_snake_case)] 140 | #[cfg(test)] 141 | mod tests { 142 | use serde_json; 143 | use super::*; 144 | 145 | #[test] 146 | fn String__delta__same_values() -> DeltaResult<()> { 147 | let s0 = String::from("foo"); 148 | let s1 = String::from("foo"); 149 | let delta: ::Delta = s0.delta(&s1)?; 150 | let json_string = serde_json::to_string(&delta) 151 | .expect("Could not serialize to json"); 152 | println!("json_string: {}", json_string); 153 | assert_eq!(json_string, "\"foo\""); 154 | let delta1: ::Delta = serde_json::from_str( 155 | &json_string 156 | ).expect("Could not deserialize from json"); 157 | assert_eq!(delta, delta1); 158 | assert_eq!(delta, String::from("foo").into_delta()?); 159 | Ok(()) 160 | } 161 | 162 | #[test] 163 | fn String__delta__different_values() -> DeltaResult<()> { 164 | let s0 = String::from("foo"); 165 | let s1 = String::from("bar"); 166 | let delta: ::Delta = s0.delta(&s1)?; 167 | let json_string = serde_json::to_string(&delta) 168 | .expect("Could not serialize to json"); 169 | println!("json_string: {}", json_string); 170 | assert_eq!(json_string, "\"bar\""); 171 | let delta1: ::Delta = serde_json::from_str( 172 | &json_string 173 | ).expect("Could not deserialize from json"); 174 | assert_eq!(delta, delta1); 175 | assert_eq!(delta, String::from("bar").into_delta()?); 176 | Ok(()) 177 | } 178 | 179 | #[test] 180 | fn String__apply__same_values() -> DeltaResult<()> { 181 | let s0 = String::from("foo"); 182 | let s1 = String::from("foo"); 183 | let delta: ::Delta = s0.delta(&s1)?; 184 | let s2 = s0.apply(delta)?; 185 | assert_eq!(s1, s2); 186 | Ok(()) 187 | } 188 | 189 | #[test] 190 | fn String__apply__different_values() -> DeltaResult<()> { 191 | let s0 = String::from("foo"); 192 | let s1 = String::from("bar"); 193 | let delta: ::Delta = s0.delta(&s1)?; 194 | let s2 = s0.apply(delta)?; 195 | assert_eq!(s1, s2); 196 | Ok(()) 197 | } 198 | 199 | 200 | #[test] 201 | fn Str__delta__same_values() -> DeltaResult<()> { 202 | let s0: Str<'static> = Str::from("foo"); 203 | let s1: Str<'static> = Str::from("foo"); 204 | let delta: ::Delta = s0.delta(&s1)?; 205 | let json_string = serde_json::to_string(&delta) 206 | .expect("Could not serialize to json"); 207 | println!("json_string: {}", json_string); 208 | assert_eq!(json_string, "\"foo\""); 209 | let delta1: ::Delta = serde_json::from_str( 210 | &json_string 211 | ).expect("Could not deserialize from json"); 212 | assert_eq!(delta, delta1); 213 | assert_eq!(delta, Str::from("foo").into_delta()?); 214 | Ok(()) 215 | } 216 | 217 | #[test] 218 | fn Str__delta__different_values() -> DeltaResult<()> { 219 | let s0: Str<'static> = Str::from("foo"); 220 | let s1: Str<'static> = Str::from("bar"); 221 | let delta: ::Delta = s0.delta(&s1)?; 222 | let json_string = serde_json::to_string(&delta) 223 | .expect("Could not serialize to json"); 224 | println!("json_string: {}", json_string); 225 | assert_eq!(json_string, "\"bar\""); 226 | let delta1: ::Delta = serde_json::from_str( 227 | &json_string 228 | ).expect("Could not deserialize from json"); 229 | assert_eq!(delta, delta1); 230 | assert_eq!(delta, Str::from("bar").into_delta()?); 231 | Ok(()) 232 | } 233 | 234 | #[test] 235 | fn Str__apply__same_values() -> DeltaResult<()> { 236 | let s0: Str<'static> = Str::from("foo"); 237 | let s1: Str<'static> = Str::from("foo"); 238 | let delta: ::Delta = s0.delta(&s1)?; 239 | let s2 = s0.apply(delta)?; 240 | assert_eq!(s1, s2); 241 | Ok(()) 242 | } 243 | 244 | #[test] 245 | fn Str__apply__different_values() -> DeltaResult<()> { 246 | let s0: Str<'static> = Str::from("foo"); 247 | let s1: Str<'static> = Str::from("bar"); 248 | let delta: ::Delta = s0.delta(&s1)?; 249 | let s2 = s0.apply(delta)?; 250 | assert_eq!(s1, s2); 251 | Ok(()) 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /deltoid/src/sync/arc.rs: -------------------------------------------------------------------------------- 1 | //! A Deltoid impl for [`Arc`] that provides extra functionality in 2 | //! the form of delta support, de/serialization, partial equality and more. 3 | //! 4 | //! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html 5 | 6 | use crate::{Apply, Core, Delta, DeltaResult, FromDelta, IntoDelta}; 7 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 8 | use serde::de; 9 | use serde::ser::SerializeMap; 10 | use std::fmt::{self, Debug}; 11 | use std::marker::PhantomData; 12 | use std::sync::Arc; 13 | 14 | 15 | impl Core for Arc 16 | where T: Clone + Debug + PartialEq + Core 17 | + for<'de> Deserialize<'de> 18 | + Serialize 19 | { 20 | type Delta = ArcDelta; 21 | } 22 | 23 | impl Apply for Arc 24 | where T: Clone + Debug + PartialEq + Apply 25 | + for<'de> Deserialize<'de> 26 | + Serialize 27 | { 28 | #[inline] 29 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 30 | let lhs: &T = self.as_ref(); 31 | match delta.0 { 32 | None => Ok(self.clone()), 33 | Some(delta) => lhs.apply(*delta).map(Arc::new), 34 | } 35 | } 36 | } 37 | 38 | impl Delta for Arc 39 | where T: Clone + Debug + PartialEq + Delta 40 | + for<'de> Deserialize<'de> 41 | + Serialize 42 | { 43 | #[inline] 44 | fn delta(&self, rhs: &Self) -> DeltaResult { 45 | let lhs: &T = self.as_ref(); 46 | let rhs: &T = rhs.as_ref(); 47 | Ok(ArcDelta(if lhs == rhs { 48 | None 49 | } else { 50 | Some(Box::new(lhs.delta(rhs)?)) 51 | })) 52 | } 53 | } 54 | 55 | impl FromDelta for Arc 56 | where T: Clone + Debug + PartialEq + FromDelta 57 | + for<'de> Deserialize<'de> 58 | + Serialize 59 | { 60 | #[inline] 61 | fn from_delta(delta: Self::Delta) -> DeltaResult { 62 | let delta = delta.0.ok_or_else(|| ExpectedValue!("ArcDelta"))?; 63 | ::from_delta(*delta).map(Arc::new) 64 | } 65 | } 66 | 67 | impl IntoDelta for Arc 68 | where T: Clone + Debug + PartialEq + IntoDelta 69 | + for<'de> Deserialize<'de> 70 | + Serialize 71 | { 72 | #[inline] 73 | fn into_delta(self) -> DeltaResult { 74 | let thing: T = self.as_ref().clone(); 75 | thing.into_delta().map(Box::new).map(Some).map(ArcDelta) 76 | } 77 | } 78 | 79 | 80 | 81 | 82 | #[derive(Clone, PartialEq)] 83 | pub struct ArcDelta( 84 | #[doc(hidden)] pub Option::Delta>> 85 | ); 86 | 87 | impl std::fmt::Debug for ArcDelta { 88 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 89 | match &self.0 { 90 | Some(d) => write!(f, "ArcDelta({:#?})", d), 91 | None => write!(f, "ArcDelta(None)"), 92 | } 93 | } 94 | } 95 | 96 | impl Serialize for ArcDelta { 97 | fn serialize(&self, serializer: S) -> Result 98 | where S: Serializer { 99 | let mut num_fields = 0; 100 | if self.0.is_some() { num_fields += 1; } 101 | let mut s = serializer.serialize_map(Some(num_fields))?; 102 | if let Some(inner) = &self.0 { 103 | s.serialize_entry("0", inner)?; 104 | } 105 | s.end() 106 | } 107 | } 108 | 109 | impl<'de, T: Core + Clone> Deserialize<'de> for ArcDelta { 110 | fn deserialize(deserializer: D) -> Result 111 | where D: Deserializer<'de> { 112 | 113 | struct DeltaVisitor(PhantomData); 114 | 115 | impl<'de, T2> de::Visitor<'de> for DeltaVisitor 116 | where T2: Core + Clone { 117 | type Value = ArcDelta; 118 | 119 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 120 | formatter.write_str("a ArcDelta") 121 | } 122 | 123 | fn visit_map(self, mut map: M) -> Result 124 | where M: de::MapAccess<'de> { 125 | let mut delta: Self::Value = ArcDelta(None); 126 | const EXPECTED_FIELDS: &[&str] = &["0"]; 127 | while let Some((key, value)) = map.next_entry()? { 128 | match (key, value) { 129 | ("0", value) => delta.0 = Some(value), 130 | (field_name, _) => return Err(de::Error::unknown_field( 131 | field_name, EXPECTED_FIELDS 132 | ))?, 133 | } 134 | } 135 | Ok(delta) 136 | } 137 | } 138 | 139 | deserializer.deserialize_map(DeltaVisitor(PhantomData)) 140 | } 141 | } 142 | 143 | #[allow(non_snake_case)] 144 | #[cfg(test)] 145 | mod tests { 146 | use serde_json; 147 | use super::*; 148 | 149 | #[test] 150 | fn Arc__delta___same_values() -> DeltaResult<()> { 151 | let foo = String::from("foo"); 152 | let bar = String::from("foo"); 153 | let box0 = Arc::new(foo); 154 | let box1 = Arc::new(bar); 155 | let delta: as Core>::Delta = box0.delta(&box1)?; 156 | let json_string = serde_json::to_string(&delta) 157 | .expect("Could not serialize to json"); 158 | println!("json_string: \"{}\"", json_string); 159 | assert_eq!(json_string, "{}"); 160 | let delta1: as Core>::Delta = serde_json::from_str( 161 | &json_string 162 | ).expect("Could not deserialize from json"); 163 | assert_eq!(delta, delta1); 164 | Ok(()) 165 | } 166 | 167 | #[test] 168 | fn Arc__delta___different_values() -> DeltaResult<()> { 169 | let foo = String::from("foo"); 170 | let bar = String::from("bar"); 171 | let box0 = Arc::new(foo); 172 | let box1 = Arc::new(bar); 173 | let delta: as Core>::Delta = box0.delta(&box1)?; 174 | let json_string = serde_json::to_string(&delta) 175 | .expect("Could not serialize to json"); 176 | println!("json_string: \"{}\"", json_string); 177 | assert_eq!(json_string, "{\"0\":\"bar\"}"); 178 | let delta1: as Core>::Delta = serde_json::from_str( 179 | &json_string 180 | ).expect("Could not deserialize from json"); 181 | assert_eq!(delta, delta1); 182 | Ok(()) 183 | } 184 | 185 | #[test] 186 | fn Arc__apply__same_values() -> DeltaResult<()> { 187 | let foo = String::from("foo"); 188 | let bar = String::from("foo"); 189 | let box0 = Arc::new(foo); 190 | let box1 = Arc::new(bar); 191 | let delta: as Core>::Delta = box0.delta(&box1)?; 192 | let box2 = box0.apply(delta)?; 193 | assert_eq!(box1, box2); 194 | Ok(()) 195 | } 196 | 197 | #[test] 198 | fn Arc__apply__different_values() -> DeltaResult<()> { 199 | let foo = String::from("foo"); 200 | let bar = String::from("bar"); 201 | let box0 = Arc::new(foo); 202 | let box1 = Arc::new(bar); 203 | let delta: as Core>::Delta = box0.delta(&box1)?; 204 | let box2 = box0.apply(delta)?; 205 | assert_eq!(box1, box2); 206 | Ok(()) 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /deltoid/src/sync/mod.rs: -------------------------------------------------------------------------------- 1 | mod arc; 2 | mod rwlock; 3 | 4 | pub use arc::*; 5 | pub use rwlock::*; 6 | -------------------------------------------------------------------------------- /deltoid/src/sync/rwlock.rs: -------------------------------------------------------------------------------- 1 | //! A newtype wrapping [`RwLock`] that provides extra functionality in 2 | //! the form of delta support, de/serialization, partial equality and more. 3 | //! 4 | //! [`RwLock`]: https://doc.rust-lang.org/std/sync/struct.RwLock.html 5 | 6 | use crate::{Apply, Core, Delta, DeltaError, DeltaResult, FromDelta, IntoDelta}; 7 | use serde::{Serialize, Serializer, Deserialize, Deserializer}; 8 | use serde::de::Visitor; 9 | use std::cmp::Ordering; 10 | use std::fmt::{self, Debug}; 11 | use std::hash::{Hash, Hasher}; 12 | use std::marker::PhantomData; 13 | pub use std::sync::{LockResult, RwLockReadGuard, RwLockWriteGuard}; 14 | 15 | 16 | #[derive(Debug, Default)] 17 | pub struct RwLock(std::sync::RwLock); 18 | 19 | #[allow(unused)] 20 | impl RwLock { 21 | pub fn new(thing: T) -> Self { Self(std::sync::RwLock::new(thing)) } 22 | 23 | pub fn into_inner(self) -> LockResult { self.0.into_inner() } 24 | 25 | pub fn try_read(&self) -> DeltaResult> { 26 | self.0.try_read().map_err(DeltaError::from) 27 | } 28 | 29 | pub fn try_write(&self) -> DeltaResult> { 30 | self.0.try_write().map_err(DeltaError::from) 31 | } 32 | } 33 | 34 | impl Clone for RwLock { 35 | fn clone(&self) -> Self { 36 | let value: &T = &*self.try_read().unwrap(); 37 | Self::new(value.clone()) 38 | } 39 | } 40 | 41 | impl Hash for RwLock { 42 | fn hash(&self, state: &mut H) { 43 | self.try_read().unwrap().hash(state) 44 | } 45 | } 46 | 47 | impl PartialEq for RwLock { 48 | fn eq(&self, rhs: &Self) -> bool { 49 | let lhs: &T = &*self.0.try_read().unwrap(); 50 | let rhs: &T = &*rhs.0.try_read().unwrap(); 51 | lhs.eq(rhs) 52 | } 53 | } 54 | 55 | impl Eq for RwLock { } 56 | 57 | impl PartialOrd for RwLock { 58 | fn partial_cmp(&self, rhs: &Self) -> Option { 59 | let lhs: &T = &*self.0.try_read().unwrap(); 60 | let rhs: &T = &*rhs.0.try_read().unwrap(); 61 | lhs.partial_cmp(rhs) 62 | } 63 | } 64 | 65 | impl Ord for RwLock { 66 | fn cmp(&self, rhs: &Self) -> Ordering { 67 | let lhs: &T = &*self.0.try_read().unwrap(); 68 | let rhs: &T = &*rhs.0.try_read().unwrap(); 69 | lhs.cmp(rhs) 70 | } 71 | } 72 | 73 | 74 | impl Serialize for RwLock { 75 | fn serialize(&self, serializer: S) -> Result { 76 | let value: &T = &self.0.try_read().unwrap(/*TODO*/); 77 | serializer.serialize_newtype_struct("RwLock", value) 78 | } 79 | } 80 | 81 | impl<'de, T: Deserialize<'de>> Deserialize<'de> for RwLock { 82 | fn deserialize(deserializer: D) -> Result 83 | where D: Deserializer<'de> { 84 | struct RwLockVisitor(PhantomData); 85 | 86 | impl<'de, V: Deserialize<'de>> Visitor<'de> for RwLockVisitor { 87 | type Value = RwLock; 88 | 89 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 90 | formatter.write_str("struct RwLock") 91 | } 92 | 93 | fn visit_newtype_struct>( 94 | self, 95 | deserializer: D 96 | ) -> Result { 97 | Deserialize::deserialize(deserializer).map(RwLock::new) 98 | } 99 | } 100 | 101 | deserializer.deserialize_newtype_struct( 102 | "RwLock", 103 | RwLockVisitor(PhantomData) 104 | ) 105 | } 106 | } 107 | 108 | 109 | 110 | impl Core for RwLock 111 | where T: Clone + Debug + PartialEq + Core 112 | + for<'de> Deserialize<'de> 113 | + Serialize 114 | { 115 | type Delta = RwLockDelta; 116 | } 117 | 118 | impl Apply for RwLock 119 | where T: Clone + Debug + PartialEq + Apply 120 | + for<'de> Deserialize<'de> 121 | + Serialize 122 | { 123 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 124 | let lhs: &T = &*self.0.try_read().unwrap(/*TODO*/); 125 | match delta.0 { 126 | Some(delta) => lhs.apply(delta).map(Self::new), 127 | None => Ok(Self::new(lhs.clone())), 128 | } 129 | } 130 | } 131 | 132 | impl Delta for RwLock 133 | where T: Clone + Debug + PartialEq + Delta 134 | + for<'de> Deserialize<'de> 135 | + Serialize 136 | { 137 | fn delta(&self, rhs: &Self) -> DeltaResult { 138 | let lhs: &T = &*self.0.try_read().unwrap(/*TODO*/); 139 | let rhs: &T = &*rhs.0.try_read().unwrap(/*TODO*/); 140 | lhs.delta(rhs).map(Some).map(RwLockDelta) 141 | } 142 | } 143 | 144 | impl FromDelta for RwLock 145 | where T: Clone + Debug + PartialEq + FromDelta 146 | + for<'de> Deserialize<'de> 147 | + Serialize 148 | { 149 | fn from_delta(delta: Self::Delta) -> DeltaResult { 150 | let delta = delta.0.ok_or_else(|| ExpectedValue!("RwLockDelta"))?; 151 | ::from_delta(delta).map(Self::new) 152 | } 153 | } 154 | 155 | impl IntoDelta for RwLock 156 | where T: Clone + Debug + PartialEq + IntoDelta 157 | + for<'de> Deserialize<'de> 158 | + Serialize 159 | { 160 | fn into_delta(self) -> DeltaResult { 161 | let value: &T = &*self.0.try_read().unwrap(/*TODO*/); 162 | value.clone().into_delta().map(Some).map(RwLockDelta) 163 | } 164 | } 165 | 166 | 167 | 168 | 169 | #[derive(Clone, PartialEq)] 170 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 171 | pub struct RwLockDelta( 172 | #[doc(hidden)] pub Option<::Delta> 173 | ); 174 | 175 | impl std::fmt::Debug for RwLockDelta { 176 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 177 | match &self.0 { 178 | Some(d) => write!(f, "RwLockDelta({:#?})", d), 179 | None => write!(f, "RwLockDelta(None)"), 180 | } 181 | } 182 | } 183 | 184 | 185 | 186 | 187 | #[allow(non_snake_case)] 188 | #[cfg(test)] 189 | mod tests { 190 | use serde_json; 191 | use super::*; 192 | 193 | #[test] 194 | fn RwLock__delta__same_values() -> DeltaResult<()> { 195 | let s0 = RwLock::new(String::from("foo")); 196 | let s1 = RwLock::new(String::from("foo")); 197 | let delta: as Core>::Delta = s0.delta(&s1)?; 198 | let json_string = serde_json::to_string(&delta) 199 | .expect("Could not serialize to json"); 200 | println!("json_string: {}", json_string); 201 | assert_eq!(json_string, "\"foo\""); 202 | let delta1: as Core>::Delta = serde_json::from_str( 203 | &json_string 204 | ).expect("Could not deserialize from json"); 205 | assert_eq!(delta, delta1); 206 | assert_eq!(delta, RwLock::new(String::from("foo")).into_delta()?); 207 | Ok(()) 208 | } 209 | 210 | #[test] 211 | fn RwLock__delta__different_values() -> DeltaResult<()> { 212 | let s0 = RwLock::new(String::from("foo")); 213 | let s1 = RwLock::new(String::from("bar")); 214 | let delta: as Core>::Delta = s0.delta(&s1)?; 215 | let json_string = serde_json::to_string(&delta) 216 | .expect("Could not serialize to json"); 217 | println!("json_string: {}", json_string); 218 | assert_eq!(json_string, "\"bar\""); 219 | let delta1: as Core>::Delta = serde_json::from_str( 220 | &json_string 221 | ).expect("Could not deserialize from json"); 222 | assert_eq!(delta, delta1); 223 | assert_eq!(delta, RwLock::new(String::from("bar")).into_delta()?); 224 | Ok(()) 225 | } 226 | 227 | #[test] 228 | fn RwLock__apply_same_values() -> DeltaResult<()> { 229 | let s0 = RwLock::new(String::from("foo")); 230 | let s1 = RwLock::new(String::from("foo")); 231 | let delta: as Core>::Delta = s0.delta(&s1)?; 232 | let s2 = s0.apply(delta)?; 233 | assert_eq!(s1, s2); 234 | Ok(()) 235 | } 236 | 237 | #[test] 238 | fn RwLock__apply_different_values() -> DeltaResult<()> { 239 | let s0 = RwLock::new(String::from("foo")); 240 | let s1 = RwLock::new(String::from("bar")); 241 | let delta: as Core>::Delta = s0.delta(&s1)?; 242 | let s2 = s0.apply(delta)?; 243 | assert_eq!(s1, s2); 244 | Ok(()) 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /deltoid/src/vec.rs: -------------------------------------------------------------------------------- 1 | //! 2 | 3 | use crate::{Apply, Core, Delta, DeltaError, DeltaResult, FromDelta, IntoDelta}; 4 | use serde::{Deserialize, Serialize}; 5 | use std::fmt::Debug; 6 | 7 | 8 | // TODO While these impls should work fine in terms of soundness, it 9 | // is actually more suited to a `Stack`-like type in terms of 10 | // efficiency. So, change the scheme to be more efficient, 11 | // possibly using dynamic programming techniques to do so. 12 | 13 | impl Core for Vec 14 | where T: Clone + Debug + PartialEq + Core 15 | + for<'de> Deserialize<'de> 16 | + Serialize 17 | { 18 | type Delta = VecDelta; 19 | } 20 | 21 | impl Apply for Vec 22 | where T: Clone + Debug + PartialEq + Apply + FromDelta 23 | + for<'de> Deserialize<'de> 24 | + Serialize 25 | { 26 | fn apply(&self, delta: Self::Delta) -> DeltaResult { 27 | let mut new: Self = self.clone(); 28 | for change in delta.into_iter() { match change { 29 | EltDelta::Edit { index, item } => { 30 | // NOTE: If self.len() == 0, the Edit should have been an Add: 31 | ensure_gt![self.len(), 0]?; 32 | // NOTE: Ensure index is not out of bounds: 33 | ensure_lt![index, self.len()]?; 34 | new[index] = self[index].apply(item)?; 35 | }, 36 | EltDelta::Add(delta) => new.push(::from_delta(delta)?), 37 | EltDelta::Remove { count } => for _ in 0 .. count { 38 | new.pop().ok_or_else(|| ExpectedValue!("VecDelta"))?; 39 | }, 40 | }} 41 | Ok(new) 42 | } 43 | } 44 | 45 | impl Delta for Vec 46 | where T: Clone + Debug + PartialEq + Delta + IntoDelta 47 | + for<'de> Deserialize<'de> 48 | + Serialize 49 | { 50 | fn delta(&self, rhs: &Self) -> DeltaResult { 51 | let (lhs_len, rhs_len) = (self.len(), rhs.len()); 52 | let max_len = usize::max(lhs_len, rhs_len); 53 | let mut changes: Vec> = vec![]; 54 | for index in 0 .. max_len { match (self.get(index), rhs.get(index)) { 55 | (None, None) => return bug_detected!(), 56 | (Some(lhs), Some(rhs)) if lhs == rhs => {/*NOP*/}, 57 | (Some(lhs), Some(rhs)) => 58 | changes.push(EltDelta::Edit { index, item: lhs.delta(rhs)? }), 59 | (None, Some(rhs)) => 60 | changes.push(EltDelta::Add(rhs.clone().into_delta()?)), 61 | (Some(_), None) => match changes.last_mut() { 62 | Some(EltDelta::Remove { ref mut count }) => *count += 1, 63 | _ => changes.push(EltDelta::Remove { count: 1 }), 64 | }, 65 | }} 66 | Ok(VecDelta(changes)) 67 | } 68 | } 69 | 70 | impl FromDelta for Vec 71 | where T: Clone + Debug + PartialEq + FromDelta 72 | + for<'de> Deserialize<'de> 73 | + Serialize 74 | { 75 | fn from_delta(delta: ::Delta) -> DeltaResult { 76 | let mut vec: Vec = vec![]; 77 | for (index, element) in delta.0.into_iter().enumerate() { 78 | match element { 79 | EltDelta::Add(elt) => vec.push(::from_delta(elt)?), 80 | _ => return Err(DeltaError::IllegalDelta { index })?, 81 | } 82 | } 83 | Ok(vec) 84 | } 85 | } 86 | 87 | impl IntoDelta for Vec 88 | where T: Clone + Debug + PartialEq + IntoDelta 89 | + for<'de> Deserialize<'de> 90 | + Serialize 91 | { 92 | fn into_delta(self) -> DeltaResult<::Delta> { 93 | let mut changes: Vec> = vec![]; 94 | for elt in self { 95 | changes.push(EltDelta::Add(elt.into_delta()?)); 96 | } 97 | Ok(VecDelta(changes)) 98 | } 99 | } 100 | 101 | 102 | 103 | #[derive(Clone, PartialEq)] 104 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 105 | pub enum EltDelta { 106 | /// Edit a value at a given `index`. 107 | Edit { 108 | /// The location of the edit 109 | index: usize, 110 | /// The new value of the item 111 | item: ::Delta, 112 | }, 113 | /// Remove `count` elements from the end of the Vec. 114 | Remove { count: usize }, 115 | /// Add a value. 116 | Add(::Delta), 117 | } 118 | 119 | impl std::fmt::Debug for EltDelta { 120 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 121 | match &self { 122 | Self::Edit { index, item } => f.debug_struct("Edit") 123 | .field("index", index) 124 | .field("item", item) 125 | .finish(), 126 | Self::Remove { count } => f.debug_struct("Remove") 127 | .field("count", count) 128 | .finish(), 129 | Self::Add(delta) => write!(f, "Add({:#?})", delta), 130 | } 131 | } 132 | } 133 | 134 | 135 | #[derive(Clone, PartialEq)] 136 | #[derive(serde_derive::Deserialize, serde_derive::Serialize)] 137 | pub struct VecDelta(#[doc(hidden)] pub Vec>); 138 | 139 | impl VecDelta { 140 | #[inline(always)] 141 | pub fn iter<'d>(&'d self) -> impl Iterator> + 'd { 142 | self.0.iter() 143 | } 144 | 145 | #[inline(always)] 146 | pub fn into_iter<'d>(self) -> impl Iterator> + 'd 147 | where Self: 'd { 148 | self.0.into_iter() 149 | } 150 | 151 | #[inline(always)] 152 | pub fn len(&self) -> usize { self.0.len() } 153 | } 154 | 155 | impl std::fmt::Debug for VecDelta { 156 | fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 157 | write!(f, "VecDelta ")?; 158 | f.debug_list().entries(self.iter()).finish() 159 | } 160 | } 161 | 162 | 163 | 164 | 165 | 166 | #[cfg(test)] 167 | mod tests { 168 | use super::*; 169 | 170 | #[allow(non_snake_case)] 171 | #[test] 172 | fn Vec__delta__same_values() -> DeltaResult<()> { 173 | let vec0: Vec = vec![1, 3, 10, 30]; 174 | let vec1: Vec = vec![1, 3, 10, 30]; 175 | assert_eq!(vec0, vec1); 176 | 177 | let delta = vec0.delta(&vec1)?; 178 | assert_eq!(delta, VecDelta(vec![])); 179 | let vec2 = vec0.apply(delta)?; 180 | assert_eq!(vec1, vec2); 181 | 182 | let delta = vec1.delta(&vec0)?; 183 | assert_eq!(delta, VecDelta(vec![])); 184 | let vec3 = vec1.apply(delta)?; 185 | assert_eq!(vec0, vec3); 186 | 187 | Ok(()) 188 | } 189 | 190 | #[allow(non_snake_case)] 191 | #[test] 192 | fn Vec__delta__different_values__same_length() -> DeltaResult<()> { 193 | let vec0 = vec![1, 3, 10, 49, 30, 500]; 194 | let vec1 = vec![1, 3, 10, 30, 500, 49]; 195 | 196 | let delta0 = vec0.delta(&vec1)?; 197 | assert_eq!(delta0, VecDelta(vec![ 198 | EltDelta::Edit { index: 3, item: 30i32.into_delta()?, }, 199 | EltDelta::Edit { index: 4, item: 500i32.into_delta()?, }, 200 | EltDelta::Edit { index: 5, item: 49i32.into_delta()?, }, 201 | ])); 202 | let vec2 = vec0.apply(delta0)?; 203 | assert_eq!(vec1, vec2); 204 | 205 | let delta = vec1.delta(&vec0)?; 206 | assert_eq!(delta, VecDelta(vec![ 207 | EltDelta::Edit { index: 3, item: 49i32.into_delta()?, }, 208 | EltDelta::Edit { index: 4, item: 30i32.into_delta()?, }, 209 | EltDelta::Edit { index: 5, item: 500i32.into_delta()?, }, 210 | ])); 211 | let vec3 = vec1.apply(delta)?; 212 | assert_eq!(vec0, vec3); 213 | 214 | Ok(()) 215 | } 216 | 217 | #[allow(non_snake_case)] 218 | #[test] 219 | fn Vec__delta__different_values__different_length() -> DeltaResult<()> { 220 | let vec0: Vec = vec![1, 3, 10, 30]; 221 | let vec1: Vec = vec![1, 3, 10, 49, 30, 500]; 222 | 223 | let delta0 = vec0.delta(&vec1)?; 224 | assert_eq!(delta0, VecDelta(vec![ 225 | EltDelta::Edit { index: 3, item: 49.into_delta()?, }, 226 | EltDelta::Add(30.into_delta()?), 227 | EltDelta::Add(500.into_delta()?), 228 | ])); 229 | let vec2 = vec0.apply(delta0)?; 230 | assert_eq!(vec1, vec2); 231 | 232 | let delta = vec1.delta(&vec0)?; 233 | assert_eq!(delta, VecDelta(vec![ 234 | EltDelta::Edit { index: 3, item: 30.into_delta()?, }, 235 | EltDelta::Remove { count: 2, }, 236 | ])); 237 | let vec3 = vec1.apply(delta)?; 238 | assert_eq!(vec0, vec3); 239 | 240 | Ok(()) 241 | } 242 | 243 | #[allow(non_snake_case)] 244 | #[test] 245 | fn Vec__apply__different_values__same_length() -> DeltaResult<()> { 246 | let vec0 = vec![1, 3, 10, 30, 30]; 247 | let vec1 = vec![1, 3, 10, 30, 40]; 248 | let delta = vec0.delta(&vec1)?; 249 | let vec2 = vec0.apply(delta)?; 250 | assert_eq!(vec1, vec2); 251 | Ok(()) 252 | } 253 | 254 | #[allow(non_snake_case)] 255 | #[test] 256 | fn Vec__apply__different_values__different_length() -> DeltaResult<()> { 257 | let vec0 = vec![1, 3, 10, 30, 30]; 258 | let vec1 = vec![1, 3, 10, 30, 30, 40]; 259 | let delta = vec0.delta(&vec1)?; 260 | let vec2 = vec0.apply(delta)?; 261 | assert_eq!(vec1, vec2); 262 | Ok(()) 263 | } 264 | 265 | } 266 | --------------------------------------------------------------------------------