1use std::fmt::{Debug, Display, Write};
4
5#[derive(Clone, Copy, PartialEq, Eq)]
7pub struct Location {
8 pub lineno: u32,
10 pub column: u32,
12 pub offset: u32,
14}
15
16impl Debug for Location {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 write!(f, "{}:{}({})", self.lineno, self.column, self.offset)
19 }
20}
21
22impl Display for Location {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 Debug::fmt(self, f)
25 }
26}
27
28pub fn escape_str(value: &str, ascii_only: bool) -> String {
43 let mut ans = String::new();
44 for c in value.chars() {
45 match c {
46 '\0' => ans.push_str("\\0"),
47 '\t' => ans.push_str("\\t"),
48 '\r' => ans.push_str("\\r"),
49 '\n' => ans.push_str("\\n"),
50 '\\' => ans.push_str("\\\\"),
51 '"' => ans.push_str("\\\""),
52 '\'' => ans.push_str("\\\'"),
53 '\x20'..='\x7e' if ascii_only => ans.push(c),
54 _ if ascii_only => ans.push_str(&c.escape_default().to_string()),
55 _ => ans.push(c),
56 }
57 }
58 ans
59}
60
61pub(crate) trait Join<Item: Display>: Iterator<Item = Item> {
62 fn join(&mut self, sep: &str) -> String {
63 if let Some(first) = self.next() {
64 let (lb, _) = self.size_hint();
65 let mut result = String::with_capacity(sep.len() * lb);
66 write!(&mut result, "{}", first).unwrap();
67 self.for_each(|i| {
68 result.push_str(sep);
69 write!(&mut result, "{}", i).unwrap();
70 });
71 result
72 } else {
73 String::new()
74 }
75 }
76}
77
78impl<T: ?Sized, Item: Display> Join<Item> for T where T: Iterator<Item = Item> {}