factor out crate

This commit is contained in:
Jana Dönszelmann 2026-04-02 08:31:58 +02:00
parent bb8fa818d2
commit af09bcd403
No known key found for this signature in database
11 changed files with 43 additions and 22 deletions

View file

@ -1,975 +0,0 @@
use super::ast::*;
use std::borrow::Cow;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Kind {
/// Parentheses e.g.
///
/// Stores the delimiter depth, for e.g. rainbow delimiters.
Delimiter(usize),
/// Separators like `=`, ':' and ','
Separator,
/// Numbers
Number,
/// Known literals, like `true`, `false`, `None`, `Ok`, `Err`
Literal,
/// Strings
String,
/// Paths
Path,
/// Spaces (returns original number of spaces)
Space(usize),
/// Constructor: the prefix of a delimited block.
/// i.e. `Some` in `Some(3)`
Constructor,
/// String prefix, suffix, hashtags, etc
StringSurroundings,
/// Any other text (the default)
Text,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Span<'a> {
pub text: Cow<'a, str>,
pub kind: Kind,
}
pub struct Config {
pub collapse_space: bool,
}
pub struct Context<'a> {
config: Config,
res: Vec<Span<'a>>,
depth: usize,
}
impl<'a> Context<'a> {
pub fn push(&mut self, text: impl Into<Cow<'a, str>>, kind: Kind) {
self.res.push(Span {
text: text.into(),
kind,
})
}
}
pub trait IntoSpans<'a>: private::IntoSpansImpl<'a> {}
pub fn into_spans<'a>(ast: impl IntoSpans<'a>, config: Config) -> Vec<Span<'a>> {
let mut cx = Context {
config,
res: Vec::new(),
depth: 0,
};
ast.into_spans(&mut cx);
cx.res
}
mod private {
use super::*;
pub trait IntoSpansImpl<'a> {
fn into_spans(self, cx: &mut Context<'a>);
}
impl<'a, T> IntoSpans<'a> for T where T: IntoSpansImpl<'a> {}
impl<'a> IntoSpansImpl<'a> for Separator {
fn into_spans(self, cx: &mut Context<'a>) {
match self {
Separator::Eq => cx.push("=", Kind::Separator),
Separator::Colon => cx.push(":", Kind::Separator),
Separator::DoubleColon => cx.push("::", Kind::Separator),
}
}
}
impl<'a> IntoSpansImpl<'a> for QuoteType {
fn into_spans(self, cx: &mut Context<'a>) {
match self {
QuoteType::Single => cx.push("'", Kind::Separator),
QuoteType::Double => cx.push("\"", Kind::Separator),
QuoteType::Backtick => cx.push("`", Kind::Separator),
}
}
}
impl<'a> IntoSpansImpl<'a> for AnyString<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
let Self {
prefix,
ty,
contents,
num_hashtags,
suffix,
} = self;
cx.push(prefix, Kind::StringSurroundings);
for _ in 0..num_hashtags {
cx.push("#", Kind::StringSurroundings)
}
ty.into_spans(cx);
cx.push(contents, Kind::String);
ty.into_spans(cx);
for _ in 0..num_hashtags {
cx.push("#", Kind::StringSurroundings)
}
cx.push(suffix, Kind::StringSurroundings);
}
}
impl<'a> IntoSpansImpl<'a> for Path<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
cx.push(self.to_string(), Kind::Path)
}
}
impl<'a> IntoSpansImpl<'a> for Number<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
cx.push(self.0, Kind::Number)
}
}
impl<'a> IntoSpansImpl<'a> for Atom<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
match self {
Atom::Text(text) => cx.push(text, Kind::Text),
}
}
}
impl<'a> IntoSpansImpl<'a> for Space<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
match self.0.len() {
0 => {}
1 => cx.push(self.0, Kind::Space(1)),
n if cx.config.collapse_space => cx.push(" ", Kind::Space(n)),
n => cx.push(self.0, Kind::Space(n)),
}
}
}
impl<'a> IntoSpansImpl<'a> for Token<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
match self {
Token::True => cx.push("true", Kind::Literal),
Token::False => cx.push("false", Kind::Literal),
Token::None => cx.push("None", Kind::Literal),
Token::Path(path) => path.into_spans(cx),
Token::String(string) => string.into_spans(cx),
Token::Number(number) => number.into_spans(cx),
Token::Separated {
before,
space_before,
separator,
after,
} => {
before.into_spans(cx);
space_before.into_spans(cx);
separator.into_spans(cx);
after.into_spans(cx);
}
Token::Delimited(delimited) => {
delimited.into_spans(cx);
}
Token::Atom(atom) => {
atom.into_spans(cx);
}
}
}
}
impl<'a> IntoSpansImpl<'a> for Segment<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
let Self {
leading_space,
token,
} = self;
leading_space.into_spans(cx);
token.into_spans(cx);
}
}
impl<'a> IntoSpansImpl<'a> for Segments<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
let Self {
segments,
trailing_space,
} = self;
for segment in segments {
segment.into_spans(cx);
}
trailing_space.into_spans(cx);
}
}
impl<'a> IntoSpansImpl<'a> for Delimited<'a> {
fn into_spans(self, cx: &mut Context<'a>) {
let Self {
prefix,
delimiter,
contents,
} = self;
match prefix {
Some(Atom::Text(text)) => cx.push(text, Kind::Constructor),
None => {}
}
match delimiter {
Delimiter::Paren => cx.push("(", Kind::Delimiter(cx.depth)),
Delimiter::Bracket => cx.push("[", Kind::Delimiter(cx.depth)),
Delimiter::Brace => cx.push("{", Kind::Delimiter(cx.depth)),
Delimiter::Angle => cx.push("<", Kind::Delimiter(cx.depth)),
}
cx.depth += 1;
contents.into_spans(cx);
cx.depth -= 1;
match delimiter {
Delimiter::Paren => cx.push(")", Kind::Delimiter(cx.depth)),
Delimiter::Bracket => cx.push("]", Kind::Delimiter(cx.depth)),
Delimiter::Brace => cx.push("}", Kind::Delimiter(cx.depth)),
Delimiter::Angle => cx.push(">", Kind::Delimiter(cx.depth)),
}
}
}
}
#[cfg(test)]
mod tests {
use insta::assert_debug_snapshot;
use super::Kind;
use crate::format_debug_output::{Config, into_spans, parse_input};
fn spans(input: &str) -> Vec<(String, Kind)> {
let res = parse_input(input).unwrap();
into_spans(
res,
Config {
collapse_space: true,
},
)
.into_iter()
.map(|i| (i.text.into_owned(), i.kind))
.collect()
}
#[test]
fn spans_ex1() {
assert_debug_snapshot!(spans(
r#"def_id=DefId(0:3 ~ unsized_coercion[10fa]::Trait)"#
), @r#"
[
(
"def_id",
Text,
),
(
"=",
Separator,
),
(
"DefId",
Constructor,
),
(
"(",
Delimiter(
0,
),
),
(
"0",
Number,
),
(
":",
Separator,
),
(
"3",
Number,
),
(
" ",
Space(
1,
),
),
(
"~",
Text,
),
(
" ",
Space(
1,
),
),
(
"unsized_coercion",
Constructor,
),
(
"[",
Delimiter(
1,
),
),
(
"10fa",
Text,
),
(
"]",
Delimiter(
1,
),
),
(
"::",
Separator,
),
(
"Trait",
Text,
),
(
")",
Delimiter(
0,
),
),
]
"#)
}
#[test]
fn spans_ex2() {
assert_debug_snapshot!(spans(
r#"data=TypeNs("MetaSized") visible_parent=DefId(2:3984 ~ core[bcc4]::marker) actual_parent=Some(DefId(2:3984 ~ core[bcc4]::marker))"#
), @r#"
[
(
"data",
Text,
),
(
"=",
Separator,
),
(
"TypeNs",
Constructor,
),
(
"(",
Delimiter(
0,
),
),
(
"",
StringSurroundings,
),
(
"\"",
Separator,
),
(
"MetaSized",
String,
),
(
"\"",
Separator,
),
(
"",
StringSurroundings,
),
(
")",
Delimiter(
0,
),
),
(
" ",
Space(
1,
),
),
(
"visible_parent",
Text,
),
(
"=",
Separator,
),
(
"DefId",
Constructor,
),
(
"(",
Delimiter(
0,
),
),
(
"2",
Number,
),
(
":",
Separator,
),
(
"3984",
Number,
),
(
" ",
Space(
1,
),
),
(
"~",
Text,
),
(
" ",
Space(
1,
),
),
(
"core",
Constructor,
),
(
"[",
Delimiter(
1,
),
),
(
"bcc4",
Text,
),
(
"]",
Delimiter(
1,
),
),
(
"::",
Separator,
),
(
"marker",
Text,
),
(
")",
Delimiter(
0,
),
),
(
" ",
Space(
1,
),
),
(
"actual_parent",
Text,
),
(
"=",
Separator,
),
(
"Some",
Constructor,
),
(
"(",
Delimiter(
0,
),
),
(
"DefId",
Constructor,
),
(
"(",
Delimiter(
1,
),
),
(
"2",
Number,
),
(
":",
Separator,
),
(
"3984",
Number,
),
(
" ",
Space(
1,
),
),
(
"~",
Text,
),
(
" ",
Space(
1,
),
),
(
"core",
Constructor,
),
(
"[",
Delimiter(
2,
),
),
(
"bcc4",
Text,
),
(
"]",
Delimiter(
2,
),
),
(
"::",
Separator,
),
(
"marker",
Text,
),
(
")",
Delimiter(
1,
),
),
(
")",
Delimiter(
0,
),
),
]
"#)
}
#[test]
fn spans_ex3() {
assert_debug_snapshot!(spans(
r#"insert(DefId(0:4 ~ unsized_coercion[10fa]::{impl#0})): inserting TraitRef <u32 as Trait> into specialization graph"#
), @r#"
[
(
"insert",
Constructor,
),
(
"(",
Delimiter(
0,
),
),
(
"DefId",
Constructor,
),
(
"(",
Delimiter(
1,
),
),
(
"0",
Number,
),
(
":",
Separator,
),
(
"4",
Number,
),
(
" ",
Space(
1,
),
),
(
"~",
Text,
),
(
" ",
Space(
1,
),
),
(
"unsized_coercion",
Constructor,
),
(
"[",
Delimiter(
2,
),
),
(
"10fa",
Text,
),
(
"]",
Delimiter(
2,
),
),
(
"::",
Separator,
),
(
"{",
Delimiter(
2,
),
),
(
"impl#0",
Text,
),
(
"}",
Delimiter(
2,
),
),
(
")",
Delimiter(
1,
),
),
(
")",
Delimiter(
0,
),
),
(
":",
Separator,
),
(
" ",
Space(
1,
),
),
(
"inserting",
Text,
),
(
" ",
Space(
1,
),
),
(
"TraitRef",
Text,
),
(
" ",
Space(
1,
),
),
(
"<u32",
Text,
),
(
" ",
Space(
1,
),
),
(
"as",
Text,
),
(
" ",
Space(
1,
),
),
(
"Trait>",
Text,
),
(
" ",
Space(
1,
),
),
(
"into",
Text,
),
(
" ",
Space(
1,
),
),
(
"specialization",
Text,
),
(
" ",
Space(
1,
),
),
(
"graph",
Text,
),
]
"#)
}
#[test]
fn spans_ex4() {
assert_debug_snapshot!(spans(
r#"inspecting def_id=DefId(3:662 ~ alloc[ef11]::boxed::Box) span=tests/ui/impl-trait/unsized_coercion.rs:12:15: 12:30 (#0)"#
), @r##"
[
(
"inspecting",
Text,
),
(
" ",
Space(
1,
),
),
(
"def_id",
Text,
),
(
"=",
Separator,
),
(
"DefId",
Constructor,
),
(
"(",
Delimiter(
0,
),
),
(
"3",
Number,
),
(
":",
Separator,
),
(
"662",
Number,
),
(
" ",
Space(
1,
),
),
(
"~",
Text,
),
(
" ",
Space(
1,
),
),
(
"alloc",
Constructor,
),
(
"[",
Delimiter(
1,
),
),
(
"ef11",
Text,
),
(
"]",
Delimiter(
1,
),
),
(
"::",
Separator,
),
(
"boxed",
Text,
),
(
"::",
Separator,
),
(
"Box",
Text,
),
(
")",
Delimiter(
0,
),
),
(
" ",
Space(
1,
),
),
(
"span",
Text,
),
(
"=",
Separator,
),
(
"tests/ui/impl-trait/unsized_coercion.rs",
Path,
),
(
":",
Separator,
),
(
"12",
Number,
),
(
":",
Separator,
),
(
"15",
Number,
),
(
":",
Separator,
),
(
" ",
Space(
1,
),
),
(
"12",
Number,
),
(
":",
Separator,
),
(
"30",
Number,
),
(
" ",
Space(
1,
),
),
(
"(",
Delimiter(
0,
),
),
(
"#0",
Text,
),
(
")",
Delimiter(
0,
),
),
]
"##)
}
}