trait_bound_pretty/
lib.rs

1use std::io::Write;
2
3use lalrpop_util::lalrpop_mod;
4
5lalrpop_mod!(pub parser);
6#[cfg(test)]
7mod parser_tests;
8
9pub trait Pretty {
10    /// Pretty-print `Self` to the supplied writer.
11    ///
12    /// This function must only ever write valid utf8 strings.
13    fn pretty_to<Writer: Write>(&self, writer: &mut Writer) -> Result<(), std::io::Error>;
14
15    /// Pretty-print `Self` into a new string.
16    fn pretty(&self) -> String {
17        let mut writer = Vec::new();
18        self.pretty_to(&mut writer)
19            .expect("writing to Vec<u8> should never fail");
20        String::from_utf8(writer).expect("we only ever write valid utf8")
21    }
22}
23
24#[derive(Debug)]
25pub enum Bound<'a> {
26    Lifetime(&'a str),
27    Item(Item<'a>),
28    Reference {
29        lifetime: &'a str,
30        mut_: bool,
31        item: Item<'a>,
32    },
33    Tuple(Vec<Bound<'a>>),
34}
35
36impl<'a> Bound<'a> {
37    fn pretty_internal<Writer: Write>(
38        &self,
39        indent_level: usize,
40        writer: &mut Writer,
41    ) -> Result<(), std::io::Error> {
42        indent(indent_level, writer)?;
43        match self {
44            Self::Lifetime(lifetime) => writer.write_all(lifetime.as_bytes()),
45            Self::Item(item) => item.pretty_internal(indent_level, writer),
46            Self::Reference {
47                lifetime,
48                mut_,
49                item,
50            } => {
51                writer.write_all(b"&")?;
52                writer.write_all(lifetime.as_bytes())?;
53                if *mut_ {
54                    writer.write_all(b" mut")?;
55                }
56                writer.write_all(b" ")?;
57                item.pretty_internal(indent_level, writer)
58            }
59            Self::Tuple(bounds) => {
60                writer.write_all(b"(\n")?;
61                for (idx, bound) in bounds.iter().enumerate() {
62                    bound.pretty_internal(indent_level + 1, writer)?;
63                    if idx != bounds.len() - 1 {
64                        writer.write_all(b",")?;
65                    }
66                    writer.write_all(b"\n")?;
67                }
68                indent(indent_level, writer)?;
69                writer.write_all(b")")
70            }
71        }
72    }
73}
74
75/// A struct, trait, enum, typedef, or generic bound.
76#[derive(Debug)]
77pub struct Item<'a> {
78    /// Note that the name vector is backwards: `item[0]` is the item name; `item[1]` is the parent module, etc.
79    name: Vec<&'a str>,
80    generic_bounds: Vec<Bound<'a>>,
81}
82
83impl<'a> Item<'a> {
84    fn pretty_internal<Writer: Write>(
85        &self,
86        indent_level: usize,
87        writer: &mut Writer,
88    ) -> Result<(), std::io::Error> {
89        for (idx, component) in self.name.iter().enumerate().rev() {
90            writer.write_all(component.as_bytes())?;
91            if idx != 0 {
92                writer.write_all(b"::")?;
93            }
94        }
95        if !self.generic_bounds.is_empty() {
96            writer.write_all(b"<\n")?;
97            for (idx, bound) in self.generic_bounds.iter().enumerate() {
98                bound.pretty_internal(indent_level + 1, writer)?;
99                if idx != self.generic_bounds.len() - 1 {
100                    writer.write_all(b",")?;
101                }
102                writer.write_all(b"\n")?;
103            }
104            indent(indent_level, writer)?;
105            writer.write_all(b">")?;
106        }
107        Ok(())
108    }
109}
110
111impl<'a> Pretty for Item<'a> {
112    fn pretty_to<Writer: Write>(&self, writer: &mut Writer) -> Result<(), std::io::Error> {
113        self.pretty_internal(0, writer)
114    }
115}
116
117const INDENT: &'static [u8] = b"  ";
118fn indent<Writer: Write>(indent_level: usize, writer: &mut Writer) -> Result<(), std::io::Error> {
119    for _ in 0..indent_level {
120        writer.write_all(INDENT)?;
121    }
122    Ok(())
123}
124
125#[derive(Debug)]
126pub struct E0277<'a> {
127    item: Item<'a>,
128    trait_bound: Item<'a>,
129}
130
131impl<'a> Pretty for E0277<'a> {
132    /// Pretty-print this Item to the supplied writer.
133    fn pretty_to<Writer: Write>(&self, writer: &mut Writer) -> Result<(), std::io::Error> {
134        writer.write_all(b"error[E0277]: the item:\n")?;
135        writer.write_all(INDENT)?;
136        self.item.pretty_internal(1, writer)?;
137        writer.write_all(b"\ndoes not satisfy the trait bound:\n")?;
138        writer.write_all(INDENT)?;
139        self.trait_bound.pretty_internal(1, writer)?;
140        Ok(())
141    }
142}