1#![cfg_attr(not(any(test, feature = "box", feature = "option")), no_std)]
77
78#[doc(hidden)]
79pub use struct_patch_derive::Filler;
80#[doc(hidden)]
81pub use struct_patch_derive::Patch;
82#[cfg(any(feature = "box", feature = "option"))]
83pub mod std;
84pub mod traits;
85pub use traits::*;
86
87#[cfg(test)]
88mod tests {
89 use serde::Deserialize;
90 #[cfg(feature = "merge")]
91 use struct_patch::Merge;
92 use struct_patch::Patch;
93 #[cfg(feature = "status")]
94 use struct_patch::Status;
95
96 use crate as struct_patch;
97
98 #[test]
99 fn test_basic() {
100 #[derive(Patch, Debug, PartialEq)]
101 struct Item {
102 field: u32,
103 other: String,
104 }
105
106 let mut item = Item {
107 field: 1,
108 other: String::from("hello"),
109 };
110 let patch = ItemPatch {
111 field: None,
112 other: Some(String::from("bye")),
113 };
114
115 item.apply(patch);
116 assert_eq!(
117 item,
118 Item {
119 field: 1,
120 other: String::from("bye")
121 }
122 );
123 }
124
125 #[test]
126 #[cfg(feature = "status")]
127 fn test_empty() {
128 #[derive(Patch)]
129 #[patch(attribute(derive(Debug, PartialEq)))]
130 struct Item {
131 data: u32,
132 }
133
134 let patch = ItemPatch { data: None };
135 let other_patch = Item::new_empty_patch();
136 assert!(patch.is_empty());
137 assert_eq!(patch, other_patch);
138 let patch = ItemPatch { data: Some(0) };
139 assert!(!patch.is_empty());
140 }
141
142 #[test]
143 fn test_derive() {
144 #[allow(dead_code)]
145 #[derive(Patch)]
146 #[patch(attribute(derive(Copy, Clone, PartialEq, Debug)))]
147 struct Item;
148
149 let patch = ItemPatch {};
150 let other_patch = patch;
151 assert_eq!(patch, other_patch);
152 }
153
154 #[test]
155 fn test_name() {
156 #[derive(Patch)]
157 #[patch(name = "PatchItem")]
158 struct Item;
159
160 let patch = PatchItem {};
161 let mut item = Item;
162 item.apply(patch);
163 }
164
165 #[test]
166 fn test_nullable() {
167 #[derive(Patch, Debug, PartialEq)]
168 struct Item {
169 field: Option<u32>,
170 other: Option<String>,
171 }
172
173 let mut item = Item {
174 field: Some(1),
175 other: Some(String::from("hello")),
176 };
177 let patch = ItemPatch {
178 field: None,
179 other: Some(None),
180 };
181
182 item.apply(patch);
183 assert_eq!(
184 item,
185 Item {
186 field: Some(1),
187 other: None
188 }
189 );
190 }
191
192 #[test]
193 fn test_skip() {
194 #[derive(Patch, PartialEq, Debug)]
195 #[patch(attribute(derive(PartialEq, Debug, Deserialize)))]
196 struct Item {
197 #[patch(skip)]
198 id: u32,
199 data: u32,
200 }
201
202 let mut item = Item { id: 1, data: 2 };
203 let data = r#"{ "id": 10, "data": 15 }"#; let patch: ItemPatch = serde_json::from_str(data).unwrap();
205 assert_eq!(patch, ItemPatch { data: Some(15) });
206
207 item.apply(patch);
208 assert_eq!(item, Item { id: 1, data: 15 });
209 }
210
211 #[test]
212 fn test_nested() {
213 #[derive(PartialEq, Debug, Default, Patch, Deserialize)]
214 #[patch(attribute(derive(PartialEq, Debug, Deserialize)))]
215 struct B {
216 c: u32,
217 d: u32,
218 }
219
220 #[derive(PartialEq, Debug, Patch, Deserialize)]
221 #[patch(attribute(derive(PartialEq, Debug, Deserialize)))]
222 struct A {
223 #[patch(name = "BPatch")]
224 b: B,
225 }
226 let mut b = B::default();
227 let b_patch: BPatch = serde_json::from_str(r#"{ "d": 1 }"#).unwrap();
228 b.apply(b_patch);
229 assert_eq!(b, B { c: 0, d: 1 });
230
231 let mut a = A { b };
232 let data = r#"{ "b": { "c": 1 } }"#;
233 let patch: APatch = serde_json::from_str(data).unwrap();
234 a.apply(patch);
241 assert_eq!(
242 a,
243 A {
244 b: B { c: 1, d: 1 }
245 }
246 );
247 }
248
249 #[test]
250 fn test_generic() {
251 #[derive(Patch)]
252 struct Item<T>
253 where
254 T: PartialEq,
255 {
256 pub field: T,
257 }
258
259 let patch = ItemPatch {
260 field: Some(String::from("hello")),
261 };
262 let mut item = Item {
263 field: String::new(),
264 };
265 item.apply(patch);
266 assert_eq!(item.field, "hello");
267 }
268
269 #[test]
270 fn test_named_generic() {
271 #[derive(Patch)]
272 #[patch(name = "PatchItem")]
273 struct Item<T>
274 where
275 T: PartialEq,
276 {
277 pub field: T,
278 }
279
280 let patch = PatchItem {
281 field: Some(String::from("hello")),
282 };
283 let mut item = Item {
284 field: String::new(),
285 };
286 item.apply(patch);
287 }
288
289 #[test]
290 fn test_nested_generic() {
291 #[derive(PartialEq, Debug, Default, Patch, Deserialize)]
292 #[patch(attribute(derive(PartialEq, Debug, Deserialize)))]
293 struct B<T>
294 where
295 T: PartialEq,
296 {
297 c: T,
298 d: T,
299 }
300
301 #[derive(PartialEq, Debug, Patch, Deserialize)]
302 #[patch(attribute(derive(PartialEq, Debug, Deserialize)))]
303 struct A {
304 #[patch(name = "BPatch<u32>")]
305 b: B<u32>,
306 }
307
308 let mut b = B::default();
309 let b_patch: BPatch<u32> = serde_json::from_str(r#"{ "d": 1 }"#).unwrap();
310 b.apply(b_patch);
311 assert_eq!(b, B { c: 0, d: 1 });
312
313 let mut a = A { b };
314 let data = r#"{ "b": { "c": 1 } }"#;
315 let patch: APatch = serde_json::from_str(data).unwrap();
316
317 a.apply(patch);
318 assert_eq!(
319 a,
320 A {
321 b: B { c: 1, d: 1 }
322 }
323 );
324 }
325
326 #[cfg(feature = "op")]
327 #[test]
328 fn test_shl() {
329 #[derive(Patch, Debug, PartialEq)]
330 struct Item {
331 field: u32,
332 other: String,
333 }
334
335 let item = Item {
336 field: 1,
337 other: String::from("hello"),
338 };
339 let patch = ItemPatch {
340 field: None,
341 other: Some(String::from("bye")),
342 };
343
344 assert_eq!(
345 item << patch,
346 Item {
347 field: 1,
348 other: String::from("bye")
349 }
350 );
351 }
352
353 #[cfg(all(feature = "op", feature = "merge"))]
354 #[test]
355 fn test_shl_on_patch() {
356 #[derive(Patch, Debug, PartialEq)]
357 struct Item {
358 field: u32,
359 other: String,
360 }
361
362 let mut item = Item {
363 field: 1,
364 other: String::from("hello"),
365 };
366 let patch = ItemPatch {
367 field: None,
368 other: Some(String::from("bye")),
369 };
370 let patch2 = ItemPatch {
371 field: Some(2),
372 other: None,
373 };
374
375 let new_patch = patch << patch2;
376
377 item.apply(new_patch);
378 assert_eq!(
379 item,
380 Item {
381 field: 2,
382 other: String::from("bye")
383 }
384 );
385 }
386
387 #[cfg(feature = "op")]
388 #[test]
389 fn test_add_patches() {
390 #[derive(Patch)]
391 #[patch(attribute(derive(Debug, PartialEq)))]
392 struct Item {
393 field: u32,
394 other: String,
395 }
396
397 let patch = ItemPatch {
398 field: Some(1),
399 other: None,
400 };
401 let patch2 = ItemPatch {
402 field: None,
403 other: Some(String::from("hello")),
404 };
405 let overall_patch = patch + patch2;
406 assert_eq!(
407 overall_patch,
408 ItemPatch {
409 field: Some(1),
410 other: Some(String::from("hello")),
411 }
412 );
413 }
414
415 #[cfg(feature = "op")]
416 #[test]
417 #[should_panic]
418 fn test_add_conflict_patches_panic() {
419 #[derive(Patch, Debug, PartialEq)]
420 struct Item {
421 field: u32,
422 }
423
424 let patch = ItemPatch { field: Some(1) };
425 let patch2 = ItemPatch { field: Some(2) };
426 let _overall_patch = patch + patch2;
427 }
428
429 #[cfg(feature = "merge")]
430 #[test]
431 fn test_merge() {
432 #[allow(dead_code)]
433 #[derive(Patch)]
434 #[patch(attribute(derive(PartialEq, Debug)))]
435 struct Item {
436 a: u32,
437 b: u32,
438 c: u32,
439 d: u32,
440 }
441
442 let patch = ItemPatch {
443 a: None,
444 b: Some(2),
445 c: Some(0),
446 d: None,
447 };
448 let patch2 = ItemPatch {
449 a: Some(1),
450 b: None,
451 c: Some(3),
452 d: None,
453 };
454
455 let merged_patch = patch.merge(patch2);
456 assert_eq!(
457 merged_patch,
458 ItemPatch {
459 a: Some(1),
460 b: Some(2),
461 c: Some(3),
462 d: None,
463 }
464 );
465 }
466
467 #[cfg(feature = "merge")]
468 #[test]
469 fn test_merge_nested() {
470 #[allow(dead_code)]
471 #[derive(Patch, PartialEq, Debug)]
472 #[patch(attribute(derive(PartialEq, Debug, Clone)))]
473 struct B {
474 c: u32,
475 d: u32,
476 e: u32,
477 f: u32,
478 }
479
480 #[allow(dead_code)]
481 #[derive(Patch)]
482 #[patch(attribute(derive(PartialEq, Debug)))]
483 struct A {
484 a: u32,
485 #[patch(name = "BPatch")]
486 b: B,
487 }
488
489 let patches = vec![
490 APatch {
491 a: Some(1),
492 b: Some(BPatch {
493 c: None,
494 d: Some(2),
495 e: Some(0),
496 f: None,
497 }),
498 },
499 APatch {
500 a: Some(0),
501 b: Some(BPatch {
502 c: Some(1),
503 d: None,
504 e: Some(3),
505 f: None,
506 }),
507 },
508 ];
509
510 let merged_patch = patches.into_iter().reduce(Merge::merge).unwrap();
511
512 assert_eq!(
513 merged_patch,
514 APatch {
515 a: Some(0),
516 b: Some(BPatch {
517 c: Some(1),
518 d: Some(2),
519 e: Some(3),
520 f: None,
521 }),
522 }
523 );
524 }
525}