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