1use std::{
100 env,
101 fmt::Debug,
102 marker::PhantomData,
103};
104
105pub trait LogAgent {
107 type Item;
108
109 fn new() -> Self;
110 fn create_log( item: Self::Item ) -> Self;
111 fn append_log( &mut self, item: Self::Item );
112}
113
114impl<T> LogAgent for Vec<T> {
115 type Item = T;
116
117 fn new() -> Self { Vec::new() }
118 fn create_log( item: T ) -> Self { vec![ item ] }
119 fn append_log( &mut self, item: T ) { self.push( item ); }
120}
121
122impl<T> LogAgent for PhantomData<T> {
123 type Item = T;
124
125 fn new() -> Self { PhantomData }
126 fn create_log( _item: T ) -> Self { PhantomData }
127 fn append_log( &mut self, _item: T ) {}
128}
129
130impl LogAgent for String {
131 type Item = String;
132
133 fn new() -> Self { String::new() }
134 fn create_log( item: String ) -> Self { item }
135 fn append_log( &mut self, item: String ) { self.push_str( &format!( "\n{}", item )); }
136}
137
138#[derive( PartialEq,Eq )]
140pub struct Log<Inner, Agent: LogAgent = Vec<Frame>> {
141 pub error : Inner, pub agent : Agent, }
144
145#[cfg( not( feature = "pretty_log" ))]
146impl<Inner,Agent> Debug for Log<Inner,Agent>
147 where Inner: Debug
148 , Agent: Debug + LogAgent
149{
150 fn fmt( &self, f: &mut std::fmt::Formatter ) -> std::fmt::Result {
151 f.debug_struct("Log")
152 .field( "error", &self.error )
153 .field( "agent", &self.agent )
154 .finish()
155 }
156}
157
158#[cfg( feature = "pretty_log" )]
159impl<Inner,Agent> Debug for Log<Inner,Agent>
160 where Inner: Debug
161 , Agent: Debug + LogAgent
162{
163 fn fmt( &self, f: &mut std::fmt::Formatter ) -> std::fmt::Result {
164 if f.alternate() {
165 f.debug_struct("Log")
166 .field( "error", &self.error )
167 .field( "agent", &self.agent )
168 .finish()
169 } else {
170 write!( f, "{:#?}", self )
171 }
172 }
173}
174
175pub type NoLog<Inner,Item=Frame> = Log<Inner,PhantomData<Item>>;
177
178pub trait ToLog<Agent> : Sized
180 where Agent : LogAgent
181{
182 fn new_log( self ) -> Log<Self,Agent>;
183 fn to_log( self, item: Agent::Item ) -> Log<Self,Agent>;
184}
185
186impl<Inner,Agent> ToLog<Agent> for Inner
187 where Agent : LogAgent
188{
189 fn new_log( self ) -> Log<Self,Agent> {
190 Log{ error: self, agent: Agent::new() }
191 }
192
193 fn to_log( self, item: Agent::Item ) -> Log<Inner,Agent> {
194 Log{ error: self, agent: Agent::create_log( item )}
195 }
196}
197
198pub trait Logger<Agent> : Sized
200 where Agent : LogAgent
201{
202 fn log( self, item: Agent::Item ) -> Self;
203}
204
205impl<Agent,E> Logger<Agent> for Log<E,Agent>
206 where Agent : LogAgent
207{
208 fn log( mut self, item: Agent::Item ) -> Self {
209 self.agent.append_log( item );
210 self
211 }
212}
213
214macro_rules! impl_logger_for_predefined_enumx {
215 ($($enumx:ident => $($_index:ident $gen:ident)*;)+) => {
216 use ::enumx::predefined::*;
217 $(
218 impl<Agent$(,$gen)*> Logger<Agent> for $enumx<$($gen),*>
219 where Agent : LogAgent
220 $(, $gen : Logger<Agent> )*
221 {
222 fn log( self, _item: Agent::Item ) -> Self {
223 match self {
224 $( $enumx::$_index( $_index ) => $enumx::$_index( Logger::<Agent>::log( $_index, _item )), )*
225 }
226 }
227 }
228 )+
229 };
230}
231
232impl_logger_for_predefined_enumx! {
233 Enum0 => ;
234 Enum1 => _0 T0;
235 Enum2 => _0 T0 _1 T1;
236 Enum3 => _0 T0 _1 T1 _2 T2;
237 Enum4 => _0 T0 _1 T1 _2 T2 _3 T3;
238 Enum5 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4;
239 Enum6 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4 _5 T5;
240 Enum7 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4 _5 T5 _6 T6;
241 Enum8 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4 _5 T5 _6 T6 _7 T7;
242 Enum9 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4 _5 T5 _6 T6 _7 T7 _8 T8;
243 Enum10 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4 _5 T5 _6 T6 _7 T7 _8 T8 _9 T9;
244 Enum11 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4 _5 T5 _6 T6 _7 T7 _8 T8 _9 T9 _10 T10;
245 Enum12 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4 _5 T5 _6 T6 _7 T7 _8 T8 _9 T9 _10 T10 _11 T11;
246 Enum13 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4 _5 T5 _6 T6 _7 T7 _8 T8 _9 T9 _10 T10 _11 T11 _12 T12;
247 Enum14 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4 _5 T5 _6 T6 _7 T7 _8 T8 _9 T9 _10 T10 _11 T11 _12 T12 _13 T13;
248 Enum15 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4 _5 T5 _6 T6 _7 T7 _8 T8 _9 T9 _10 T10 _11 T11 _12 T12 _13 T13 _14 T14;
249 Enum16 => _0 T0 _1 T1 _2 T2 _3 T3 _4 T4 _5 T5 _6 T6 _7 T7 _8 T8 _9 T9 _10 T10 _11 T11 _12 T12 _13 T13 _14 T14 _15 T15;
250}
251
252#[derive( Debug, PartialEq, Eq )]
254pub struct Env<Agent: LogAgent>( Agent );
255
256impl<Agent> LogAgent for Env<Agent>
257 where Agent : LogAgent
258{
259 type Item = <Agent as LogAgent>::Item;
260
261 fn new() -> Self {
262 Env( Agent::new() )
263 }
264
265 fn append_log( &mut self, item: Self::Item ) {
266 if env_log_enabled() {
267 self.0.append_log( item );
268 }
269 }
270
271 fn create_log( item: Self::Item ) -> Self {
272 if env_log_enabled() {
273 Env( Agent::create_log( item ))
274 } else {
275 Env( Agent::new() )
276 }
277 }
278}
279
280fn env_log_enabled() -> bool {
281 env::var( "RUST_BACKTRACE" )
282 .map( |value| value == "1" || value == "full" )
283 .unwrap_or( false )
284}
285
286pub trait MapToLog<Agent> : Sized
288 where Agent : LogAgent
289{
290 type Output;
291
292 fn map_to_log( self, item: Agent::Item ) -> Self::Output;
293}
294
295impl<Agent,T,E> MapToLog<Agent> for Result<T,E>
296 where E : ToLog<Agent>
297 , Agent : LogAgent
298{
299 type Output = Result<Log<T,Agent>, E>;
300
301 fn map_to_log( self, item: Agent::Item ) -> Self::Output {
302 self.map( |v| v.to_log( item ))
303 }
304}
305
306pub trait MapErrToLog<Agent> : Sized
308 where Agent : LogAgent
309{
310 type Output;
311
312 fn map_err_to_log( self, item: Agent::Item ) -> Self::Output;
313}
314
315impl<Agent,T,E> MapErrToLog<Agent> for Result<T,E>
316 where E : ToLog<Agent>
317 , Agent : LogAgent
318{
319 type Output = Result<T, Log<E,Agent>>;
320
321 fn map_err_to_log( self, item: Agent::Item ) -> Self::Output {
322 self.map_err( |e| e.to_log( item ))
323 }
324}
325
326pub trait MapLog<Agent> : Sized
328 where Agent : LogAgent
329{
330 type Output;
331
332 fn map_log( self, item: Agent::Item ) -> Self::Output;
333}
334
335impl<Agent,T,E> MapLog<Agent> for Result<T,E>
336 where T : Logger<Agent>
337 , Agent : LogAgent
338{
339 type Output = Self;
340
341 fn map_log( self, item: Agent::Item ) -> Self::Output {
342 self.map( |e| e.log( item ))
343 }
344}
345
346pub trait MapErrLog<Agent> : Sized
348 where Agent : LogAgent
349{
350 type Output;
351
352 fn map_err_log( self, item: Agent::Item ) -> Self::Output;
353}
354
355impl<Agent,T,E> MapErrLog<Agent> for Result<T,E>
356 where E : Logger<Agent>
357 , Agent : LogAgent
358{
359 type Output = Self;
360
361 fn map_err_log( self, item: Agent::Item ) -> Self::Output {
362 self.map_err( |e| e.log( item ))
363 }
364}
365
366#[derive( Debug,Default,PartialEq,Eq,PartialOrd,Ord )]
368pub struct Frame {
369 pub module : &'static str,
370 pub file : &'static str,
371 pub line : u32,
372 pub column : u32,
373 pub info : Option<String>,
374}
375
376impl Frame {
377 pub fn new( module: &'static str, file: &'static str, line: u32, column: u32, info: Option<String> ) -> Self {
378 Frame{ module, file, line, column, info }
379 }
380}
381
382#[macro_export]
388macro_rules! frame {
389 ( $expr:expr ) => {
390 Frame::new( module_path!(), file!(), line!(), column!(), Some( String::from( $expr )))
391 };
392 () => {
393 Frame::new( module_path!(), file!(), line!(), column!(), None )
394 };
395}