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