1use std::rc::Rc;
2
3pub trait LogImpl {
4 fn info(&self, ss: &String);
5 fn warn(&self, ss: &String);
6 fn error(&self, ss: &String);
7}
8
9pub struct DefaultLogImpl {}
10impl LogImpl for DefaultLogImpl {
11 fn info(&self, ss: &String) {
12 println!("{}", ss);
13 }
14
15 fn warn(&self, ss: &String) {
16 println!("{}", ss);
17 }
18
19 fn error(&self, ss: &String) {
20 println!("{}", ss);
21 }
22}
23
24pub struct Log4 {
25 pub enable: bool,
27 tags: Vec<String>,
29 delegate: Rc<Box<dyn LogImpl>>,
31}
32
33unsafe impl Sync for Log4 {}
34
35impl Log4 {
36 pub fn new() -> Self {
37 let log = Log4 {
38 enable: true,
39 tags: Vec::new(),
40 delegate: Rc::new(Box::new(DefaultLogImpl {})),
41 };
42 return log;
43 }
44
45 pub fn set_log_impl(&mut self, delegate: Box<dyn LogImpl>) -> &mut Self {
46 self.delegate = Rc::new(delegate);
47 return self;
48 }
49
50 fn to_log_line<T: std::fmt::Debug>(&self, ss: T) -> String {
51 let tags_str: String = if (&self).tags.len() > 0 {
52 format!("[{}]", (&self).tags.join("]["))
53 } else {
54 "".to_string()
55 };
56 let content = format!("{} {:?}", tags_str, ss);
57 return content;
58 }
59 pub fn info<T: std::fmt::Debug>(&self, ss: T) {
60 if self.enable {
61 let content = self.to_log_line(ss);
62 self.delegate.info(&content);
63 }
64 }
65 pub fn warn<T: std::fmt::Debug>(&self, ss: T) {
66 if self.enable {
67 let content = self.to_log_line(ss);
68 self.delegate.warn(&content);
69 }
70 }
71
72 pub fn error<T: std::fmt::Debug>(&self, ss: T) {
73 if self.enable {
74 let content = self.to_log_line(ss);
75 self.delegate.error(&content);
76 }
77 }
78
79 pub fn add_tag<T: std::fmt::Debug>(&mut self, tag: T) -> &mut Log4 {
80 self.tags.push(format!("{:?}", tag));
81 return self;
82 }
83
84 pub fn fork(&self) -> Log4 {
85 let log4 = Log4 {
86 tags: self.tags.clone(),
87 delegate: self.delegate.clone(),
88 enable: self.enable,
89 };
90 return log4;
91 }
92}
93
94#[cfg(test)]
95mod test_log4 {
96 use super::{DefaultLogImpl, Log4};
97 use once_cell::sync::Lazy;
98
99 static mut MYLOG: Lazy<Log4> = Lazy::new(|| Log4::new());
100
101 static mut MYLOG22: Lazy<Log4> = Lazy::new(|| unsafe { MYLOG.fork() });
102
103 #[test]
104 fn test_log() {
105 let mut log = Log4::new();
106 let aaa: String = String::from("AAA");
107 let bbb: &String = &String::from("BBB");
108 log.add_tag(aaa).add_tag(bbb);
109 log.info("CCC");
110 log.info(String::from("DDD"));
112 log.info(bbb);
113
114 let mut log2 = log.fork();
115 log2.add_tag("fork1");
116 log2.info("EEE");
117 log2.warn("GGG");
118 log2.error("HHH");
119
120 log.info("III");
121 log.warn("JJJ");
122 log.error("KKK");
123
124 let mut log3 = log2.fork();
125 log3.info("log enabled");
126 log3.enable = false;
127 log3.info("this log shall not appear");
128 log3.enable = true;
129 log3.info("log enabled again");
130 }
131
132 #[test]
133 fn test_delete() {
134 let mut log = Log4::new();
135 log.set_log_impl(Box::new(DefaultLogImpl {}));
136 log.info("test delegate");
137 }
138
139 #[test]
140 fn test_static() {
141 unsafe {
142 MYLOG.info("static info");
143 MYLOG.warn("static warn");
144 MYLOG.error("static error");
145
146 let log2 = MYLOG.fork();
147 log2.info("fork static info");
148
149 MYLOG22.info("static fork info");
150 }
151 }
152}