1use std::error;
2use std::fmt;
3use std::io::{self, Write};
4use std::iter;
5use std::string::FromUtf8Error;
6
7#[derive(Clone, Debug)]
84pub enum Event<'a> {
85 StartTrack(usize),
101
102 StartTracks(&'a [usize]),
119
120 StopTrack(usize),
137
138 Station(usize, &'a str),
162
163 SplitTrack(usize, usize),
183
184 JoinTrack(usize, usize),
217
218 NoEvent,
228}
229
230pub fn to_writer<W: Write>(mut writer: W, events: &[Event]) -> Result<(), Error> {
246 let mut tracks = vec![0];
247
248 for event in events {
249 use Event::*;
250 match event {
251 &StartTrack(track_id) => {
252 if !tracks.contains(&track_id) {
253 tracks.push(track_id);
254
255 let line = iter::repeat("|")
256 .take(tracks.len())
257 .collect::<Vec<_>>()
258 .join(" ");
259
260 writeln!(&mut writer, "{}", line)?;
261 }
262 }
263
264 &StartTracks(track_ids) => {
265 let mut render = false;
266
267 for track_id in track_ids.iter() {
268 if !tracks.contains(track_id) {
269 tracks.push(*track_id);
270
271 render = true;
272 }
273 }
274
275 if render {
276 let line = iter::repeat("|")
277 .take(tracks.len())
278 .collect::<Vec<_>>()
279 .join(" ");
280
281 writeln!(&mut writer, "{}", line)?;
282 }
283 }
284
285 &StopTrack(track_id) => stop_track(&mut writer, &mut tracks, track_id)?,
286
287 &Station(track_id, station_name) => {
288 let line = tracks
289 .iter()
290 .map(|&id| if id == track_id { "*" } else { "|" })
291 .collect::<Vec<_>>()
292 .join(" ");
293
294 writeln!(&mut writer, "{} {}", line, station_name)?;
295 }
296
297 &SplitTrack(from_track_id, new_track_id) => {
298 if !tracks.contains(&new_track_id) {
299 let from_track_index = tracks.iter().position(|&id| id == from_track_id);
300
301 if let Some(from_track_index) = from_track_index {
302 let line = (0..tracks.len())
303 .map(|i| {
304 use std::cmp::Ordering::*;
305 match i.cmp(&from_track_index) {
306 Greater => "\\",
307 Equal => "|\\",
308 Less => "|",
309 }
310 })
311 .collect::<Vec<_>>()
312 .join(" ");
313
314 writeln!(&mut writer, "{}", line)?;
315
316 tracks.insert(from_track_index + 1, new_track_id);
317 } else {
318 tracks.push(new_track_id);
319
320 let line = iter::repeat("|")
321 .take(tracks.len())
322 .collect::<Vec<_>>()
323 .join(" ");
324
325 writeln!(&mut writer, "{}", line)?;
326 }
327 }
328 }
329
330 &JoinTrack(from_track_id, to_track_id) => {
331 let from_track_index = tracks.iter().position(|&id| id == from_track_id);
332
333 if from_track_id == to_track_id {
334 stop_track(&mut writer, &mut tracks, from_track_id)?;
335 continue;
336 }
337
338 if let Some(from_track_index) = from_track_index {
339 let to_track_index = tracks.iter().position(|&id| id == to_track_id);
340
341 if let Some(to_track_index) = to_track_index {
342 let left_index = from_track_index.min(to_track_index);
343 let right_index = from_track_index.max(to_track_index);
344
345 if (right_index - left_index) == 1 {
346 let line = (0..tracks.len())
347 .filter_map(|i| {
348 if i > right_index {
349 Some("/")
350 } else if i == left_index {
351 Some("|/")
352 } else if i != right_index {
353 Some("|")
354 } else {
355 None
356 }
357 })
358 .collect::<Vec<_>>()
359 .join(" ");
360
361 writeln!(&mut writer, "{}", line)?;
362 } else {
363 let line = (0..tracks.len())
364 .filter_map(|i| {
365 if i > right_index {
366 Some(" /")
367 } else if i == right_index {
368 None
369 } else if i >= (right_index - 1) {
370 Some("|/")
371 } else if i > left_index {
372 Some("|_")
373 } else {
374 Some("| ")
375 }
376 })
377 .collect::<Vec<_>>()
378 .concat();
379
380 writeln!(&mut writer, "{}", line)?;
381
382 let track_count = tracks.len() - 1;
383 let line = (0..track_count)
384 .map(|i| {
385 if i == left_index {
386 "|/"
387 } else if i == (track_count - 1) {
388 "|"
389 } else {
390 "| "
391 }
392 })
393 .collect::<Vec<_>>()
394 .concat();
395
396 writeln!(&mut writer, "{}", line)?;
397 }
398
399 tracks.remove(from_track_index);
400 } else {
401 stop_track(&mut writer, &mut tracks, from_track_id)?;
402 }
403 }
404 }
405
406 NoEvent => {
407 let line = iter::repeat("|")
408 .take(tracks.len())
409 .collect::<Vec<_>>()
410 .join(" ");
411
412 writeln!(&mut writer, "{}", line)?;
413 }
414 }
415 }
416
417 Ok(())
418}
419
420fn stop_track<W: Write>(
421 mut writer: W,
422 tracks: &mut Vec<usize>,
423 track_id: usize,
424) -> Result<(), Error> {
425 if let Some(index) = tracks.iter().position(|&id| id == track_id) {
426 let line = (0..tracks.len())
427 .map(|i| if i == index { "\"" } else { "|" })
428 .collect::<Vec<_>>()
429 .join(" ");
430
431 writeln!(&mut writer, "{}", line)?;
432
433 if index != (tracks.len() - 1) {
434 let line = (0..tracks.len())
435 .map(|i| {
436 use std::cmp::Ordering::*;
437 match i.cmp(&index) {
438 Greater => "/",
439 Equal => "",
440 Less => "|",
441 }
442 })
443 .collect::<Vec<_>>()
444 .join(" ");
445
446 writeln!(&mut writer, "{}", line)?;
447 }
448
449 tracks.remove(index);
450 }
451
452 Ok(())
453}
454
455#[inline]
471pub fn to_vec(events: &[Event]) -> Result<Vec<u8>, Error> {
472 let mut vec = Vec::new();
473 to_writer(&mut vec, events)?;
474 Ok(vec)
475}
476
477#[inline]
493pub fn to_string(events: &[Event]) -> Result<String, Error> {
494 let vec = to_vec(events)?;
495 Ok(String::from_utf8(vec)?)
496}
497
498#[derive(Debug)]
505pub enum Error {
506 IoError(io::Error),
510
511 FromUtf8Error(FromUtf8Error),
515}
516
517impl fmt::Display for Error {
518 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
519 use Error::*;
520 match self {
521 IoError(err) => err.fmt(fmt),
522 FromUtf8Error(err) => err.fmt(fmt),
523 }
524 }
525}
526
527impl error::Error for Error {
528 #[inline]
529 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
530 use Error::*;
531 match self {
532 IoError(ref err) => Some(err),
533 FromUtf8Error(ref err) => Some(err),
534 }
535 }
536}
537
538impl From<io::Error> for Error {
539 #[inline]
540 fn from(err: io::Error) -> Self {
541 Self::IoError(err)
542 }
543}
544
545impl From<FromUtf8Error> for Error {
546 #[inline]
547 fn from(err: FromUtf8Error) -> Self {
548 Self::FromUtf8Error(err)
549 }
550}
551
552#[cfg(test)]
553mod tests {
554 use super::to_string;
555 use super::Event::*;
556
557 #[test]
558 fn start_track() {
559 let events = [StartTrack(1)];
560 let string = to_string(&events).unwrap();
561
562 assert_eq!(string, "| |\n");
563 }
564
565 #[test]
566 fn start_track_already_exists() {
567 let events = [StartTrack(0)];
568 let string = to_string(&events).unwrap();
569
570 assert_eq!(string, "");
571 }
572
573 #[test]
574 fn start_track_already_exists2() {
575 #[rustfmt::skip]
576 let events = [
577 StartTrack(1),
578 StartTrack(2),
579 StartTrack(1),
580 StartTrack(2),
581 ];
582 let string = to_string(&events).unwrap();
583
584 assert_eq!(string, "| |\n| | |\n");
585 }
586
587 #[test]
588 fn start_track_default() {
589 let events = [StartTrack(0)];
590 let string = to_string(&events).unwrap();
591
592 assert_eq!(string, "");
593 }
594
595 #[test]
596 fn event_start_track_default2() {
597 let events = [StartTrack(1)];
598 let string = to_string(&events).unwrap();
599
600 assert_eq!(string, "| |\n");
601 }
602
603 #[test]
604 fn event_start_tracks() {
605 let events = [StartTracks(&[1, 2, 3])];
606 let string = to_string(&events).unwrap();
607
608 assert_eq!(string, "| | | |\n");
609 }
610
611 #[test]
612 fn start_tracks_some_already_exist() {
613 let events = [StartTracks(&[0, 1, 2])];
614 let string = to_string(&events).unwrap();
615
616 assert_eq!(string, "| | |\n");
617 }
618
619 #[test]
620 fn start_tracks_all_already_exist() {
621 let events = [StartTracks(&[0, 0, 0])];
622 let string = to_string(&events).unwrap();
623
624 assert_eq!(string, "");
625 }
626
627 #[test]
628 fn stop_track() {
629 let events = [StopTrack(0)];
630 let string = to_string(&events).unwrap();
631
632 assert_eq!(string, "\"\n");
633 }
634
635 #[test]
636 fn stop_track_does_not_exist() {
637 let events = [StopTrack(1)];
638 let string = to_string(&events).unwrap();
639
640 assert_eq!(string, "");
641 }
642
643 #[test]
644 fn stop_track_left() {
645 #[rustfmt::skip]
646 let events = [
647 StartTracks(&[0, 1, 2, 3, 4]),
648 StopTrack(0),
649 NoEvent,
650 ];
651 let string = to_string(&events).unwrap();
652
653 assert_eq!(
654 string,
655 r#"| | | | |
656" | | | |
657 / / / /
658| | | |
659"#
660 );
661 }
662
663 #[test]
664 fn stop_track_middle() {
665 #[rustfmt::skip]
666 let events = [
667 StartTracks(&[0, 1, 2, 3, 4]),
668 StopTrack(2),
669 NoEvent,
670 ];
671 let string = to_string(&events).unwrap();
672
673 assert_eq!(
674 string,
675 r#"| | | | |
676| | " | |
677| | / /
678| | | |
679"#
680 );
681 }
682
683 #[test]
684 fn stop_track_right() {
685 #[rustfmt::skip]
686 let events = [
687 StartTracks(&[0, 1, 2, 3, 4]),
688 StopTrack(4),
689 NoEvent,
690 ];
691 let string = to_string(&events).unwrap();
692
693 assert_eq!(
694 string,
695 r#"| | | | |
696| | | | "
697| | | |
698"#
699 );
700 }
701
702 #[test]
703 fn station() {
704 let events = [
705 StartTracks(&[0, 1, 2]),
706 Station(0, "Station 1"),
707 Station(1, "Station 2"),
708 Station(2, "Station 3"),
709 Station(0, "Station 4"),
710 Station(1, "Station 5"),
711 Station(2, "Station 6"),
712 ];
713 let string = to_string(&events).unwrap();
714
715 assert_eq!(
716 string,
717 r#"| | |
718* | | Station 1
719| * | Station 2
720| | * Station 3
721* | | Station 4
722| * | Station 5
723| | * Station 6
724"#
725 );
726 }
727
728 #[test]
729 fn station_non_existing_track() {
730 let events = [
731 StartTracks(&[0, 1, 2]),
732 Station(0, "Station 1"),
733 Station(1, "Station 2"),
734 Station(2, "Station 3"),
735 Station(3, "Station 4"),
736 Station(4, "Station 5"),
737 Station(5, "Station 6"),
738 Station(std::usize::MAX, "Station 7"),
739 ];
740 let string = to_string(&events).unwrap();
741
742 assert_eq!(
743 string,
744 r#"| | |
745* | | Station 1
746| * | Station 2
747| | * Station 3
748| | | Station 4
749| | | Station 5
750| | | Station 6
751| | | Station 7
752"#
753 );
754 }
755
756 #[test]
757 fn split_track() {
758 let events = [
759 SplitTrack(0, 1),
760 NoEvent,
761 SplitTrack(0, 2),
762 SplitTrack(1, 3),
763 SplitTrack(3, 4),
764 ];
765 let string = to_string(&events).unwrap();
766
767 assert_eq!(
768 string,
769 r#"|\
770| |
771|\ \
772| | |\
773| | | |\
774"#
775 );
776 }
777
778 #[test]
779 fn split_track_non_existing_from_track() {
780 let events1 = [
781 SplitTrack(1, 2),
782 SplitTrack(3, 4),
783 Station(2, "2"),
784 Station(4, "4"),
785 ];
786 let events2 = [
787 StartTrack(2),
788 StartTrack(4),
789 Station(2, "2"),
790 Station(4, "4"),
791 ];
792
793 let string1 = to_string(&events1).unwrap();
794 let string2 = to_string(&events2).unwrap();
795
796 assert_eq!(string1, string2);
797 }
798
799 #[test]
800 fn split_track_already_existing_new_track() {
801 let events1 = [
802 StartTracks(&[0, 1, 2]),
803 SplitTrack(0, 1),
804 SplitTrack(0, 2),
805 SplitTrack(3, 4),
806 Station(0, "0"),
807 Station(1, "1"),
808 Station(2, "2"),
809 Station(3, "3"),
810 Station(4, "4"),
811 ];
812 let events2 = [
813 StartTracks(&[0, 1, 2]),
814 StartTrack(4),
815 Station(0, "0"),
816 Station(1, "1"),
817 Station(2, "2"),
818 Station(3, "3"),
819 Station(4, "4"),
820 ];
821
822 let string1 = to_string(&events1).unwrap();
823 let string2 = to_string(&events2).unwrap();
824
825 assert_eq!(string1, string2);
826 }
827
828 #[test]
829 fn split_track_same_from_and_new_track() {
830 let events = [SplitTrack(0, 0)];
831 let string = to_string(&events).unwrap();
832
833 assert_eq!(string, "");
834
835 #[rustfmt::skip]
836 let events1 = [
837 StartTracks(&[0, 1, 2]),
838 SplitTrack(1, 1),
839 SplitTrack(0, 2),
840 ];
841 let events2 = [StartTracks(&[0, 1, 2])];
842
843 let string1 = to_string(&events1).unwrap();
844 let string2 = to_string(&events2).unwrap();
845
846 assert_eq!(string1, string2);
847 }
848
849 #[test]
850 fn join_track_zero_between() {
851 #[rustfmt::skip]
852 let events = [
853 StartTracks(&[0, 1, 2]),
854 JoinTrack(1, 0),
855 NoEvent,
856 ];
857 let string = to_string(&events).unwrap();
858
859 assert_eq!(
860 string,
861 r#"| | |
862|/ /
863| |
864"#
865 );
866 }
867
868 #[test]
869 fn join_track_one_between() {
870 #[rustfmt::skip]
871 let events = [
872 StartTracks(&[0, 1, 2]),
873 JoinTrack(2, 0),
874 NoEvent,
875 ];
876 let string = to_string(&events).unwrap();
877
878 assert_eq!(
879 string,
880 r#"| | |
881| |/
882|/|
883| |
884"#
885 );
886 }
887
888 #[test]
889 fn join_track_many_between() {
890 #[rustfmt::skip]
891 let events = [
892 StartTracks(&[0, 1, 2, 3, 4]),
893 JoinTrack(4, 0),
894 NoEvent,
895 ];
896 let string = to_string(&events).unwrap();
897
898 assert_eq!(
899 string,
900 r#"| | | | |
901| |_|_|/
902|/| | |
903| | | |
904"#
905 );
906 }
907
908 #[test]
909 fn join_track_always_leftmost() {
910 let events1 = [
911 StartTracks(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
912 JoinTrack(4, 1),
913 JoinTrack(5, 0),
914 JoinTrack(8, 7),
915 JoinTrack(9, 6),
916 NoEvent,
917 ];
918
919 let events2 = events1
920 .iter()
921 .cloned()
922 .map(|event| match event {
923 JoinTrack(from, to) => JoinTrack(to, from),
924 _ => event,
925 })
926 .collect::<Vec<_>>();
927
928 let string1 = to_string(&events1).unwrap();
929 let string2 = to_string(&events2).unwrap();
930
931 assert_eq!(string1, string2);
934 }
935
936 #[test]
939 fn join_track_non_existing_from_track_existing_to_track() {
940 let events1 = [
941 StartTracks(&[0, 1, 2, 3, 4]),
942 JoinTrack(5, 0),
943 JoinTrack(10, 1),
944 ];
945 let events2 = [StartTracks(&[0, 1, 2, 3, 4])];
946
947 let string1 = to_string(&events1).unwrap();
948 let string2 = to_string(&events2).unwrap();
949
950 assert_eq!(string1, string2);
951 }
952
953 #[test]
954 fn join_track_non_existing_from_track_non_existing_to_track() {
955 let events1 = [
956 StartTracks(&[0, 1, 2, 3, 4]),
957 JoinTrack(5, 6),
958 JoinTrack(10, 11),
959 ];
960 let events2 = [StartTracks(&[0, 1, 2, 3, 4])];
961
962 let string1 = to_string(&events1).unwrap();
963 let string2 = to_string(&events2).unwrap();
964
965 assert_eq!(string1, string2);
966 }
967
968 #[test]
969 fn join_track_existing_from_track_non_existing_to_track() {
970 let events1 = [
971 StartTracks(&[0, 1, 2, 3, 4]),
972 JoinTrack(0, 5),
973 JoinTrack(2, 10),
974 ];
975 #[rustfmt::skip]
976 let events2 = [
977 StartTracks(&[0, 1, 2, 3, 4]),
978 StopTrack(0),
979 StopTrack(2),
980 ];
981
982 let string1 = to_string(&events1).unwrap();
983 let string2 = to_string(&events2).unwrap();
984
985 assert_eq!(string1, string2);
986 }
987
988 #[test]
989 fn join_track_same_from_and_to_track() {
990 let events1 = [
991 StartTracks(&[0, 1, 2, 3, 4]),
992 JoinTrack(0, 0),
993 JoinTrack(2, 2),
994 JoinTrack(10, 10),
995 ];
996 #[rustfmt::skip]
997 let events2 = [
998 StartTracks(&[0, 1, 2, 3, 4]),
999 StopTrack(0),
1000 StopTrack(2),
1001 ];
1002
1003 let string1 = to_string(&events1).unwrap();
1004 let string2 = to_string(&events2).unwrap();
1005
1006 assert_eq!(string1, string2);
1007 }
1008
1009 #[test]
1010 fn no_event() {
1011 let events = [NoEvent, NoEvent, NoEvent];
1012 let string = to_string(&events).unwrap();
1013
1014 assert_eq!(string, "|\n|\n|\n");
1015
1016 #[rustfmt::skip]
1017 let events = [
1018 StartTracks(&[0, 1, 2]),
1019 NoEvent,
1020 NoEvent,
1021 NoEvent,
1022 ];
1023 let string = to_string(&events).unwrap();
1024
1025 assert_eq!(string, "| | |\n| | |\n| | |\n| | |\n");
1026 }
1027}