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