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