1#![warn(missing_docs)]
13
14use std::any::type_name;
15use std::cell::RefCell;
16use std::collections::HashMap;
17use std::collections::HashSet;
18use std::fmt::Debug;
19use std::fmt::Display;
20use std::fmt::Formatter;
21use std::fmt::Result;
22use std::iter::Iterator;
23use std::ops::Add;
24use std::ops::AddAssign;
25use std::ops::BitOr;
26use std::ops::BitOrAssign;
27
28pub mod prelude {
32 pub use std::marker::PhantomData;
33 pub use std::rc::Rc;
34
35 pub use crate::*;
36}
37
38use prelude::*;
39
40#[macro_export]
50macro_rules! stp {
51 ($i: ident, $t: expr) => {{
52 set_tiles(format!("{}", stringify!($i)), $t.to_string());
53 set_raw_tiles(format!("{}", stringify!($i)), $t.clone());
54 }};
55}
56
57#[macro_export]
68macro_rules! stq {
69 ($e: expr, $t: expr) => {{
70 set_tiles(format!("{}", $e), $t.to_string());
71 set_raw_tiles(format!("{}", $e), $t.clone());
72 }};
73}
74
75#[macro_export]
86macro_rules! gtp {
87 ($i: ident) => {{
88 get_raw_tile(&stringify!($i).to_string())
89 }};
90}
91
92#[macro_export]
104macro_rules! gtq {
105 ($e: expr) => {{
106 let target_tile_name = format!("{}", $e);
107 get_raw_tile(&target_tile_name)
108 }};
109}
110
111#[doc(hidden)]
112pub trait MacroAttributeForT {
118 #[doc(hidden)]
119 fn process(&self) -> RTile;
120}
121
122impl MacroAttributeForT for &str {
123 fn process(&self) -> RTile {
124 RTile::construct_from_str(self)
125 }
126}
127
128impl MacroAttributeForT for String {
129 fn process(&self) -> RTile {
130 RTile::construct_from_str(self.as_str())
131 }
132}
133
134impl MacroAttributeForT for &String {
135 fn process(&self) -> RTile {
136 RTile::construct_from_str(self.as_str())
137 }
138}
139
140impl MacroAttributeForT for RTile {
141 fn process(&self) -> RTile {
142 RTile::construct_from_str(self.to_string().as_str())
143 }
144}
145
146impl MacroAttributeForT for &RTile {
147 fn process(&self) -> RTile {
148 RTile::construct_from_str(self.to_string().as_str())
149 }
150}
151
152impl MacroAttributeForT for Vec<&str> {
153 fn process(&self) -> RTile {
154 RTile::new_str(self.clone())
155 }
156}
157
158impl MacroAttributeForT for Vec<String> {
159 fn process(&self) -> RTile {
160 RTile::new(self.clone())
161 }
162}
163
164#[macro_export]
203macro_rules! tf {
204 ($t: expr) => {{
205 $t.to_string()
206 .split('\n')
207 .collect::<Vec<&str>>()
208 .iter()
209 .map(|&item| item.trim())
210 .collect::<Vec<&str>>()
211 .join("")
212 }};
213}
214
215#[macro_export]
249macro_rules! t {
250 () => {{
251 RTile::new(vec![])
252 }};
253 ("") => {{
254 RTile {
255 name: None,
256 lns: vec!["".to_string()],
257 do_trimming: true,
258 marker: PhantomData::<Rc<()>>,
259 }
260 }};
261 ($e:expr) => {{
262 MacroAttributeForT::process(&$e)
263 }};
264 ($($arg:tt)*) => {{
265 let val = format!($($arg)*);
266 t!(val)
267 }};
268}
269
270#[macro_export]
303macro_rules! tp {
304 ($i:ident) => {{
305 let mut $i = t!();
306 $i.name = Some(stringify!($i).to_string());
307 set_tiles(format!("{}", stringify!($i)), $i.to_string());
308 set_raw_tiles(format!("{}", stringify!($i)), $i.clone());
309 $i
310 }};
311 ($i:ident, $e:expr) => {{
312 let mut $i = t!($e);
313 $i.name = Some(stringify!($i).to_string());
314 set_tiles(format!("{}", stringify!($i)), $i.to_string());
315 set_raw_tiles(format!("{}", stringify!($i)), $i.clone());
316 $i
317 }};
318 ($i:ident, $($arg:tt)*) => {{
319 let val = format!($($arg)*);
320 let mut $i = t!(val);
321 $i.name = Some(stringify!($i).to_string());
322 set_tiles(format!("{}", stringify!($i)), $i.to_string());
323 set_raw_tiles(format!("{}", stringify!($i)), $i.clone());
324 $i
325 }};
326}
327
328#[macro_export]
364macro_rules! tq {
365 ($e:expr) => {{
366 let mut target_tile = t!();
367 let target_tile_name = format!("{}", $e);
368 target_tile.name = Some(target_tile_name.clone());
369 set_tiles(target_tile_name.clone(), target_tile.to_string());
370 set_raw_tiles(target_tile_name, target_tile.clone());
371 target_tile
372 }};
373 ($e:expr, $val:expr) => {{
374 let mut target_tile = t!($val);
375 let target_tile_name = format!("{}", $e);
376 target_tile.name = Some(target_tile_name.clone());
377 set_tiles(target_tile_name.clone(), target_tile.to_string());
378 set_raw_tiles(target_tile_name, target_tile.clone());
379 target_tile
380 }};
381 ($e:expr, $($arg:tt)*) => {{
382 let val = format!($($arg)*);
383 let mut target_tile = t!(val);
384 let target_tile_name = format!("{}", $e);
385 target_tile.name = Some(target_tile_name.clone());
386 set_tiles(target_tile_name.clone(), target_tile.to_string());
387 set_raw_tiles(target_tile_name, target_tile.clone());
388 target_tile
389 }};
390}
391
392#[macro_export]
407macro_rules! tt {
408 ($e:expr) => {{
409 t!(t!($e))
410 }};
411 ($($arg:tt)*) => {{
412 let val = format!($($arg)*);
413 t!(t!(val))
414 }};
415}
416
417#[macro_export]
427macro_rules! ttp {
428 ($i:ident, $e:expr) => {{
429 let mut $i = t!(t!($e));
430 $i.name = Some(stringify!($i).to_string());
431 set_tiles(format!("{}", stringify!($i)), $i.to_string());
432 set_raw_tiles(format!("{}", stringify!($i)), $i.clone());
433 $i
434 }};
435 ($i:ident, $($arg:tt)*) => {{
436 let val = format!($($arg)*);
437 let mut $i = t!(t!(val));
438 $i.name = Some(stringify!($i).to_string());
439 set_tiles(format!("{}", stringify!($i)), $i.to_string());
440 set_raw_tiles(format!("{}", stringify!($i)), $i.clone());
441 $i
442 }};
443}
444
445#[macro_export]
456macro_rules! ttq {
457 ($e:expr, $val:expr) => {{
458 let mut target_tile = t!(t!($val));
459 let target_tile_name = format!("{}", $e);
460 target_tile.name = Some(target_tile_name.clone());
461 set_tiles(target_tile_name.clone(), target_tile.to_string());
462 set_raw_tiles(target_tile_name, target_tile.clone());
463 target_tile
464 }};
465 ($e:expr, $($arg:tt)*) => {{
466 let val = format!($($arg)*);
467 let mut target_tile = t!(t!(val));
468 let target_tile_name = format!("{}", $e);
469 target_tile.name = Some(target_tile_name.clone());
470 set_tiles(target_tile_name.clone(), target_tile.to_string());
471 set_raw_tiles(target_tile_name, target_tile.clone());
472 target_tile
473 }};
474}
475
476#[macro_export]
488macro_rules! sr {
489 ($e:expr) => {{
490 $e.raw()
491 }};
492 ($($arg:tt)*) => {{
493 let val = format!($($arg)*);
494 t!(val).raw()
495 }};
496}
497
498#[macro_export]
515macro_rules! ts {
516 () => {{
517 "".to_string()
518 }};
519 ($e:expr) => {{
520 t!($e).to_string()
521 }};
522 ($($arg:tt)*) => {{
523 let val = format!($($arg)*);
524 t!(val).to_string()
525 }};
526}
527
528#[doc(hidden)]
529pub trait MacroAttributeForK {
535 #[doc(hidden)]
536 fn process(&self) -> RTile;
537}
538
539impl MacroAttributeForK for &str {
540 fn process(&self) -> RTile {
541 RTile::from_str_without_trimming(self)
542 }
543}
544
545impl MacroAttributeForK for String {
546 fn process(&self) -> RTile {
547 RTile::from_str_without_trimming(self.as_str())
548 }
549}
550
551impl MacroAttributeForK for &String {
552 fn process(&self) -> RTile {
553 RTile::from_str_without_trimming(self.as_str())
554 }
555}
556
557impl MacroAttributeForK for RTile {
558 fn process(&self) -> RTile {
559 RTile::from_str_without_trimming(self.to_string().as_str())
560 }
561}
562
563impl MacroAttributeForK for &RTile {
564 fn process(&self) -> RTile {
565 RTile::from_str_without_trimming(self.to_string().as_str())
566 }
567}
568
569impl MacroAttributeForK for Vec<&str> {
570 fn process(&self) -> RTile {
571 RTile::new_without_trimming_str(self.clone())
572 }
573}
574
575impl MacroAttributeForK for Vec<String> {
576 fn process(&self) -> RTile {
577 RTile::new_without_trimming(self.clone())
578 }
579}
580
581#[macro_export]
596macro_rules! kf {
597 ($t: expr) => {{
598 $t.to_string().split('\n').collect::<Vec<&str>>().join("")
599 }};
600}
601
602#[macro_export]
612macro_rules! k {
613 () => {{
614 RTile::new_without_trimming(vec![])
615 }};
616 ("") => {{
617 RTile {
618 name: None,
619 lns: vec!["".to_string()],
620 do_trimming: false,
621 marker: PhantomData::<Rc<()>>,
622 }
623 }};
624 ($e:expr) => {{
625 MacroAttributeForK::process(&$e)
626 }};
627 ($($arg:tt)*) => {{
628 let val = format!($($arg)*);
629 k!(val)
630 }};
631}
632
633#[macro_export]
645macro_rules! kp {
646 ($i:ident) => {{
647 let mut $i = k!();
648 $i.name = Some(stringify!($i).to_string());
649 set_tiles(format!("{}", stringify!($i)), $i.to_string());
650 set_raw_tiles(format!("{}", stringify!($i)), $i.clone());
651 $i
652 }};
653 ($i:ident, $e:expr) => {{
654 let mut $i = k!($e);
655 $i.name = Some(stringify!($i).to_string());
656 set_tiles(format!("{}", stringify!($i)), $i.to_string());
657 set_raw_tiles(format!("{}", stringify!($i)), $i.clone());
658 $i
659 }};
660 ($i:ident, $($arg:tt)*) => {{
661 let val = format!($($arg)*);
662 let mut $i = k!(val);
663 $i.name = Some(stringify!($i).to_string());
664 set_tiles(format!("{}", stringify!($i)), $i.to_string());
665 set_raw_tiles(format!("{}", stringify!($i)), $i.clone());
666 $i
667 }};
668}
669
670#[macro_export]
684macro_rules! kq {
685 ($e:expr) => {{
686 let mut target_tile = k!();
687 let target_tile_name = format!("{}", $e);
688 target_tile.name = Some(target_tile_name.clone());
689 set_tiles(target_tile_name.clone(), target_tile.to_string());
690 set_raw_tiles(target_tile_name, target_tile.clone());
691 target_tile
692 }};
693 ($e:expr, $val:expr) => {{
694 let mut target_tile = k!($val);
695 let target_tile_name = format!("{}", $e);
696 target_tile.name = Some(target_tile_name.clone());
697 set_tiles(target_tile_name.clone(), target_tile.to_string());
698 set_raw_tiles(target_tile_name, target_tile.clone());
699 target_tile
700 }};
701 ($e:expr, $($arg:tt)*) => {{
702 let val = format!($($arg)*);
703 let mut target_tile = k!(val);
704 let target_tile_name = format!("{}", $e);
705 target_tile.name = Some(target_tile_name.clone());
706 set_tiles(target_tile_name.clone(), target_tile.to_string());
707 set_raw_tiles(target_tile_name, target_tile.clone());
708 target_tile
709 }};
710}
711
712#[macro_export]
724macro_rules! kk {
725 ($e:expr) => {{
726 k!(k!($e))
727 }};
728 ($($arg:tt)*) => {{
729 let val = format!($($arg)*);
730 k!(k!(val))
731 }};
732}
733
734#[macro_export]
744macro_rules! kkp {
745 ($i:ident, $e:expr) => {{
746 let mut $i = k!(k!($e));
747 $i.name = Some(stringify!($i).to_string());
748 set_tiles(format!("{}", stringify!($i)), $i.to_string());
749 set_raw_tiles(format!("{}", stringify!($i)), $i.clone());
750 $i
751 }};
752 ($i:ident, $($arg:tt)*) => {{
753 let val = format!($($arg)*);
754 let mut $i = k!(k!(val));
755 $i.name = Some(stringify!($i).to_string());
756 set_tiles(format!("{}", stringify!($i)), $i.to_string());
757 set_raw_tiles(format!("{}", stringify!($i)), $i.clone());
758 $i
759 }};
760}
761
762#[macro_export]
772macro_rules! kkq {
773 ($e:expr, $val:expr) => {{
774 let mut target_tile = k!(k!($val));
775 let target_tile_name = format!("{}", $e);
776 target_tile.name = Some(target_tile_name.clone());
777 set_tiles(target_tile_name.clone(), target_tile.to_string());
778 set_raw_tiles(target_tile_name, target_tile.clone());
779 target_tile
780 }};
781 ($e:expr, $($arg:tt)*) => {{
782 let val = format!($($arg)*);
783 let mut target_tile = k!(k!(val));
784 let target_tile_name = format!("{}", $e);
785 target_tile.name = Some(target_tile_name.clone());
786 set_tiles(target_tile_name.clone(), target_tile.to_string());
787 set_raw_tiles(target_tile_name, target_tile.clone());
788 target_tile
789 }};
790}
791
792#[macro_export]
801macro_rules! ks {
802 () => {{
803 "".to_string()
804 }};
805 ($e:expr) => {{
806 k!($e).to_string()
807 }};
808 ($($arg:tt)*) => {{
809 let val = format!($($arg)*);
810 k!(val).to_string()
811 }};
812}
813
814thread_local! {
815 static TL_PROCESSED_TILES: RefCell<HashMap<String, String>> = RefCell::new(HashMap::new());
816 static TL_RAW_TILES: RefCell<HashMap<String, RTile>> = RefCell::new(HashMap::new());
817}
818
819#[doc(hidden)]
820pub fn set_tiles(key: String, value: String) {
821 TL_PROCESSED_TILES.with_borrow_mut(|v| v.insert(key, value));
822}
823
824#[doc(hidden)]
825pub fn set_raw_tiles(key: String, value: RTile) {
826 TL_RAW_TILES.with_borrow_mut(|v| v.insert(key, value));
827}
828
829#[doc(hidden)]
830pub fn get_raw_tile(key: &str) -> Option<RTile> {
831 let key = &key.to_string();
832
833 TL_RAW_TILES.with_borrow(|v| {
834 if v.contains_key(key) {
835 Some(v.get(key).unwrap().clone())
836 } else {
837 None
838 }
839 })
840}
841
842pub fn remove_tile(key: &str) {
858 let key = &key.to_string();
859 TL_RAW_TILES.with_borrow_mut(|v| v.remove(key));
860 TL_PROCESSED_TILES.with_borrow_mut(|v| v.remove(key));
861}
862
863pub fn clear_tiles() {
876 TL_RAW_TILES.with_borrow_mut(|v| v.clear());
877 TL_PROCESSED_TILES.with_borrow_mut(|v| v.clear());
878}
879
880pub fn get_blank_tiles() -> HashSet<String> {
891 let mut blank_tiles = HashSet::new();
892 TL_RAW_TILES.with_borrow(|v| {
893 for (tile_name, tile) in v.iter() {
894 if tile.lns == Vec::<String>::new() {
895 assert!(!tile_name.is_empty());
896 blank_tiles.insert(tile_name.clone());
897 }
898 }
899 });
900 blank_tiles
901}
902
903fn trim<I, T>(t1: I, do_trimming: bool) -> Vec<String>
904where
905 I: IntoIterator<Item = T> + Debug,
906 T: Into<String>,
907{
908 let t1: Vec<String> = t1.into_iter().map(Into::into).collect();
909 if !do_trimming {
910 return t1;
911 }
912
913 let mut lns: Vec<String> = t1.into_iter().map(|ln| ln.trim_end().to_string()).collect();
914 lns = lns.into_iter().skip_while(|ln| ln.is_empty()).collect();
915 lns.reverse();
916 lns = lns.into_iter().skip_while(|ln| ln.is_empty()).collect();
917 lns.reverse();
918 let lf: Vec<&str> = lns
919 .iter()
920 .filter(|ln| !ln.is_empty())
921 .map(|ln| ln.as_str())
922 .collect();
923 let left = if lf.is_empty() {
924 0
925 } else {
926 lf.iter()
927 .map(|ln| ln.len() - ln.trim_start().len())
928 .min()
929 .unwrap_or(0_usize)
930 };
931 let result = lns
932 .into_iter()
933 .map(|ln| ln.chars().skip(left).collect())
934 .collect();
935 result
936}
937
938fn append<I, T>(t1: &mut Vec<String>, t2: I)
939where
940 I: IntoIterator<Item = T> + Debug,
941 T: Into<String>,
942{
943 let t2: Vec<String> = t2.into_iter().map(Into::into).collect();
944
945 let diff: i32 = t2.len() as i32 - t1.len() as i32;
946 if diff > 0 {
947 t1.extend(vec!["".to_owned(); diff as usize]);
948 }
949 let w = t1.iter().map(|s| s.chars().count()).max().unwrap_or(0);
950 for (i, s) in t2.into_iter().enumerate() {
951 t1[i] = format!("{:<w$}{}", t1[i], s, w = w);
952 }
953}
954
955enum ExtraSteps {
956 DoNothing,
957 DoAppendTheTextFromCursorToInnerTileNameOrTheEndOfLine,
958}
959
960fn get_next_inner_tile_name(
961 ln: &str,
962 current_cursor: &mut usize,
963 end: &mut usize,
964) -> Option<String> {
965 find_next_inner_tile_name(
966 ln,
967 current_cursor,
968 end,
969 &mut Vec::<String>::new(),
970 ExtraSteps::DoNothing,
971 )
972}
973
974fn find_next_inner_tile_name(
975 ln: &str,
976 current_cursor: &mut usize,
977 end: &mut usize,
978 curr: &mut Vec<String>,
979 extra_steps: ExtraSteps,
980) -> Option<String> {
981 let mut start = ln[*current_cursor..].find("@{").unwrap_or(ln.len());
982 if *current_cursor == ln.len() && start == ln.len() && *end == ln.len() && !ln.is_empty() {
983 return None;
984 }
985 if start < ln.len() {
986 start += *current_cursor;
987 }
988
989 if let ExtraSteps::DoAppendTheTextFromCursorToInnerTileNameOrTheEndOfLine = extra_steps {
990 append(curr, vec![&ln[*end..start]]);
991 }
992
993 if start == ln.len() {
994 return None;
995 }
996 *end = ln[start..].find('}').map_or(0, |i| i + 1);
997 if *end == 0 {
998 panic!("unfinished @{{}} expression");
999 }
1000 *end += start;
1001 *current_cursor = *end;
1002 let tile_name = ln[start + 2..*end - 1].to_string();
1003 Some(tile_name)
1004}
1005
1006fn r_format_using_processed_tiles_data(s: &str) -> Vec<String> {
1007 let lns: Vec<&str> = s.split('\n').collect();
1008 let mut res = vec![];
1009 for ln in lns {
1010 let mut curr = vec![];
1011 let mut current_cursor = 0_usize;
1012 let mut end = 0;
1013
1014 while let Some(tile_name) = find_next_inner_tile_name(
1015 ln,
1016 &mut current_cursor,
1017 &mut end,
1018 &mut curr,
1019 ExtraSteps::DoAppendTheTextFromCursorToInnerTileNameOrTheEndOfLine,
1020 ) {
1021 TL_PROCESSED_TILES.with_borrow(|v| {
1022 if v.contains_key(&tile_name) {
1023 let tile_value = v.get(&tile_name).unwrap();
1024 let lns: Vec<&str> = tile_value.split('\n').collect();
1025 append(&mut curr, lns);
1026 } else {
1027 println!("{} tile is not found", tile_name);
1028 }
1029 });
1030 }
1031 res.append(&mut curr);
1032 }
1033 res
1034}
1035
1036fn r_format_using_raw_tiles_data(s: &str) -> Vec<String> {
1037 let lns: Vec<&str> = s.split('\n').collect();
1038 let mut res = vec![];
1039 for ln in lns {
1040 let mut curr = vec![];
1041 let mut current_cursor = 0_usize;
1042 let mut end = 0;
1043
1044 while let Some(tile_name) = find_next_inner_tile_name(
1045 ln,
1046 &mut current_cursor,
1047 &mut end,
1048 &mut curr,
1049 ExtraSteps::DoAppendTheTextFromCursorToInnerTileNameOrTheEndOfLine,
1050 ) {
1051 TL_RAW_TILES.with_borrow(|v_raw| {
1052 if v_raw.contains_key(&tile_name) {
1053 let tile_value = v_raw.get(&tile_name).unwrap();
1054 check_for_recursion_of_tiles(&tile_name, tile_value);
1055 process_all_required_tiles_data(&tile_name, tile_value);
1056
1057 TL_PROCESSED_TILES.with_borrow(|v| {
1058 if v.contains_key(&tile_name) {
1059 let tile_value = v.get(&tile_name).unwrap();
1060 let lns: Vec<&str> = tile_value.split('\n').collect();
1061 append(&mut curr, lns);
1062 } else {
1063 println!("{} tile is not found", tile_name);
1064 }
1065 });
1066 } else {
1067 println!("{} tile is not found", tile_name);
1068 }
1069 });
1070 }
1071 res.append(&mut curr);
1072 }
1073 res
1074}
1075
1076fn check_for_recursion_of_tiles(tile_name: &String, tile_value: &RTile) {
1077 let mut inner_tiles: Vec<String> = vec![];
1078 let mut processed_tiles: HashSet<String> = HashSet::new();
1079 let mut direct_parents: HashSet<String> = HashSet::new();
1080 direct_parents.insert(tile_name.clone());
1081 check_for_recursion_in_inner_tiles(
1082 tile_name,
1083 tile_value,
1084 &mut processed_tiles,
1085 &mut inner_tiles,
1086 &direct_parents,
1087 );
1088}
1089
1090fn process_all_required_tiles_data(tile_name: &String, tile_value: &RTile) {
1091 let mut inner_tiles: Vec<String> = vec![tile_name.clone()];
1092 let mut processed_tiles: HashSet<String> = HashSet::new();
1093
1094 find_inner_tiles(
1095 tile_name,
1096 tile_value,
1097 &mut processed_tiles,
1098 &mut inner_tiles,
1099 );
1100
1101 if !inner_tiles.is_empty() {
1102 for inner_tile_index in (0..inner_tiles.len()).rev() {
1103 let inner_tile_name = inner_tiles.get(inner_tile_index).unwrap();
1104
1105 let result = TL_RAW_TILES.with_borrow(|v| {
1106 if v.contains_key(inner_tile_name) {
1107 let inner_tile_value = v.get(inner_tile_name).unwrap();
1108 inner_tile_value.reevaluate()
1109 } else {
1110 String::new()
1112 }
1113 });
1114
1115 TL_PROCESSED_TILES.with_borrow_mut(|v| v.insert(inner_tile_name.clone(), result));
1116 }
1117 }
1118}
1119
1120fn check_for_recursion_in_inner_tiles(
1121 tile_name: &String,
1122 tile_value: &RTile,
1123 processed_tiles: &mut HashSet<String>,
1124 inner_tiles: &mut Vec<String>,
1125 direct_parents: &HashSet<String>,
1126) {
1127 for ln in &tile_value.lns {
1128 let mut curr = vec![];
1129 let mut current_cursor = 0_usize;
1130 let mut end = 0;
1131
1132 while let Some(inner_tile_name) = find_next_inner_tile_name(
1133 ln,
1134 &mut current_cursor,
1135 &mut end,
1136 &mut curr,
1137 ExtraSteps::DoAppendTheTextFromCursorToInnerTileNameOrTheEndOfLine,
1138 ) {
1139 if processed_tiles.contains(&inner_tile_name) {
1140 continue;
1141 } else {
1142 TL_RAW_TILES.with_borrow(|v| {
1143 if v.contains_key(&inner_tile_name) {
1144 if direct_parents.contains(&inner_tile_name) {
1145 panic!("detected a recursion");
1146 } else {
1147 let inner_tile_value = v.get(&inner_tile_name).unwrap();
1148 inner_tiles.push(inner_tile_name.clone());
1149
1150 let mut all_direct_parents = direct_parents.clone();
1151 all_direct_parents.insert(inner_tile_name.clone());
1152 check_for_recursion_in_inner_tiles(
1153 &inner_tile_name,
1154 inner_tile_value,
1155 processed_tiles,
1156 inner_tiles,
1157 &all_direct_parents,
1158 );
1159 }
1160 } else {
1161 println!("{} tile is not found", inner_tile_name);
1162 }
1163 });
1164 }
1165 }
1166 processed_tiles.insert(tile_name.to_string());
1167 }
1168}
1169
1170fn find_inner_tiles(
1171 tile_name: &String,
1172 tile_value: &RTile,
1173 processed_tiles: &mut HashSet<String>,
1174 inner_tiles: &mut Vec<String>,
1175) {
1176 for ln in &tile_value.lns {
1177 let mut curr = vec![];
1178 let mut current_cursor = 0_usize;
1179 let mut end = 0;
1180 while let Some(inner_tile_name) = find_next_inner_tile_name(
1181 ln,
1182 &mut current_cursor,
1183 &mut end,
1184 &mut curr,
1185 ExtraSteps::DoAppendTheTextFromCursorToInnerTileNameOrTheEndOfLine,
1186 ) {
1187 if processed_tiles.contains(&inner_tile_name) {
1188 continue;
1189 } else {
1190 TL_RAW_TILES.with_borrow(|v| {
1191 if v.contains_key(&inner_tile_name) {
1192 let inner_tile_value = v.get(&inner_tile_name).unwrap();
1193 inner_tiles.push(inner_tile_name.clone());
1194
1195 find_inner_tiles(
1196 &inner_tile_name,
1197 inner_tile_value,
1198 processed_tiles,
1199 inner_tiles,
1200 );
1201 } else {
1202 println!("{} tile is not found", inner_tile_name);
1203 }
1204 });
1205 }
1206 }
1207 processed_tiles.insert(tile_name.to_string());
1208 }
1209}
1210
1211fn identify_any_missing_inner_tiles(
1212 tile_name: Option<String>,
1213 tile_lns: &[String],
1214 processed_tiles: &mut HashSet<String>,
1215 missing_inner_tiles: &mut HashSet<String>,
1216) {
1217 for ln in tile_lns {
1218 let mut curr = vec![];
1219 let mut current_cursor = 0_usize;
1220 let mut end = 0;
1221 while let Some(inner_tile_name) = find_next_inner_tile_name(
1222 ln,
1223 &mut current_cursor,
1224 &mut end,
1225 &mut curr,
1226 ExtraSteps::DoAppendTheTextFromCursorToInnerTileNameOrTheEndOfLine,
1227 ) {
1228 if processed_tiles.contains(&inner_tile_name) {
1229 continue;
1230 } else {
1231 TL_RAW_TILES.with_borrow(|v| {
1232 if v.contains_key(&inner_tile_name) {
1233 let inner_tile_value = v.get(&inner_tile_name).unwrap();
1234
1235 identify_any_missing_inner_tiles(
1236 Some(inner_tile_name.clone()),
1237 &inner_tile_value.lns,
1238 processed_tiles,
1239 missing_inner_tiles,
1240 );
1241 } else if missing_inner_tiles.contains(&inner_tile_name) {
1242 } else {
1243 missing_inner_tiles.insert(inner_tile_name.clone());
1244 }
1245 });
1246 }
1247 }
1248 if tile_name.is_some() {
1249 processed_tiles.insert(tile_name.clone().unwrap());
1250 }
1251 }
1252}
1253
1254fn get_blank_inner_tiles_names(
1255 tile_name: Option<String>,
1256 tile_lns: &[String],
1257 processed_tiles: &mut HashSet<String>,
1258 blank_inner_tiles: &mut Vec<String>,
1259) {
1260 for ln in tile_lns {
1261 let mut curr = vec![];
1262 let mut current_cursor = 0_usize;
1263 let mut end = 0;
1264 while let Some(inner_tile_name) = find_next_inner_tile_name(
1265 ln,
1266 &mut current_cursor,
1267 &mut end,
1268 &mut curr,
1269 ExtraSteps::DoAppendTheTextFromCursorToInnerTileNameOrTheEndOfLine,
1270 ) {
1271 if processed_tiles.contains(&inner_tile_name) {
1272 continue;
1273 } else {
1274 TL_RAW_TILES.with_borrow(|v| {
1275 if v.contains_key(&inner_tile_name) {
1276 let inner_tile_value = v.get(&inner_tile_name).unwrap();
1277 if inner_tile_value.lns == Vec::<String>::new() {
1278 blank_inner_tiles.push(inner_tile_name.clone());
1279 }
1280
1281 get_blank_inner_tiles_names(
1282 Some(inner_tile_name),
1283 &inner_tile_value.lns,
1284 processed_tiles,
1285 blank_inner_tiles,
1286 );
1287 } else {
1288 println!("{} tile is not found", inner_tile_name);
1289 }
1290 });
1291 }
1292 }
1293 if tile_name.is_some() {
1294 processed_tiles.insert(tile_name.clone().unwrap());
1295 }
1296 }
1297}
1298
1299#[doc(hidden)]
1300#[derive(Debug, Clone, PartialEq)]
1301pub struct RTile {
1302 pub name: Option<String>,
1303 pub lns: Vec<String>,
1304 pub do_trimming: bool,
1305 pub marker: PhantomData<Rc<()>>,
1306}
1307
1308impl RTile {
1309 pub fn new_str(lns: Vec<&str>) -> Self {
1310 let lns: Vec<String> = lns.iter().map(|&item| item.to_string()).collect();
1311 create_blank_tiles_of_any_missing_inner_tiles(None, &lns);
1312 Self {
1313 name: None,
1314 lns: trim(lns, true),
1315 do_trimming: true,
1316 marker: PhantomData::<Rc<()>>,
1317 }
1318 }
1319
1320 pub fn new(lns: Vec<String>) -> Self {
1321 create_blank_tiles_of_any_missing_inner_tiles(None, &lns);
1322 Self {
1323 name: None,
1324 lns: trim(lns, true),
1325 do_trimming: true,
1326 marker: PhantomData::<Rc<()>>,
1327 }
1328 }
1329
1330 pub fn construct_from_str(val: &str) -> Self {
1331 let lns: Vec<&str> = val.split('\n').collect();
1332 let lns: Vec<String> = lns.iter().map(|&item| item.to_string()).collect();
1333 create_blank_tiles_of_any_missing_inner_tiles(None, &lns);
1334 Self {
1335 name: None,
1336 lns: trim(lns, true),
1337 do_trimming: true,
1338 marker: PhantomData::<Rc<()>>,
1339 }
1340 }
1341
1342 pub fn new_without_trimming_str(lns: Vec<&str>) -> Self {
1343 let lns: Vec<String> = lns.iter().map(|&item| item.to_string()).collect();
1344 create_blank_tiles_of_any_missing_inner_tiles(None, &lns);
1345 Self {
1346 name: None,
1347 lns: trim(lns, false),
1348 do_trimming: false,
1349 marker: PhantomData::<Rc<()>>,
1350 }
1351 }
1352
1353 pub fn new_without_trimming(lns: Vec<String>) -> Self {
1354 create_blank_tiles_of_any_missing_inner_tiles(None, &lns);
1355 Self {
1356 name: None,
1357 lns: trim(lns, false),
1358 do_trimming: false,
1359 marker: PhantomData::<Rc<()>>,
1360 }
1361 }
1362
1363 pub fn from_str_without_trimming(val: &str) -> Self {
1364 let lns: Vec<&str> = val.split('\n').collect();
1365 let lns: Vec<String> = lns.iter().map(|&item| item.to_string()).collect();
1366 create_blank_tiles_of_any_missing_inner_tiles(None, &lns);
1367 Self {
1368 name: None,
1369 lns: trim(lns, false),
1370 do_trimming: false,
1371 marker: PhantomData::<Rc<()>>,
1372 }
1373 }
1374
1375 pub fn get_names_of_blank_inner_tiles(&self) -> Vec<String> {
1376 let mut processed_tiles: HashSet<String> = HashSet::new();
1377 let mut blank_inner_tiles = vec![];
1378 get_blank_inner_tiles_names(
1379 self.name.clone(),
1380 &self.lns,
1381 &mut processed_tiles,
1382 &mut blank_inner_tiles,
1383 );
1384 blank_inner_tiles
1385 }
1386
1387 pub fn reevaluate(&self) -> String {
1388 trim(
1390 r_format_using_processed_tiles_data(self.lns.join("\n").as_str()),
1391 self.do_trimming,
1392 )
1393 .join("\n")
1394 }
1395
1396 pub fn join<T: Display + Debug>(&self, x: &[T], last: Option<RTile>) -> Self {
1397 let mut res = RTile::new_without_trimming(vec![]);
1398 for (idx, item) in x.iter().enumerate() {
1399 match item {
1400 i if type_name::<T>() == "rtile::RTile" => {
1401 let lns = i
1402 .to_string()
1403 .split('\n')
1404 .collect::<Vec<&str>>()
1405 .iter()
1406 .map(|&item| item.to_string())
1407 .collect();
1408 res += RTile::new_without_trimming(lns);
1409 }
1410 i => {
1411 res += RTile::construct_from_str(i.to_string().as_str());
1412 }
1413 };
1414 if idx < x.len() - 1 {
1415 res += self.clone();
1416 }
1417 }
1418 match last {
1419 Some(t) => res + t,
1420 None => res,
1421 }
1422 }
1423
1424 pub fn vjoin<T: Display + Debug>(&self, x: &[T], inline: bool, last: Option<RTile>) -> Self {
1425 let last = last.unwrap_or_else(|| RTile::new(vec![]));
1426 let mut res = RTile::new_without_trimming(vec![]);
1427 for (idx, item) in x.iter().enumerate() {
1428 match item {
1429 i if type_name::<T>() == "rtile::RTile" => {
1430 let lns = i
1431 .to_string()
1432 .split('\n')
1433 .collect::<Vec<&str>>()
1434 .iter()
1435 .map(|&item| item.to_string())
1436 .collect();
1437
1438 res |= RTile::new_without_trimming(lns)
1439 + if inline {
1440 if idx < x.len() - 1 {
1441 self.clone()
1442 } else {
1443 last.clone()
1444 }
1445 } else {
1446 RTile::construct_from_str("")
1447 }
1448 }
1449 i => {
1450 res |= RTile::construct_from_str(i.to_string().as_str())
1451 + if inline {
1452 if idx < x.len() - 1 {
1453 self.clone()
1454 } else {
1455 last.clone()
1456 }
1457 } else {
1458 RTile::construct_from_str("")
1459 }
1460 }
1461 };
1462 if !inline {
1463 let tile = if idx < x.len() - 1 {
1464 self.clone()
1465 } else {
1466 last.clone()
1467 };
1468 res |= tile;
1469 }
1470 }
1471 res
1472 }
1473
1474 pub fn raw(&self) -> String {
1482 trim(self.lns.clone(), self.do_trimming)
1483 .join("\n")
1484 .to_string()
1485 }
1486
1487 pub fn has_inner_tiles_in_raw_data(&self) -> bool {
1488 for ln in &self.lns {
1489 let start = ln[..].find("@{").unwrap_or(ln.len());
1490 if start == ln.len() {
1491 continue;
1492 }
1493 let end = ln[start..].find('}').map_or(0, |i| i + 1);
1494 if end == 0 {
1495 panic!("unfinished @{{}} expression");
1496 }
1497 return true;
1498 }
1499 false
1500 }
1501
1502 pub fn inner_tiles_in_raw_data(&self) -> Vec<Vec<String>> {
1503 let mut result = vec![];
1504 for ln in &self.lns {
1505 let mut tiles_on_line = vec![];
1506 let mut current_cursor = 0_usize;
1507 let mut end = 0;
1508 while let Some(tile_name) = get_next_inner_tile_name(ln, &mut current_cursor, &mut end)
1509 {
1510 tiles_on_line.push(tile_name.clone());
1511 current_cursor = end;
1512 }
1513 result.push(tiles_on_line);
1514 }
1515 result
1516 }
1517
1518 pub fn inner_tiles(&self) -> HashSet<String> {
1519 let mut inner_tiles: Vec<String> = vec![];
1520 let mut processed_tiles: HashSet<String> = HashSet::new();
1521
1522 find_inner_tiles(&String::new(), self, &mut processed_tiles, &mut inner_tiles);
1523
1524 inner_tiles.into_iter().collect()
1525 }
1526
1527 pub fn flatten(&self) -> String {
1528 self.lns
1529 .iter()
1530 .map(|item| item.trim())
1531 .collect::<Vec<&str>>()
1532 .join("")
1533 }
1534
1535 pub fn dimensions(&self) -> (usize, usize) {
1536 let width = self
1537 .lns
1538 .iter()
1539 .map(|s| s.chars().count())
1540 .max()
1541 .unwrap_or(0);
1542 let height = self.lns.len();
1543 (width, height)
1544 }
1545}
1546
1547fn create_blank_tiles_of_any_missing_inner_tiles(name: Option<String>, lns: &[String]) {
1548 let mut processed_tiles: HashSet<String> = HashSet::new();
1549 let mut missing_inner_tiles: HashSet<String> = HashSet::new();
1550 identify_any_missing_inner_tiles(name, lns, &mut processed_tiles, &mut missing_inner_tiles);
1551 if !missing_inner_tiles.is_empty() {
1552 for missing_inner_tile_name in missing_inner_tiles {
1553 TL_RAW_TILES.with_borrow_mut(|v| {
1554 v.insert(
1555 missing_inner_tile_name.clone(),
1556 RTile {
1557 name: Some(missing_inner_tile_name.clone()),
1558 lns: vec![],
1559 do_trimming: true,
1560 marker: PhantomData::<Rc<()>>,
1561 },
1562 )
1563 });
1564 TL_PROCESSED_TILES
1565 .with_borrow_mut(|v| v.insert(missing_inner_tile_name.clone(), String::new()));
1566 }
1567 }
1568}
1569
1570impl Add for RTile {
1571 type Output = Self;
1572
1573 fn add(self, other: RTile) -> Self::Output {
1574 let mut lns = self.lns.clone();
1575 append(&mut lns, other.lns);
1576
1577 create_blank_tiles_of_any_missing_inner_tiles(None, &lns);
1578
1579 Self {
1580 name: None,
1581 lns,
1582 do_trimming: self.do_trimming,
1583 marker: PhantomData::<Rc<()>>,
1584 }
1585 }
1586}
1587
1588impl AddAssign for RTile {
1589 fn add_assign(&mut self, other: Self) {
1590 append(&mut self.lns, other.lns);
1591 }
1592}
1593
1594impl BitOr for RTile {
1595 type Output = Self;
1596
1597 fn bitor(self, other: RTile) -> Self::Output {
1598 let lns = [&self.lns[..], &other.lns[..]].concat();
1599
1600 create_blank_tiles_of_any_missing_inner_tiles(None, &lns);
1601
1602 Self {
1603 name: None,
1604 lns,
1605 do_trimming: self.do_trimming,
1606 marker: PhantomData::<Rc<()>>,
1607 }
1608 }
1609}
1610
1611impl BitOrAssign for RTile {
1612 fn bitor_assign(&mut self, other: Self) {
1613 self.lns = [&self.lns[..], &other.lns[..]].concat();
1614 }
1615}
1616
1617impl Display for RTile {
1618 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1619 if self.do_trimming {
1620 write!(
1621 f,
1622 "{}",
1623 trim(
1624 r_format_using_raw_tiles_data(self.lns.join("\n").as_str()),
1625 true,
1626 )
1627 .join("\n")
1628 )
1629 } else {
1630 let ktile_vec = r_format_using_raw_tiles_data(self.lns.join("\n").as_str());
1631 let blank_vec = vec![""; ktile_vec.len()];
1632 let output = k!(blank_vec) + k!(ktile_vec) + k!(blank_vec);
1633 write!(
1634 f,
1635 "{}",
1636 r_format_using_raw_tiles_data(output.lns.join("\n").as_str()).join("\n")
1637 )
1638 }
1639 }
1640}