1use std::fmt;
13
14use crate::types::{
15 family::Family,
16 header::Header,
17 individual::{name::Name, Individual},
18 multimedia::Multimedia,
19 note::Note,
20 repository::Repository,
21 source::Source,
22 submission::Submission,
23 submitter::Submitter,
24 GedcomData,
25};
26
27pub struct GedcomDataDebug<'a>(pub &'a GedcomData);
31
32impl fmt::Debug for GedcomDataDebug<'_> {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 let mut debug = f.debug_struct("GedcomData");
35
36 if self.0.header.is_some() {
37 debug.field("header", &"Some(...)");
38 }
39
40 if !self.0.individuals.is_empty() {
41 debug.field(
42 "individuals",
43 &format!("[{} records]", self.0.individuals.len()),
44 );
45 }
46
47 if !self.0.families.is_empty() {
48 debug.field("families", &format!("[{} records]", self.0.families.len()));
49 }
50
51 if !self.0.sources.is_empty() {
52 debug.field("sources", &format!("[{} records]", self.0.sources.len()));
53 }
54
55 if !self.0.repositories.is_empty() {
56 debug.field(
57 "repositories",
58 &format!("[{} records]", self.0.repositories.len()),
59 );
60 }
61
62 if !self.0.multimedia.is_empty() {
63 debug.field(
64 "multimedia",
65 &format!("[{} records]", self.0.multimedia.len()),
66 );
67 }
68
69 if !self.0.submitters.is_empty() {
70 debug.field(
71 "submitters",
72 &format!("[{} records]", self.0.submitters.len()),
73 );
74 }
75
76 if !self.0.submissions.is_empty() {
77 debug.field(
78 "submissions",
79 &format!("[{} records]", self.0.submissions.len()),
80 );
81 }
82
83 if !self.0.custom_data.is_empty() {
84 debug.field(
85 "custom_data",
86 &format!("[{} records]", self.0.custom_data.len()),
87 );
88 }
89
90 debug.finish()
91 }
92}
93
94pub struct IndividualDebug<'a>(pub &'a Individual);
96
97impl fmt::Debug for IndividualDebug<'_> {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 let mut debug = f.debug_struct("Individual");
100
101 if let Some(ref xref) = self.0.xref {
102 debug.field("xref", xref);
103 }
104
105 if let Some(ref name) = self.0.name {
106 if let Some(ref value) = name.value {
107 debug.field("name", value);
108 }
109 }
110
111 if let Some(ref sex) = self.0.sex {
112 debug.field("sex", &format!("{}", sex.value));
113 }
114
115 if !self.0.events.is_empty() {
116 debug.field("events", &format!("[{} events]", self.0.events.len()));
117 }
118
119 if !self.0.families.is_empty() {
120 debug.field("families", &format!("[{} links]", self.0.families.len()));
121 }
122
123 if !self.0.attributes.is_empty() {
124 debug.field(
125 "attributes",
126 &format!("[{} attrs]", self.0.attributes.len()),
127 );
128 }
129
130 debug.finish_non_exhaustive()
131 }
132}
133
134pub struct FamilyDebug<'a>(pub &'a Family);
136
137impl fmt::Debug for FamilyDebug<'_> {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 let mut debug = f.debug_struct("Family");
140
141 if let Some(ref xref) = self.0.xref {
142 debug.field("xref", xref);
143 }
144
145 if let Some(ref ind1) = self.0.individual1 {
146 debug.field("individual1", ind1);
147 }
148
149 if let Some(ref ind2) = self.0.individual2 {
150 debug.field("individual2", ind2);
151 }
152
153 if !self.0.children.is_empty() {
154 debug.field("children", &format!("[{} children]", self.0.children.len()));
155 }
156
157 if !self.0.events.is_empty() {
158 debug.field("events", &format!("[{} events]", self.0.events.len()));
159 }
160
161 debug.finish_non_exhaustive()
162 }
163}
164
165pub struct SourceDebug<'a>(pub &'a Source);
167
168impl fmt::Debug for SourceDebug<'_> {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 let mut debug = f.debug_struct("Source");
171
172 if let Some(ref xref) = self.0.xref {
173 debug.field("xref", xref);
174 }
175
176 if let Some(ref title) = self.0.title {
177 debug.field("title", title);
178 }
179
180 if let Some(ref author) = self.0.author {
181 debug.field("author", author);
182 }
183
184 if let Some(ref abbr) = self.0.abbreviation {
185 debug.field("abbreviation", abbr);
186 }
187
188 debug.finish_non_exhaustive()
189 }
190}
191
192pub struct RepositoryDebug<'a>(pub &'a Repository);
194
195impl fmt::Debug for RepositoryDebug<'_> {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 let mut debug = f.debug_struct("Repository");
198
199 if let Some(ref xref) = self.0.xref {
200 debug.field("xref", xref);
201 }
202
203 if let Some(ref name) = self.0.name {
204 debug.field("name", name);
205 }
206
207 if self.0.address.is_some() {
208 debug.field("address", &"Some(...)");
209 }
210
211 debug.finish_non_exhaustive()
212 }
213}
214
215pub struct MultimediaDebug<'a>(pub &'a Multimedia);
217
218impl fmt::Debug for MultimediaDebug<'_> {
219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220 let mut debug = f.debug_struct("Multimedia");
221
222 if let Some(ref xref) = self.0.xref {
223 debug.field("xref", xref);
224 }
225
226 if let Some(ref title) = self.0.title {
227 debug.field("title", title);
228 }
229
230 if let Some(ref file) = self.0.file {
231 if let Some(ref value) = file.value {
232 debug.field("file", value);
233 }
234 }
235
236 if let Some(ref form) = self.0.form {
237 if let Some(ref value) = form.value {
238 debug.field("format", value);
239 }
240 }
241
242 debug.finish_non_exhaustive()
243 }
244}
245
246pub struct HeaderDebug<'a>(pub &'a Header);
248
249impl fmt::Debug for HeaderDebug<'_> {
250 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251 let mut debug = f.debug_struct("Header");
252
253 if let Some(ref gedcom) = self.0.gedcom {
254 if let Some(ref version) = gedcom.version {
255 debug.field("gedcom_version", version);
256 }
257 }
258
259 if let Some(ref source) = self.0.source {
260 if let Some(ref name) = source.name {
261 debug.field("source", name);
262 }
263 }
264
265 if let Some(ref encoding) = self.0.encoding {
266 if let Some(ref value) = encoding.value {
267 debug.field("encoding", value);
268 }
269 }
270
271 if let Some(ref date) = self.0.date {
272 if let Some(ref value) = date.value {
273 debug.field("date", value);
274 }
275 }
276
277 debug.finish_non_exhaustive()
278 }
279}
280
281pub struct SubmitterDebug<'a>(pub &'a Submitter);
283
284impl fmt::Debug for SubmitterDebug<'_> {
285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286 let mut debug = f.debug_struct("Submitter");
287
288 if let Some(ref xref) = self.0.xref {
289 debug.field("xref", xref);
290 }
291
292 if let Some(ref name) = self.0.name {
293 debug.field("name", name);
294 }
295
296 debug.finish_non_exhaustive()
297 }
298}
299
300pub struct SubmissionDebug<'a>(pub &'a Submission);
302
303impl fmt::Debug for SubmissionDebug<'_> {
304 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305 let mut debug = f.debug_struct("Submission");
306
307 if let Some(ref xref) = self.0.xref {
308 debug.field("xref", xref);
309 }
310
311 if let Some(ref family_file) = self.0.family_file_name {
312 debug.field("family_file", family_file);
313 }
314
315 if let Some(ref submitter_ref) = self.0.submitter_ref {
316 debug.field("submitter_ref", submitter_ref);
317 }
318
319 debug.finish_non_exhaustive()
320 }
321}
322
323pub struct NameDebug<'a>(pub &'a Name);
325
326impl fmt::Debug for NameDebug<'_> {
327 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
328 let mut debug = f.debug_struct("Name");
329
330 if let Some(ref value) = self.0.value {
331 debug.field("value", value);
332 }
333
334 if let Some(ref given) = self.0.given {
335 debug.field("given", given);
336 }
337
338 if let Some(ref surname) = self.0.surname {
339 debug.field("surname", surname);
340 }
341
342 if let Some(ref prefix) = self.0.prefix {
343 debug.field("prefix", prefix);
344 }
345
346 if let Some(ref suffix) = self.0.suffix {
347 debug.field("suffix", suffix);
348 }
349
350 debug.finish_non_exhaustive()
351 }
352}
353
354pub struct NoteDebug<'a>(pub &'a Note);
356
357impl fmt::Debug for NoteDebug<'_> {
358 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359 let mut debug = f.debug_struct("Note");
360
361 if let Some(ref value) = self.0.value {
362 const MAX_LEN: usize = 50;
364 if value.len() > MAX_LEN {
365 debug.field("value", &format!("{}...", &value[..MAX_LEN]));
366 } else {
367 debug.field("value", value);
368 }
369 }
370
371 if let Some(ref mime) = self.0.mime {
372 debug.field("mime", mime);
373 }
374
375 if let Some(ref lang) = self.0.language {
376 debug.field("language", lang);
377 }
378
379 debug.finish_non_exhaustive()
380 }
381}
382
383pub trait ImprovedDebug {
385 fn debug(&self) -> impl fmt::Debug;
387}
388
389impl ImprovedDebug for GedcomData {
390 fn debug(&self) -> impl fmt::Debug {
391 GedcomDataDebug(self)
392 }
393}
394
395impl ImprovedDebug for Individual {
396 fn debug(&self) -> impl fmt::Debug {
397 IndividualDebug(self)
398 }
399}
400
401impl ImprovedDebug for Family {
402 fn debug(&self) -> impl fmt::Debug {
403 FamilyDebug(self)
404 }
405}
406
407impl ImprovedDebug for Source {
408 fn debug(&self) -> impl fmt::Debug {
409 SourceDebug(self)
410 }
411}
412
413impl ImprovedDebug for Repository {
414 fn debug(&self) -> impl fmt::Debug {
415 RepositoryDebug(self)
416 }
417}
418
419impl ImprovedDebug for Multimedia {
420 fn debug(&self) -> impl fmt::Debug {
421 MultimediaDebug(self)
422 }
423}
424
425impl ImprovedDebug for Header {
426 fn debug(&self) -> impl fmt::Debug {
427 HeaderDebug(self)
428 }
429}
430
431impl ImprovedDebug for Submitter {
432 fn debug(&self) -> impl fmt::Debug {
433 SubmitterDebug(self)
434 }
435}
436
437impl ImprovedDebug for Submission {
438 fn debug(&self) -> impl fmt::Debug {
439 SubmissionDebug(self)
440 }
441}
442
443impl ImprovedDebug for Name {
444 fn debug(&self) -> impl fmt::Debug {
445 NameDebug(self)
446 }
447}
448
449impl ImprovedDebug for Note {
450 fn debug(&self) -> impl fmt::Debug {
451 NoteDebug(self)
452 }
453}
454
455#[cfg(test)]
456mod tests {
457 use super::*;
458 use crate::Gedcom;
459
460 #[test]
461 fn test_gedcom_data_improved_debug() {
462 let sample = "\
463 0 HEAD\n\
464 1 GEDC\n\
465 2 VERS 5.5\n\
466 0 @I1@ INDI\n\
467 1 NAME John /Doe/\n\
468 0 @I2@ INDI\n\
469 1 NAME Jane /Doe/\n\
470 0 @F1@ FAM\n\
471 1 HUSB @I1@\n\
472 1 WIFE @I2@\n\
473 0 TRLR";
474
475 let mut gedcom = Gedcom::new(sample.chars()).unwrap();
476 let data = gedcom.parse_data().unwrap();
477
478 let debug_output = format!("{:?}", data.debug());
479 assert!(debug_output.contains("GedcomData"));
480 assert!(debug_output.contains("[2 records]")); assert!(debug_output.contains("[1 records]")); }
483
484 #[test]
485 fn test_individual_improved_debug() {
486 let sample = "\
487 0 HEAD\n\
488 1 GEDC\n\
489 2 VERS 5.5\n\
490 0 @I1@ INDI\n\
491 1 NAME John /Doe/\n\
492 1 SEX M\n\
493 1 BIRT\n\
494 2 DATE 1 JAN 1900\n\
495 0 TRLR";
496
497 let mut gedcom = Gedcom::new(sample.chars()).unwrap();
498 let data = gedcom.parse_data().unwrap();
499
500 let debug_output = format!("{:?}", data.individuals[0].debug());
501 assert!(debug_output.contains("Individual"));
502 assert!(debug_output.contains("@I1@"));
503 assert!(debug_output.contains("John /Doe/"));
504 assert!(debug_output.contains("Male"));
505 assert!(debug_output.contains("[1 events]"));
506 }
507
508 #[test]
509 fn test_family_improved_debug() {
510 let sample = "\
511 0 HEAD\n\
512 1 GEDC\n\
513 2 VERS 5.5\n\
514 0 @F1@ FAM\n\
515 1 HUSB @I1@\n\
516 1 WIFE @I2@\n\
517 1 CHIL @I3@\n\
518 1 CHIL @I4@\n\
519 0 TRLR";
520
521 let mut gedcom = Gedcom::new(sample.chars()).unwrap();
522 let data = gedcom.parse_data().unwrap();
523
524 let debug_output = format!("{:?}", data.families[0].debug());
525 assert!(debug_output.contains("Family"));
526 assert!(debug_output.contains("@F1@"));
527 assert!(debug_output.contains("@I1@"));
528 assert!(debug_output.contains("@I2@"));
529 assert!(debug_output.contains("[2 children]"));
530 }
531
532 #[test]
533 fn test_source_improved_debug() {
534 let sample = "\
535 0 HEAD\n\
536 1 GEDC\n\
537 2 VERS 5.5\n\
538 0 @S1@ SOUR\n\
539 1 TITL Census Records\n\
540 1 AUTH Government\n\
541 0 TRLR";
542
543 let mut gedcom = Gedcom::new(sample.chars()).unwrap();
544 let data = gedcom.parse_data().unwrap();
545
546 let debug_output = format!("{:?}", data.sources[0].debug());
547 assert!(debug_output.contains("Source"));
548 assert!(debug_output.contains("@S1@"));
549 assert!(debug_output.contains("Census Records"));
550 assert!(debug_output.contains("Government"));
551 }
552
553 #[test]
554 fn test_header_improved_debug() {
555 let sample = "\
556 0 HEAD\n\
557 1 GEDC\n\
558 2 VERS 5.5\n\
559 1 SOUR TestApp\n\
560 2 NAME Test Application\n\
561 1 CHAR UTF-8\n\
562 0 TRLR";
563
564 let mut gedcom = Gedcom::new(sample.chars()).unwrap();
565 let data = gedcom.parse_data().unwrap();
566
567 let header = data.header.as_ref().unwrap();
568 let debug_output = format!("{:?}", header.debug());
569 assert!(debug_output.contains("Header"));
570 assert!(debug_output.contains("5.5"));
571 assert!(debug_output.contains("UTF-8"));
572 }
573
574 #[test]
575 fn test_note_truncation_in_debug() {
576 let long_content = "A".repeat(100);
577 let note = Note {
578 value: Some(long_content),
579 mime: None,
580 translation: None,
581 citation: None,
582 language: None,
583 };
584
585 let debug_output = format!("{:?}", note.debug());
586 assert!(debug_output.contains("..."));
587 assert!(!debug_output.contains(&"A".repeat(100)));
589 }
590
591 #[test]
592 fn test_name_improved_debug() {
593 let name = Name {
594 value: Some("John /Doe/".to_string()),
595 given: Some("John".to_string()),
596 surname: Some("Doe".to_string()),
597 prefix: None,
598 surname_prefix: None,
599 note: None,
600 suffix: Some("Jr.".to_string()),
601 nickname: None,
602 source: Vec::new(),
603 name_type: None,
604 phonetic: Vec::new(),
605 romanized: Vec::new(),
606 custom_data: Vec::new(),
607 };
608
609 let debug_output = format!("{:?}", name.debug());
610 assert!(debug_output.contains("Name"));
611 assert!(debug_output.contains("John /Doe/"));
612 assert!(debug_output.contains("given"));
613 assert!(debug_output.contains("surname"));
614 assert!(debug_output.contains("Jr."));
615 }
616}