chalk_solve/display/
utils.rs

1//! Render utilities which don't belong anywhere else.
2use std::fmt::{Display, Formatter, Result};
3
4pub fn as_display<F: Fn(&mut Formatter<'_>) -> Result>(f: F) -> impl Display {
5    struct ClosureDisplay<F: Fn(&mut Formatter<'_>) -> Result>(F);
6
7    impl<F: Fn(&mut Formatter<'_>) -> Result> Display for ClosureDisplay<F> {
8        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
9            self.0(f)
10        }
11    }
12
13    ClosureDisplay(f)
14}
15
16macro_rules! write_joined_non_empty_list {
17    ($f:expr,$template:tt,$list:expr,$sep:expr) => {{
18        let mut x = $list.into_iter().peekable();
19        if x.peek().is_some() {
20            write!($f, $template, x.format($sep))
21        } else {
22            Ok(())
23        }
24    }};
25}
26
27/// Processes a name given by an [`Interner`][chalk_ir::interner::Interner] debug
28/// method into something usable by the `display` module.
29///
30/// This is specifically useful when implementing
31/// [`RustIrDatabase`][crate::RustIrDatabase] `name_*` methods.
32pub fn sanitize_debug_name(func: impl Fn(&mut Formatter<'_>) -> Option<Result>) -> String {
33    use std::fmt::Write;
34
35    // First, write the debug method contents to a String.
36    let mut debug_out = String::new();
37    // ignore if the result is `None`, as we can just as easily tell by looking
38    // to see if anything was written to `debug_out`.
39    write!(
40        debug_out,
41        "{}",
42        as_display(|fmt| { func(fmt).unwrap_or(Ok(())) })
43    )
44    .expect("expected writing to a String to succeed");
45    if debug_out.is_empty() {
46        return "Unknown".to_owned();
47    }
48
49    // now the actual sanitization
50    debug_out.replace(|c: char| !c.is_ascii_alphanumeric(), "_")
51}