1#[macro_use]
137extern crate nom;
138
139use std::fmt::{self,Debug};
140use std::collections::HashMap;
141use nom::IResult;
142
143pub struct TraceList {
144 pub traces: HashMap<&'static str, Trace>,
145}
146
147impl TraceList {
148 pub fn new() -> Self {
149 let mut traces = HashMap::new();
150 traces.insert("default", Trace::new());
151
152 TraceList { traces }
153 }
154
155 pub fn reset(&mut self, tag: &'static str) {
156 let t = self.traces.entry(tag).or_insert(Trace::new());
157 t.reset();
158 }
159
160 pub fn print(&self, tag: &'static str) {
161 self.traces.get(tag).map(|t| t.print());
162 }
163
164 pub fn activate(&mut self, tag: &'static str) {
165 let t = self.traces.entry(tag).or_insert(Trace::new());
166 t.active = true;
167 }
168
169 pub fn deactivate(&mut self, tag: &'static str) {
170 let t = self.traces.entry(tag).or_insert(Trace::new());
171 t.active = false;
172 }
173
174 pub fn open<T>(&mut self, tag: &'static str, input: T, location: &'static str)
175 where Input: From<T> {
176 let t = self.traces.entry(tag).or_insert(Trace::new());
177 t.open(input, location);
178 }
179
180 pub fn close<I,O:Debug,E:Debug>(&mut self, tag: &'static str, input: I, location: &'static str, result: &nom::IResult<I,O,E>)
181 where Input: From<I> {
182 let t = self.traces.entry(tag).or_insert(Trace::new());
183 t.close(input, location, result);
184 }
185}
186
187pub struct Trace {
190 pub events: Vec<TraceEvent>,
191 pub level: usize,
192 pub active: bool,
193}
194
195impl Trace {
196 pub fn new() -> Self {
197 Trace {
198 events: Vec::new(),
199 level: 0,
200 active: true,
201 }
202 }
203
204 pub fn reset(&mut self) {
205 self.events.clear();
206 self.level = 0;
207 }
208
209 pub fn print(&self) {
210 for event in self.events.iter() {
211 event.print();
212 }
213 }
214
215 pub fn open<T>(&mut self, input: T, location: &'static str)
216 where Input: From<T> {
217 if self.active {
218 self.events.push(TraceEvent::new(
219 self.level,
220 input,
221 location,
222 TraceEventType::Open,
223 ));
224
225 self.level += 1;
226 }
227 }
228
229 pub fn close<I,O:Debug,E:Debug>(&mut self, input: I, location: &'static str, result: &nom::IResult<I,O,E>)
230 where Input: From<I> {
231 if self.active {
232 self.level -= 1;
233 let event_type = match result {
234 Ok((_,o)) => TraceEventType::CloseOk(format!("{:?}", o)),
235 Err(nom::Err::Error(e)) => TraceEventType::CloseError(format!("{:?}", e)),
236 Err(nom::Err::Failure(e)) => TraceEventType::CloseFailure(format!("{:?}", e)),
237 Err(nom::Err::Incomplete(i)) => TraceEventType::CloseIncomplete(i.clone()),
238 };
239 self.events.push(TraceEvent::new(
240 self.level,
241 input,
242 location,
243 event_type
244 ));
245 }
246 }
247}
248
249#[derive(Clone,Debug)]
250pub struct TraceEvent {
251 pub level: usize,
252 pub input: Input,
253 pub location: &'static str,
254 pub event: TraceEventType,
255}
256
257#[derive(Clone,Debug)]
258pub enum TraceEventType {
259 Open,
260 CloseOk(String),
261 CloseError(String),
262 CloseFailure(String),
263 CloseIncomplete(nom::Needed),
264}
265
266impl TraceEvent {
267 pub fn new<T>(level: usize, input: T, location: &'static str, event: TraceEventType) -> Self
268 where Input: From<T> {
269 TraceEvent {
270 level,
271 input: Input::from(input),
272 location,
273 event,
274 }
275 }
276
277 pub fn print(&self) {
278 let indent = std::iter::repeat('\t').take(self.level).collect::<String>();
279 match &self.event {
280 TraceEventType::Open => {
281 println!("{}{}\t{:?}\n", indent, self.location, self.input);
282 },
283 TraceEventType::CloseOk(result) => {
284 println!("{}-> Ok({})", indent, result);
285 },
286 TraceEventType::CloseError(e) => {
287 println!("{}-> Error({})", indent, e);
288 },
289 TraceEventType::CloseFailure(e) => {
290 println!("{}-> Failure({})", indent, e);
291 },
292 TraceEventType::CloseIncomplete(i) => {
293 println!("{}-> Incomplete({:?})", indent, i);
294 },
295 }
296 }
297}
298
299#[derive(Clone)]
300pub enum Input {
301 Bytes(*const u8, usize),
302 String(*const u8, usize),
303}
304
305impl From<&[u8]> for Input {
306 fn from(input: &[u8]) -> Self {
307 Input::Bytes(input.as_ptr(), input.len())
308 }
309}
310
311impl From<&str> for Input {
312 fn from(input: &str) -> Self {
313 Input::String(input.as_ptr(), input.len())
314 }
315}
316
317impl Debug for Input {
318 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
319 match self {
320 Input::String(ptr, len) => {
321 let s = unsafe {
322 std::str::from_utf8_unchecked(std::slice::from_raw_parts(*ptr, *len))
323 };
324 write!(f, "\"{}\"", s)
325 },
326 Input::Bytes(ptr, len) => {
327 let s: &[u8] = unsafe {
328 std::slice::from_raw_parts(*ptr, *len)
329 };
330 write!(f, "{}", to_hex(s, 16))
331 }
332 }
333 }
334}
335
336fn to_hex(input: &[u8], chunk_size: usize) -> String {
337 let mut v = Vec::with_capacity(input.len() * 3);
338 let mut i = 0;
339
340 if input.len() <= chunk_size {
341 to_hex_chunk(input, i, input.len(), &mut v);
342 } else {
343 for chunk in input.chunks(chunk_size) {
344 to_hex_chunk(chunk,
346 i, chunk_size, &mut v);
347 i += chunk_size;
348 v.push(b'\n');
349 }
350 }
351
352 String::from_utf8_lossy(&v[..]).into_owned()
353}
354
355static CHARS: &'static [u8] = b"0123456789abcdef";
356
357fn to_hex_chunk(chunk: &[u8], i: usize, chunk_size: usize, v: &mut Vec<u8>) {
358 let s = format!("{:08x}", i);
359 for &ch in s.as_bytes().iter() {
360 v.push(ch);
361 }
362 v.push(b'\t');
363
364 for &byte in chunk {
365 v.push(CHARS[(byte >> 4) as usize]);
366 v.push(CHARS[(byte & 0xf) as usize]);
367 v.push(b' ');
368 }
369 if chunk_size > chunk.len() {
370 for _ in 0..(chunk_size - chunk.len()) {
371 v.push(b' ');
372 v.push(b' ');
373 v.push(b' ');
374 }
375 }
376 v.push(b'\t');
377
378 for &byte in chunk {
379 if (byte >= 32 && byte <= 126) || byte >= 128 {
380 v.push(byte);
381 } else {
382 v.push(b'.');
383 }
384 }
385}
386
387thread_local! {
388 pub static NOM_TRACE: ::std::cell::RefCell<TraceList> = ::std::cell::RefCell::new(TraceList::new());
389}
390
391#[macro_export]
393macro_rules! print_trace (
394 () => {
395 $crate::NOM_TRACE.with(|trace| {
396 trace.borrow().print("default");
397 });
398 };
399 ($tag:expr) => {
400 $crate::NOM_TRACE.with(|trace| {
401 trace.borrow().print($tag);
402 });
403 };
404);
405
406#[macro_export]
408macro_rules! reset_trace (
409 () => {
410 $crate::NOM_TRACE.with(|trace| {
411 trace.borrow_mut().reset("default");
412 });
413 };
414 ($tag:expr) => {
415 $crate::NOM_TRACE.with(|trace| {
416 trace.borrow_mut().reset($tag);
417 });
418 };
419);
420
421#[macro_export]
423macro_rules! activate_trace (
424 () => {
425 $crate::NOM_TRACE.with(|trace| {
426 trace.borrow_mut().activate("default");
427 });
428 };
429 ($tag:expr) => {
430 $crate::NOM_TRACE.with(|trace| {
431 trace.borrow_mut().activate($tag);
432 });
433 };
434);
435
436#[macro_export]
438macro_rules! deactivate_trace (
439 () => {
440 $crate::NOM_TRACE.with(|trace| {
441 trace.borrow_mut().deactivate("default");
442 });
443 };
444 ($tag:expr) => {
445 $crate::NOM_TRACE.with(|trace| {
446 trace.borrow_mut().deactivate($tag);
447 });
448 };
449);
450
451pub fn tr<I,O,E,F>(tag: &'static str, name: &'static str, f: F) -> impl Fn(I) -> IResult<I,O,E>
453 where Input: From<I>,
454 F: Fn(I) -> IResult<I,O,E>,
455 I: Clone,
456 O: Debug,
457 E: Debug {
458 move |i: I| {
459 let input1 = i.clone();
460 let input2 = i.clone();
461 NOM_TRACE.with(|trace| {
462 (*trace.borrow_mut()).open(tag, input1, name);
463 });
464
465 let res = f(i);
466
467 NOM_TRACE.with(|trace| {
468 (*trace.borrow_mut()).close(tag, input2, name, &res);
469 });
470
471 res
472 }
473}
474
475#[macro_export]
477macro_rules! tr (
478 ($i:expr, $name:ident, $submac:ident!( $($args:tt)* )) => (
479 tr!(__impl $i, "default", stringify!($name), $submac!($($args)*))
480 );
481 ($i:expr, $name:ident, $f:expr) => (
482 tr!(__impl $i, "default", stringify!($name), call!($f))
483 );
484 ($i:expr, $submac:ident!( $($args:tt)* )) => (
485 tr!(__impl $i, "default", stringify!($submac), $submac!($($args)*))
486 );
487 ($i:expr, $f:expr) => (
488 tr!(__impl $i, "default", stringify!($f), call!($f))
489 );
490 (__impl $i:expr, $name:expr, $submac:ident!( $($args:tt)* )) => (
491 tr!(__impl $i, "default", $name, $submac!($($args)*))
492 );
493 (__impl $i:expr, $submac:ident!( $($args:tt)* )) => (
494 tr!(__impl $i, "default", $submac!($($args)*))
495 );
496 (__impl $i:expr, $f:expr) => (
497 tr!(__impl $i, "default", $f)
498 );
499
500 ($i:expr, $tag:expr, $name:ident, $submac:ident!( $($args:tt)* )) => (
501 tr!(__impl $i, $tag, stringify!($name), $submac!($($args)*))
502 );
503 ($i:expr, $tag:expr, $name:ident, $f:expr) => (
504 tr!(__impl $i, $tag, stringify!($name), call!($f))
505 );
506 ($i:expr, $tag:expr, $submac:ident!( $($args:tt)* )) => (
507 tr!(__impl $i, $tag, stringify!($submac), $submac!($($args)*))
508 );
509 ($i:expr, $tag:expr, $f:expr) => (
510 tr!(__impl $i, $tag, stringify!($f), call!($f))
511 );
512 (__impl $i:expr, $tag:expr, $name:expr, $submac:ident!( $($args:tt)* )) => (
513 {
514 let input = $i;
515 $crate::NOM_TRACE.with(|trace| {
516 (*trace.borrow_mut()).open($tag, input, $name);
517 });
518
519 let res = $submac!(input, $($args)*);
520 $crate::NOM_TRACE.with(|trace| {
521 (*trace.borrow_mut()).close($tag, input, $name, &res);
522 });
523
524 res
525 }
526 );
527 (__impl $i:expr, $tag:expr, $submac:ident!( $($args:tt)* )) => (
528 {
529 let input = $i;
530 $crate::NOM_TRACE.with(|trace| {
531 (*trace.borrow_mut()).open($tag, input, stringify!($submac));
532 });
533
534 let res = $submac!(input, $($args)*);
535 $crate::NOM_TRACE.with(|trace| {
536 (*trace.borrow_mut()).close($tag, input, $name, &res);
537 });
538
539 res
540 }
541 );
542 (__impl $i:expr, $tag:expr, $f:expr) => (
543 {
544 let input = $i;
545 $crate::NOM_TRACE.with(|trace| {
546 (*trace.borrow_mut()).open($tag, input, stringify!($f));
547 });
548
549 let res = $f(input);
550 $crate::NOM_TRACE.with(|trace| {
551 (*trace.borrow_mut()).close($tag, input, $name, &res);
552 });
553
554 res
555 }
556 );
557);
558
559
560#[cfg(test)]
561mod tests {
562 use super::*;
563 use nom::character::complete::digit1 as digit;
564
565 #[test]
566 pub fn trace_bytes_parser() {
567 named!(parser<Vec<&[u8]>>,
568 tr!(preceded!(
569 tr!(tag!("data: ")),
570 tr!(delimited!(
571 tag!("("),
572 separated_list!(
573 tr!(tag!(",")),
574 tr!(digit)
575 ),
576 tr!(tag!(")"))
577 ))
578 ))
579 );
580
581 println!("parsed: {:?}", parser(&b"data: (1,2,3)"[..]));
582
583 print_trace!();
584 reset_trace!();
585 panic!();
586 }
587
588 #[test]
589 pub fn trace_str_parser() {
590 named!(parser<&str, Vec<&str>>,
591 tr!(ROOT, preceded!(
592 tr!(tag!("data: ")),
593 tr!(PARENS, delimited!(
594 tag!("("),
595 separated_list!(
596 tr!(tag!(",")),
597 tr!(digit)
598 ),
599 tr!(tag!(")"))
600 ))
601 ))
602 );
603
604 deactivate_trace!();
605 activate_trace!();
606 println!("parsed: {:?}", parser("data: (1,2,3)"));
607
608 print_trace!();
609 reset_trace!();
610 panic!();
611 }
612}