1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use serde::de::{Deserialize, Deserializer};
4 use serde::ser::{Serialize, SerializeStruct, Serializer};
5 
6 use crate::toc::*;
7 use crate::TagList;
8 use crate::TocEntryType;
9 use crate::TocLoopType;
10 use crate::TocScope;
11 
12 impl Serialize for TocRef {
serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>13     fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
14         let mut toc = serializer.serialize_struct("Toc", 3)?;
15         toc.serialize_field("scope", &self.scope())?;
16         toc.serialize_field("tags", &self.tags())?;
17         toc.serialize_field("entries", &self.entries())?;
18         toc.end()
19     }
20 }
21 
22 impl Serialize for Toc {
serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>23     fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
24         self.as_ref().serialize(serializer)
25     }
26 }
27 
28 impl Serialize for TocEntryRef {
serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>29     fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
30         let mut toc_entry = serializer.serialize_struct("TocEntry", 6)?;
31         toc_entry.serialize_field("entry_type", &self.entry_type())?;
32         toc_entry.serialize_field("uid", &self.uid())?;
33         toc_entry.serialize_field("start_stop", &self.start_stop_times())?;
34         toc_entry.serialize_field("tags", &self.tags())?;
35         toc_entry.serialize_field("loop", &self.loop_())?;
36         toc_entry.serialize_field("sub_entries", &self.sub_entries())?;
37         toc_entry.end()
38     }
39 }
40 
41 impl Serialize for TocEntry {
serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>42     fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
43         self.as_ref().serialize(serializer)
44     }
45 }
46 
47 #[derive(serde::Deserialize)]
48 struct TocDe {
49     scope: TocScope,
50     tags: Option<TagList>,
51     entries: Vec<TocEntry>,
52 }
53 
54 impl From<TocDe> for Toc {
from(mut toc_de: TocDe) -> Self55     fn from(mut toc_de: TocDe) -> Self {
56         skip_assert_initialized!();
57         let mut toc = Toc::new(toc_de.scope);
58         {
59             let toc = toc.get_mut().unwrap();
60             if let Some(tags) = toc_de.tags.take() {
61                 toc.set_tags(tags);
62             }
63             let entry_iter = toc_de.entries.drain(..);
64             for entry in entry_iter {
65                 toc.append_entry(entry);
66             }
67         }
68         toc
69     }
70 }
71 
72 impl<'de> Deserialize<'de> for Toc {
deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>73     fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
74         skip_assert_initialized!();
75         TocDe::deserialize(deserializer).map(|toc_de| toc_de.into())
76     }
77 }
78 
79 #[derive(serde::Deserialize)]
80 struct TocEntryDe {
81     entry_type: TocEntryType,
82     uid: String,
83     start_stop: Option<(i64, i64)>,
84     tags: Option<TagList>,
85     #[serde(rename = "loop")]
86     loop_: Option<(TocLoopType, i32)>,
87     sub_entries: Vec<TocEntry>,
88 }
89 
90 impl From<TocEntryDe> for TocEntry {
from(mut toc_entry_de: TocEntryDe) -> Self91     fn from(mut toc_entry_de: TocEntryDe) -> Self {
92         skip_assert_initialized!();
93         let mut toc_entry = TocEntry::new(toc_entry_de.entry_type, toc_entry_de.uid.as_str());
94         {
95             let toc_entry = toc_entry.get_mut().unwrap();
96             if let Some(start_stop) = toc_entry_de.start_stop.take() {
97                 toc_entry.set_start_stop_times(start_stop.0, start_stop.1);
98             }
99             if let Some(tags) = toc_entry_de.tags.take() {
100                 toc_entry.set_tags(tags);
101             }
102             if let Some(loop_) = toc_entry_de.loop_.take() {
103                 toc_entry.set_loop(loop_.0, loop_.1);
104             }
105 
106             let entry_iter = toc_entry_de.sub_entries.drain(..);
107             for sub_entries in entry_iter {
108                 toc_entry.append_sub_entry(sub_entries);
109             }
110         }
111         toc_entry
112     }
113 }
114 
115 impl<'de> Deserialize<'de> for TocEntry {
deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>116     fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
117         skip_assert_initialized!();
118         TocEntryDe::deserialize(deserializer).map(|toc_entry_de| toc_entry_de.into())
119     }
120 }
121 
122 #[cfg(test)]
123 mod tests {
124     use crate::tags::Title;
125     use crate::toc::*;
126     use crate::TagList;
127     use crate::TagMergeMode;
128     use crate::TocEntryType;
129     use crate::TocScope;
130 
131     #[test]
test_serialize()132     fn test_serialize() {
133         crate::init().unwrap();
134 
135         let mut toc = Toc::new(TocScope::Global);
136         {
137             let toc = toc.get_mut().unwrap();
138             let mut tags = TagList::new();
139             tags.get_mut()
140                 .unwrap()
141                 .add::<Title>(&"toc", TagMergeMode::Append);
142             toc.set_tags(tags);
143 
144             let mut toc_edition = TocEntry::new(TocEntryType::Edition, "edition");
145             {
146                 let toc_edition = toc_edition.get_mut().unwrap();
147                 toc_edition.set_start_stop_times(0, 15);
148 
149                 let mut toc_chap_1 = TocEntry::new(TocEntryType::Chapter, "chapter1");
150                 {
151                     let toc_chap_1 = toc_chap_1.get_mut().unwrap();
152                     toc_chap_1.set_start_stop_times(0, 10);
153                     let mut toc_chap_1_1 = TocEntry::new(TocEntryType::Chapter, "chapter1.1");
154                     {
155                         let toc_chap_1_1 = toc_chap_1_1.get_mut().unwrap();
156                         toc_chap_1_1.set_start_stop_times(0, 4);
157                         let mut tags = TagList::new();
158                         tags.get_mut()
159                             .unwrap()
160                             .add::<Title>(&"chapter 1.1", TagMergeMode::Append);
161                         toc_chap_1_1.set_tags(tags);
162                     }
163                     toc_chap_1.append_sub_entry(toc_chap_1_1);
164 
165                     let mut toc_chap_1_2 = TocEntry::new(TocEntryType::Chapter, "chapter1.2");
166                     {
167                         let toc_chap_1_2 = toc_chap_1_2.get_mut().unwrap();
168                         toc_chap_1_2.set_start_stop_times(4, 10);
169                         let mut tags = TagList::new();
170                         tags.get_mut()
171                             .unwrap()
172                             .add::<Title>(&"chapter 1.2", TagMergeMode::Append);
173                         toc_chap_1_2.set_tags(tags);
174                     }
175                     toc_chap_1.append_sub_entry(toc_chap_1_2);
176                 }
177                 toc_edition.append_sub_entry(toc_chap_1);
178 
179                 let mut toc_chap_2 = TocEntry::new(TocEntryType::Chapter, "chapter2");
180                 {
181                     let toc_chap_2 = toc_chap_2.get_mut().unwrap();
182                     toc_chap_2.set_start_stop_times(10, 15);
183                     let mut tags = TagList::new();
184                     tags.get_mut()
185                         .unwrap()
186                         .add::<Title>(&"chapter 2", TagMergeMode::Append);
187                     toc_chap_2.set_tags(tags);
188                 }
189                 toc_edition.append_sub_entry(toc_chap_2);
190             }
191             toc.append_entry(toc_edition);
192         }
193 
194         let pretty_config = ron::ser::PrettyConfig::new().with_new_line("".to_string());
195 
196         let res = ron::ser::to_string_pretty(&toc, pretty_config);
197         assert_eq!(
198             Ok(concat!(
199                 "(",
200                 "    scope: Global,",
201                 "    tags: Some((",
202                 "        scope: Stream,",
203                 "        tags: [",
204                 "            (\"title\", [",
205                 "                \"toc\",",
206                 "            ]),",
207                 "        ],",
208                 "    )),",
209                 "    entries: [",
210                 "        (",
211                 "            entry_type: Edition,",
212                 "            uid: \"edition\",",
213                 "            start_stop: Some((0, 15)),",
214                 "            tags: None,",
215                 "            loop: Some((None, 0)),",
216                 "            sub_entries: [",
217                 "                (",
218                 "                    entry_type: Chapter,",
219                 "                    uid: \"chapter1\",",
220                 "                    start_stop: Some((0, 10)),",
221                 "                    tags: None,",
222                 "                    loop: Some((None, 0)),",
223                 "                    sub_entries: [",
224                 "                        (",
225                 "                            entry_type: Chapter,",
226                 "                            uid: \"chapter1.1\",",
227                 "                            start_stop: Some((0, 4)),",
228                 "                            tags: Some((",
229                 "                                scope: Stream,",
230                 "                                tags: [",
231                 "                                    (\"title\", [",
232                 "                                        \"chapter 1.1\",",
233                 "                                    ]),",
234                 "                                ],",
235                 "                            )),",
236                 "                            loop: Some((None, 0)),",
237                 "                            sub_entries: [],",
238                 "                        ),",
239                 "                        (",
240                 "                            entry_type: Chapter,",
241                 "                            uid: \"chapter1.2\",",
242                 "                            start_stop: Some((4, 10)),",
243                 "                            tags: Some((",
244                 "                                scope: Stream,",
245                 "                                tags: [",
246                 "                                    (\"title\", [",
247                 "                                        \"chapter 1.2\",",
248                 "                                    ]),",
249                 "                                ],",
250                 "                            )),",
251                 "                            loop: Some((None, 0)),",
252                 "                            sub_entries: [],",
253                 "                        ),",
254                 "                    ],",
255                 "                ),",
256                 "                (",
257                 "                    entry_type: Chapter,",
258                 "                    uid: \"chapter2\",",
259                 "                    start_stop: Some((10, 15)),",
260                 "                    tags: Some((",
261                 "                        scope: Stream,",
262                 "                        tags: [",
263                 "                            (\"title\", [",
264                 "                                \"chapter 2\",",
265                 "                            ]),",
266                 "                        ],",
267                 "                    )),",
268                 "                    loop: Some((None, 0)),",
269                 "                    sub_entries: [],",
270                 "                ),",
271                 "            ],",
272                 "        ),",
273                 "    ],",
274                 ")",
275             )
276             .to_owned()),
277             res,
278         );
279     }
280 
281     #[allow(clippy::cognitive_complexity)]
282     #[test]
test_deserialize()283     fn test_deserialize() {
284         use crate::tags::Title;
285 
286         crate::init().unwrap();
287 
288         let toc_ron = r#"
289             (
290                 scope: Global,
291                 tags: Some((
292                     scope: Stream,
293                     tags: [
294                         ("title", ["toc"]),
295                     ],
296                 )),
297                 entries: [
298                     (
299                         entry_type: Edition,
300                         uid: "edition",
301                         start_stop: Some((0, 15)),
302                         tags: None,
303                         loop: Some((None, 0)),
304                         sub_entries: [
305                             (
306                                 entry_type: Chapter,
307                                 uid: "chapter1",
308                                 start_stop: Some((0, 10)),
309                                 tags: None,
310                                 loop: Some((None, 0)),
311                                 sub_entries: [
312                                     (
313                                         entry_type: Chapter,
314                                         uid: "chapter1.1",
315                                         start_stop: Some((0, 4)),
316                                         tags: Some((
317                                             scope: Stream,
318                                             tags: [
319                                                 ("title", ["chapter 1.1"]),
320                                             ],
321                                         )),
322                                         loop: Some((None, 0)),
323                                         sub_entries: [
324                                         ],
325                                     ),
326                                     (
327                                         entry_type: Chapter,
328                                         uid: "chapter1.2",
329                                         start_stop: Some((4, 10)),
330                                         tags: Some((
331                                             scope: Stream,
332                                             tags: [
333                                                 ("title", ["chapter 1.2"]),
334                                             ],
335                                         )),
336                                         loop: Some((None, 0)),
337                                         sub_entries: [
338                                         ],
339                                     ),
340                                 ],
341                             ),
342                             (
343                                 entry_type: Chapter,
344                                 uid: "chapter2",
345                                 start_stop: Some((10, 15)),
346                                 tags: Some((
347                                     scope: Stream,
348                                     tags: [
349                                         ("title", ["chapter 2"]),
350                                     ],
351                                 )),
352                                 loop: Some((None, 0)),
353                                 sub_entries: [
354                                 ],
355                             ),
356                         ],
357                     ),
358                 ],
359             )
360         "#;
361         let toc: Toc = ron::de::from_str(toc_ron).unwrap();
362         assert_eq!(toc.scope(), TocScope::Global);
363 
364         let entries = toc.entries();
365         assert_eq!(1, entries.len());
366 
367         let edition = &entries[0];
368         assert_eq!(TocEntryType::Edition, edition.entry_type());
369         assert_eq!("edition", edition.uid());
370         assert!(edition.tags().is_none());
371         assert_eq!(Some((0, 15)), edition.start_stop_times());
372 
373         let sub_entries = edition.sub_entries();
374         assert_eq!(2, sub_entries.len());
375 
376         let chapter1 = &sub_entries[0];
377         assert_eq!(TocEntryType::Chapter, chapter1.entry_type());
378         assert_eq!("chapter1", chapter1.uid());
379         assert!(chapter1.tags().is_none());
380         assert_eq!(Some((0, 10)), chapter1.start_stop_times());
381 
382         let chap1_sub_entries = chapter1.sub_entries();
383         assert_eq!(2, sub_entries.len());
384 
385         let chapter1_1 = &chap1_sub_entries[0];
386         assert_eq!(TocEntryType::Chapter, chapter1_1.entry_type());
387         assert_eq!("chapter1.1", chapter1_1.uid());
388         assert_eq!(Some((0, 4)), chapter1_1.start_stop_times());
389         let tags = chapter1_1.tags().unwrap();
390         assert_eq!("chapter 1.1", tags.index::<Title>(0).unwrap().get());
391         assert_eq!(0, chapter1_1.sub_entries().len());
392 
393         let chapter1_2 = &chap1_sub_entries[1];
394         assert_eq!(TocEntryType::Chapter, chapter1_2.entry_type());
395         assert_eq!("chapter1.2", chapter1_2.uid());
396         assert_eq!(Some((4, 10)), chapter1_2.start_stop_times());
397         let tags = chapter1_2.tags().unwrap();
398         assert_eq!("chapter 1.2", tags.index::<Title>(0).unwrap().get());
399         assert_eq!(0, chapter1_2.sub_entries().len());
400 
401         let chapter2 = &sub_entries[1];
402         assert_eq!(TocEntryType::Chapter, chapter2.entry_type());
403         assert_eq!("chapter2", chapter2.uid());
404         let tags = chapter2.tags().unwrap();
405         assert_eq!("chapter 2", tags.index::<Title>(0).unwrap().get());
406         assert_eq!(Some((10, 15)), chapter2.start_stop_times());
407         assert_eq!(0, chapter2.sub_entries().len());
408     }
409 
410     #[allow(clippy::cognitive_complexity)]
411     #[test]
test_serde_roundtrip()412     fn test_serde_roundtrip() {
413         crate::init().unwrap();
414 
415         let mut toc = Toc::new(TocScope::Global);
416         {
417             let toc = toc.get_mut().unwrap();
418             let mut tags = TagList::new();
419             tags.get_mut()
420                 .unwrap()
421                 .add::<Title>(&"toc", TagMergeMode::Append);
422             toc.set_tags(tags);
423 
424             let mut toc_edition = TocEntry::new(TocEntryType::Edition, "edition");
425             {
426                 let toc_edition = toc_edition.get_mut().unwrap();
427                 toc_edition.set_start_stop_times(0, 15);
428 
429                 let mut toc_chap_1 = TocEntry::new(TocEntryType::Chapter, "chapter1");
430                 {
431                     let toc_chap_1 = toc_chap_1.get_mut().unwrap();
432                     toc_chap_1.set_start_stop_times(0, 10);
433                     let mut toc_chap_1_1 = TocEntry::new(TocEntryType::Chapter, "chapter1.1");
434                     {
435                         let toc_chap_1_1 = toc_chap_1_1.get_mut().unwrap();
436                         toc_chap_1_1.set_start_stop_times(0, 4);
437                         let mut tags = TagList::new();
438                         tags.get_mut()
439                             .unwrap()
440                             .add::<Title>(&"chapter 1.1", TagMergeMode::Append);
441                         toc_chap_1_1.set_tags(tags);
442                     }
443                     toc_chap_1.append_sub_entry(toc_chap_1_1);
444 
445                     let mut toc_chap_1_2 = TocEntry::new(TocEntryType::Chapter, "chapter1.2");
446                     {
447                         let toc_chap_1_2 = toc_chap_1_2.get_mut().unwrap();
448                         toc_chap_1_2.set_start_stop_times(4, 10);
449                         let mut tags = TagList::new();
450                         tags.get_mut()
451                             .unwrap()
452                             .add::<Title>(&"chapter 1.2", TagMergeMode::Append);
453                         toc_chap_1_2.set_tags(tags);
454                     }
455                     toc_chap_1.append_sub_entry(toc_chap_1_2);
456                 }
457                 toc_edition.append_sub_entry(toc_chap_1);
458 
459                 let mut toc_chap_2 = TocEntry::new(TocEntryType::Chapter, "chapter2");
460                 {
461                     let toc_chap_2 = toc_chap_2.get_mut().unwrap();
462                     toc_chap_2.set_start_stop_times(10, 15);
463                     let mut tags = TagList::new();
464                     tags.get_mut()
465                         .unwrap()
466                         .add::<Title>(&"chapter 2", TagMergeMode::Append);
467                     toc_chap_2.set_tags(tags);
468                 }
469                 toc_edition.append_sub_entry(toc_chap_2);
470             }
471             toc.append_entry(toc_edition);
472         }
473         let toc_ser = ron::ser::to_string(&toc).unwrap();
474 
475         let toc_de: Toc = ron::de::from_str(toc_ser.as_str()).unwrap();
476         assert_eq!(toc_de.scope(), toc.scope());
477 
478         let entries_de = toc_de.entries();
479         let entries = toc.entries();
480         assert_eq!(entries_de.len(), entries.len());
481 
482         let edition_de = &entries_de[0];
483         let edition = &entries[0];
484         assert_eq!(edition_de.entry_type(), edition.entry_type());
485         assert_eq!(edition_de.uid(), edition.uid());
486         assert_eq!(edition_de.tags(), edition.tags());
487         assert_eq!(edition_de.start_stop_times(), edition.start_stop_times());
488 
489         let sub_entries_de = edition_de.sub_entries();
490         let sub_entries = edition.sub_entries();
491         assert_eq!(sub_entries_de.len(), sub_entries.len());
492 
493         let chapter1_de = &sub_entries_de[0];
494         let chapter1 = &sub_entries[0];
495         assert_eq!(chapter1_de.entry_type(), chapter1.entry_type());
496         assert_eq!(chapter1_de.uid(), chapter1.uid());
497         assert_eq!(chapter1_de.tags().is_none(), chapter1.tags().is_none());
498         assert_eq!(chapter1_de.start_stop_times(), chapter1.start_stop_times());
499 
500         let chap1_sub_entries_de = chapter1_de.sub_entries();
501         let chap1_sub_entries = chapter1.sub_entries();
502         assert_eq!(sub_entries_de.len(), sub_entries.len());
503 
504         let chapter1_1_de = &chap1_sub_entries_de[0];
505         let chapter1_1 = &chap1_sub_entries[0];
506         assert_eq!(chapter1_1_de.entry_type(), chapter1_1.entry_type());
507         assert_eq!(chapter1_1_de.uid(), chapter1_1.uid());
508         assert_eq!(
509             chapter1_1_de.start_stop_times(),
510             chapter1_1.start_stop_times()
511         );
512         let tags_de = chapter1_1_de.tags().unwrap();
513         let tags = chapter1_1.tags().unwrap();
514         assert_eq!(
515             tags_de.index::<Title>(0).unwrap().get(),
516             tags.index::<Title>(0).unwrap().get()
517         );
518         assert_eq!(
519             chapter1_1_de.sub_entries().len(),
520             chapter1_1.sub_entries().len()
521         );
522 
523         let chapter1_2_de = &chap1_sub_entries_de[1];
524         let chapter1_2 = &chap1_sub_entries[1];
525         assert_eq!(chapter1_2_de.entry_type(), chapter1_2.entry_type());
526         assert_eq!(chapter1_2_de.uid(), chapter1_2.uid());
527         assert_eq!(
528             chapter1_2_de.start_stop_times(),
529             chapter1_2.start_stop_times()
530         );
531         let tags_de = chapter1_2_de.tags().unwrap();
532         let tags = chapter1_2.tags().unwrap();
533         assert_eq!(
534             tags_de.index::<Title>(0).unwrap().get(),
535             tags.index::<Title>(0).unwrap().get()
536         );
537         assert_eq!(
538             chapter1_2_de.sub_entries().len(),
539             chapter1_2.sub_entries().len()
540         );
541 
542         let chapter2_de = &sub_entries_de[1];
543         let chapter2 = &sub_entries[1];
544         assert_eq!(chapter2_de.entry_type(), chapter2.entry_type());
545         assert_eq!(chapter2_de.uid(), chapter2.uid());
546         let tags_de = chapter2_de.tags().unwrap();
547         let tags = chapter2.tags().unwrap();
548         assert_eq!(
549             tags_de.index::<Title>(0).unwrap().get(),
550             tags.index::<Title>(0).unwrap().get()
551         );
552         assert_eq!(chapter2_de.start_stop_times(), chapter2.start_stop_times());
553         assert_eq!(
554             chapter2_de.sub_entries().len(),
555             chapter2.sub_entries().len()
556         );
557     }
558 }
559