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