use crate::comment::combine_strs_with_missing_comments;
use crate::config::lists::*;
use crate::config::ImportGranularity;
-use crate::config::{Edition, IndentStyle};
+use crate::config::{Edition, IndentStyle, Version};
use crate::lists::{
definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
};
// FIXME we do a lot of allocation to make our own representation.
#[derive(Clone, Eq, Hash, PartialEq)]
-pub(crate) enum UseSegment {
+pub(crate) enum UseSegmentKind {
Ident(String, Option<String>),
Slf(Option<String>),
Super(Option<String>),
List(Vec<UseTree>),
}
+#[derive(Clone, Eq, PartialEq)]
+pub(crate) struct UseSegment {
+ pub(crate) kind: UseSegmentKind,
+ pub(crate) version: Version,
+}
+
#[derive(Clone)]
pub(crate) struct UseTree {
pub(crate) path: Vec<UseSegment>,
impl UseSegment {
// Clone a version of self with any top-level alias removed.
fn remove_alias(&self) -> UseSegment {
- match *self {
- UseSegment::Ident(ref s, _) => UseSegment::Ident(s.clone(), None),
- UseSegment::Slf(_) => UseSegment::Slf(None),
- UseSegment::Super(_) => UseSegment::Super(None),
- UseSegment::Crate(_) => UseSegment::Crate(None),
- _ => self.clone(),
+ let kind = match self.kind {
+ UseSegmentKind::Ident(ref s, _) => UseSegmentKind::Ident(s.clone(), None),
+ UseSegmentKind::Slf(_) => UseSegmentKind::Slf(None),
+ UseSegmentKind::Super(_) => UseSegmentKind::Super(None),
+ UseSegmentKind::Crate(_) => UseSegmentKind::Crate(None),
+ _ => return self.clone(),
+ };
+ UseSegment {
+ kind,
+ version: self.version,
}
}
// Check if self == other with their aliases removed.
fn equal_except_alias(&self, other: &Self) -> bool {
- match (self, other) {
- (UseSegment::Ident(ref s1, _), UseSegment::Ident(ref s2, _)) => s1 == s2,
- (UseSegment::Slf(_), UseSegment::Slf(_))
- | (UseSegment::Super(_), UseSegment::Super(_))
- | (UseSegment::Crate(_), UseSegment::Crate(_))
- | (UseSegment::Glob, UseSegment::Glob) => true,
- (UseSegment::List(ref list1), UseSegment::List(ref list2)) => list1 == list2,
+ match (&self.kind, &other.kind) {
+ (UseSegmentKind::Ident(ref s1, _), UseSegmentKind::Ident(ref s2, _)) => s1 == s2,
+ (UseSegmentKind::Slf(_), UseSegmentKind::Slf(_))
+ | (UseSegmentKind::Super(_), UseSegmentKind::Super(_))
+ | (UseSegmentKind::Crate(_), UseSegmentKind::Crate(_))
+ | (UseSegmentKind::Glob, UseSegmentKind::Glob) => true,
+ (UseSegmentKind::List(ref list1), UseSegmentKind::List(ref list2)) => list1 == list2,
_ => false,
}
}
fn get_alias(&self) -> Option<&str> {
- match self {
- UseSegment::Ident(_, a)
- | UseSegment::Slf(a)
- | UseSegment::Super(a)
- | UseSegment::Crate(a) => a.as_deref(),
+ match &self.kind {
+ UseSegmentKind::Ident(_, a)
+ | UseSegmentKind::Slf(a)
+ | UseSegmentKind::Super(a)
+ | UseSegmentKind::Crate(a) => a.as_deref(),
_ => None,
}
}
if name.is_empty() || name == "{{root}}" {
return None;
}
- Some(match name {
- "self" => UseSegment::Slf(None),
- "super" => UseSegment::Super(None),
- "crate" => UseSegment::Crate(None),
+ let kind = match name {
+ "self" => UseSegmentKind::Slf(None),
+ "super" => UseSegmentKind::Super(None),
+ "crate" => UseSegmentKind::Crate(None),
_ => {
let mod_sep = if modsep { "::" } else { "" };
- UseSegment::Ident(format!("{}{}", mod_sep, name), None)
+ UseSegmentKind::Ident(format!("{}{}", mod_sep, name), None)
}
+ };
+
+ Some(UseSegment {
+ kind,
+ version: context.config.version(),
})
}
fn contains_comment(&self) -> bool {
- if let UseSegment::List(list) = self {
+ if let UseSegmentKind::List(list) = &self.kind {
list.iter().any(|subtree| subtree.contains_comment())
} else {
false
impl fmt::Debug for UseSegment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self, f)
+ fmt::Display::fmt(&self.kind, f)
}
}
impl fmt::Display for UseSegment {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&self.kind, f)
+ }
+}
+
+impl Hash for UseSegment {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.kind.hash(state);
+ }
+}
+
+impl fmt::Debug for UseSegmentKind {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl fmt::Display for UseSegmentKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
- UseSegment::Glob => write!(f, "*"),
- UseSegment::Ident(ref s, Some(ref alias)) => write!(f, "{} as {}", s, alias),
- UseSegment::Ident(ref s, None) => write!(f, "{}", s),
- UseSegment::Slf(..) => write!(f, "self"),
- UseSegment::Super(..) => write!(f, "super"),
- UseSegment::Crate(..) => write!(f, "crate"),
- UseSegment::List(ref list) => {
+ UseSegmentKind::Glob => write!(f, "*"),
+ UseSegmentKind::Ident(ref s, Some(ref alias)) => write!(f, "{} as {}", s, alias),
+ UseSegmentKind::Ident(ref s, None) => write!(f, "{}", s),
+ UseSegmentKind::Slf(..) => write!(f, "self"),
+ UseSegmentKind::Super(..) => write!(f, "super"),
+ UseSegmentKind::Crate(..) => write!(f, "crate"),
+ UseSegmentKind::List(ref list) => {
write!(f, "{{")?;
for (i, item) in list.iter().enumerate() {
if i != 0 {
}
}
+ let version = context.config.version();
+
match a.kind {
UseTreeKind::Glob => {
// in case of a global path and the glob starts at the root, e.g., "::*"
if a.prefix.segments.len() == 1 && leading_modsep {
- result.path.push(UseSegment::Ident("".to_owned(), None));
+ let kind = UseSegmentKind::Ident("".to_owned(), None);
+ result.path.push(UseSegment { kind, version });
}
- result.path.push(UseSegment::Glob);
+ result.path.push(UseSegment {
+ kind: UseSegmentKind::Glob,
+ version,
+ });
}
UseTreeKind::Nested(ref list) => {
// Extract comments between nested use items.
// in case of a global path and the nested list starts at the root,
// e.g., "::{foo, bar}"
if a.prefix.segments.len() == 1 && leading_modsep {
- result.path.push(UseSegment::Ident("".to_owned(), None));
+ let kind = UseSegmentKind::Ident("".to_owned(), None);
+ result.path.push(UseSegment { kind, version });
}
- result.path.push(UseSegment::List(
+ let kind = UseSegmentKind::List(
list.iter()
.zip(items)
.map(|(t, list_item)| {
Self::from_ast(context, &t.0, Some(list_item), None, None, None)
})
.collect(),
- ));
+ );
+ result.path.push(UseSegment { kind, version });
}
UseTreeKind::Simple(ref rename, ..) => {
// If the path has leading double colons and is composed of only 2 segments, then we
Some(rewrite_ident(context, ident).to_owned())
}
});
- let segment = match name.as_ref() {
- "self" => UseSegment::Slf(alias),
- "super" => UseSegment::Super(alias),
- "crate" => UseSegment::Crate(alias),
- _ => UseSegment::Ident(name, alias),
+ let kind = match name.as_ref() {
+ "self" => UseSegmentKind::Slf(alias),
+ "super" => UseSegmentKind::Super(alias),
+ "crate" => UseSegmentKind::Crate(alias),
+ _ => UseSegmentKind::Ident(name, alias),
};
+ let segment = UseSegment { kind, version };
+
// `name` is already in result.
result.path.pop();
result.path.push(segment);
let mut aliased_self = false;
// Remove foo::{} or self without attributes.
- match last {
+ match last.kind {
_ if self.attrs.is_some() => (),
- UseSegment::List(ref list) if list.is_empty() => {
+ UseSegmentKind::List(ref list) if list.is_empty() => {
self.path = vec![];
return self;
}
- UseSegment::Slf(None) if self.path.is_empty() && self.visibility.is_some() => {
+ UseSegmentKind::Slf(None) if self.path.is_empty() && self.visibility.is_some() => {
self.path = vec![];
return self;
}
}
// Normalise foo::self -> foo.
- if let UseSegment::Slf(None) = last {
+ if let UseSegmentKind::Slf(None) = last.kind {
if !self.path.is_empty() {
return self;
}
}
// Normalise foo::self as bar -> foo as bar.
- if let UseSegment::Slf(_) = last {
- if let Some(UseSegment::Ident(_, None)) = self.path.last() {
+ if let UseSegmentKind::Slf(_) = last.kind {
+ if let Some(UseSegment {
+ kind: UseSegmentKind::Ident(_, None),
+ ..
+ }) = self.path.last()
+ {
aliased_self = true;
}
}
let mut done = false;
if aliased_self {
match self.path.last_mut() {
- Some(UseSegment::Ident(_, ref mut old_rename)) => {
+ Some(UseSegment {
+ kind: UseSegmentKind::Ident(_, ref mut old_rename),
+ ..
+ }) => {
assert!(old_rename.is_none());
- if let UseSegment::Slf(Some(rename)) = last.clone() {
+ if let UseSegmentKind::Slf(Some(rename)) = last.clone().kind {
*old_rename = Some(rename);
done = true;
}
}
// Normalise foo::{bar} -> foo::bar
- if let UseSegment::List(ref list) = last {
+ if let UseSegmentKind::List(ref list) = last.kind {
if list.len() == 1 && list[0].to_string() != "self" {
normalize_sole_list = true;
}
}
if normalize_sole_list {
- match last {
- UseSegment::List(list) => {
+ match last.kind {
+ UseSegmentKind::List(list) => {
for seg in &list[0].path {
self.path.push(seg.clone());
}
}
// Recursively normalize elements of a list use (including sorting the list).
- if let UseSegment::List(list) = last {
+ if let UseSegmentKind::List(list) = last.kind {
let mut list = list.into_iter().map(UseTree::normalize).collect::<Vec<_>>();
list.sort();
- last = UseSegment::List(list);
+ last = UseSegment {
+ kind: UseSegmentKind::List(list),
+ version: last.version,
+ };
}
self.path.push(last);
if self.path.is_empty() || self.contains_comment() {
return vec![self];
}
- match self.path.clone().last().unwrap() {
- UseSegment::List(list) => {
+ match &self.path.clone().last().unwrap().kind {
+ UseSegmentKind::List(list) => {
if list.len() == 1 && list[0].path.len() == 1 {
- if let UseSegment::Slf(..) = list[0].path[0] {
+ if let UseSegmentKind::Slf(..) = list[0].path[0].kind {
return vec![self];
};
}
/// If this tree ends in `::self`, rewrite it to `::{self}`.
fn nest_trailing_self(mut self) -> UseTree {
- if let Some(UseSegment::Slf(..)) = self.path.last() {
+ if let Some(UseSegment {
+ kind: UseSegmentKind::Slf(..),
+ ..
+ }) = self.path.last()
+ {
let self_segment = self.path.pop().unwrap();
- self.path.push(UseSegment::List(vec![UseTree::from_path(
- vec![self_segment],
- DUMMY_SP,
- )]));
+ let version = self_segment.version;
+ let kind = UseSegmentKind::List(vec![UseTree::from_path(vec![self_segment], DUMMY_SP)]);
+ self.path.push(UseSegment { kind, version });
}
self
}
return None;
}
if a.len() != len && b.len() != len {
- if let UseSegment::List(ref list) = a[len] {
+ let version = a[len].version;
+ if let UseSegmentKind::List(ref list) = a[len].kind {
let mut list = list.clone();
merge_use_trees_inner(
&mut list,
merge_by,
);
let mut new_path = b[..len].to_vec();
- new_path.push(UseSegment::List(list));
+ let kind = UseSegmentKind::List(list);
+ new_path.push(UseSegment { kind, version });
return Some(new_path);
}
} else if len == 1 {
} else {
(&b[0], &a[1..])
};
+ let kind = UseSegmentKind::Slf(common.get_alias().map(ToString::to_string));
+ let version = a[0].version;
let mut list = vec![UseTree::from_path(
- vec![UseSegment::Slf(common.get_alias().map(ToString::to_string))],
+ vec![UseSegment { kind, version }],
DUMMY_SP,
)];
match rest {
- [UseSegment::List(rest_list)] => list.extend(rest_list.clone()),
+ [
+ UseSegment {
+ kind: UseSegmentKind::List(rest_list),
+ ..
+ },
+ ] => list.extend(rest_list.clone()),
_ => list.push(UseTree::from_path(rest.to_vec(), DUMMY_SP)),
}
- return Some(vec![b[0].clone(), UseSegment::List(list)]);
+ return Some(vec![
+ b[0].clone(),
+ UseSegment {
+ kind: UseSegmentKind::List(list),
+ version,
+ },
+ ]);
} else {
len -= 1;
}
];
list.sort();
let mut new_path = b[..len].to_vec();
- new_path.push(UseSegment::List(list));
+ let kind = UseSegmentKind::List(list);
+ let version = a[0].version;
+ new_path.push(UseSegment { kind, version });
Some(new_path)
}
}
impl Ord for UseSegment {
fn cmp(&self, other: &UseSegment) -> Ordering {
- use self::UseSegment::*;
+ use self::UseSegmentKind::*;
fn is_upper_snake_case(s: &str) -> bool {
s.chars()
.all(|c| c.is_uppercase() || c == '_' || c.is_numeric())
}
- match (self, other) {
- (&Slf(ref a), &Slf(ref b))
- | (&Super(ref a), &Super(ref b))
- | (&Crate(ref a), &Crate(ref b)) => match (a, b) {
+ match (&self.kind, &other.kind) {
+ (Slf(ref a), Slf(ref b))
+ | (Super(ref a), Super(ref b))
+ | (Crate(ref a), Crate(ref b)) => match (a, b) {
(Some(sa), Some(sb)) => {
sa.trim_start_matches("r#").cmp(sb.trim_start_matches("r#"))
}
(_, _) => a.cmp(b),
},
- (&Glob, &Glob) => Ordering::Equal,
- (&Ident(ref pia, ref aa), &Ident(ref pib, ref ab)) => {
+ (Glob, Glob) => Ordering::Equal,
+ (Ident(ref pia, ref aa), Ident(ref pib, ref ab)) => {
let ia = pia.trim_start_matches("r#");
let ib = pib.trim_start_matches("r#");
// snake_case < CamelCase < UPPER_SNAKE_CASE
(None, None) => Ordering::Equal,
}
}
- (&List(ref a), &List(ref b)) => {
+ (List(ref a), List(ref b)) => {
for (a, b) in a.iter().zip(b.iter()) {
let ord = a.cmp(b);
if ord != Ordering::Equal {
a.len().cmp(&b.len())
}
- (&Slf(_), _) => Ordering::Less,
- (_, &Slf(_)) => Ordering::Greater,
- (&Super(_), _) => Ordering::Less,
- (_, &Super(_)) => Ordering::Greater,
- (&Crate(_), _) => Ordering::Less,
- (_, &Crate(_)) => Ordering::Greater,
- (&Ident(..), _) => Ordering::Less,
- (_, &Ident(..)) => Ordering::Greater,
- (&Glob, _) => Ordering::Less,
- (_, &Glob) => Ordering::Greater,
+ (Slf(_), _) => Ordering::Less,
+ (_, Slf(_)) => Ordering::Greater,
+ (Super(_), _) => Ordering::Less,
+ (_, Super(_)) => Ordering::Greater,
+ (Crate(_), _) => Ordering::Less,
+ (_, Crate(_)) => Ordering::Greater,
+ (Ident(..), _) => Ordering::Less,
+ (_, Ident(..)) => Ordering::Greater,
+ (Glob, _) => Ordering::Less,
+ (_, Glob) => Ordering::Greater,
}
}
}
}
let has_nested_list = use_tree_list.iter().any(|use_segment| {
use_segment.path.last().map_or(false, |last_segment| {
- matches!(last_segment, UseSegment::List(..))
+ matches!(last_segment.kind, UseSegmentKind::List(..))
})
});
impl Rewrite for UseSegment {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
- Some(match self {
- UseSegment::Ident(ref ident, Some(ref rename)) => format!("{} as {}", ident, rename),
- UseSegment::Ident(ref ident, None) => ident.clone(),
- UseSegment::Slf(Some(ref rename)) => format!("self as {}", rename),
- UseSegment::Slf(None) => "self".to_owned(),
- UseSegment::Super(Some(ref rename)) => format!("super as {}", rename),
- UseSegment::Super(None) => "super".to_owned(),
- UseSegment::Crate(Some(ref rename)) => format!("crate as {}", rename),
- UseSegment::Crate(None) => "crate".to_owned(),
- UseSegment::Glob => "*".to_owned(),
- UseSegment::List(ref use_tree_list) => rewrite_nested_use_tree(
+ Some(match self.kind {
+ UseSegmentKind::Ident(ref ident, Some(ref rename)) => {
+ format!("{} as {}", ident, rename)
+ }
+ UseSegmentKind::Ident(ref ident, None) => ident.clone(),
+ UseSegmentKind::Slf(Some(ref rename)) => format!("self as {}", rename),
+ UseSegmentKind::Slf(None) => "self".to_owned(),
+ UseSegmentKind::Super(Some(ref rename)) => format!("super as {}", rename),
+ UseSegmentKind::Super(None) => "super".to_owned(),
+ UseSegmentKind::Crate(Some(ref rename)) => format!("crate as {}", rename),
+ UseSegmentKind::Crate(None) => "crate".to_owned(),
+ UseSegmentKind::Glob => "*".to_owned(),
+ UseSegmentKind::List(ref use_tree_list) => rewrite_nested_use_tree(
context,
use_tree_list,
// 1 = "{" and "}"
struct Parser<'a> {
input: Peekable<Chars<'a>>,
+ version: Version,
}
impl<'a> Parser<'a> {
}
fn push_segment(
+ &self,
result: &mut Vec<UseSegment>,
buf: &mut String,
alias_buf: &mut Option<String>,
) {
+ let version = self.version;
if !buf.is_empty() {
let mut alias = None;
swap(alias_buf, &mut alias);
match buf.as_ref() {
"self" => {
- result.push(UseSegment::Slf(alias));
+ let kind = UseSegmentKind::Slf(alias);
+ result.push(UseSegment { kind, version });
*buf = String::new();
*alias_buf = None;
}
"super" => {
- result.push(UseSegment::Super(alias));
+ let kind = UseSegmentKind::Super(alias);
+ result.push(UseSegment { kind, version });
*buf = String::new();
*alias_buf = None;
}
"crate" => {
- result.push(UseSegment::Crate(alias));
+ let kind = UseSegmentKind::Crate(alias);
+ result.push(UseSegment { kind, version });
*buf = String::new();
*alias_buf = None;
}
_ => {
let mut name = String::new();
swap(buf, &mut name);
- result.push(UseSegment::Ident(name, alias));
+ let kind = UseSegmentKind::Ident(name, alias);
+ result.push(UseSegment { kind, version });
}
}
}
'{' => {
assert!(buf.is_empty());
self.bump();
- result.push(UseSegment::List(self.parse_list()));
+ let kind = UseSegmentKind::List(self.parse_list());
+ result.push(UseSegment {
+ kind,
+ version: self.version,
+ });
self.eat('}');
}
'*' => {
assert!(buf.is_empty());
self.bump();
- result.push(UseSegment::Glob);
+ let kind = UseSegmentKind::Glob;
+ result.push(UseSegment {
+ kind,
+ version: self.version,
+ });
}
':' => {
self.bump();
self.eat(':');
- Self::push_segment(&mut result, &mut buf, &mut alias_buf);
+ self.push_segment(&mut result, &mut buf, &mut alias_buf);
}
'}' | ',' => {
- Self::push_segment(&mut result, &mut buf, &mut alias_buf);
+ self.push_segment(&mut result, &mut buf, &mut alias_buf);
return UseTree {
path: result,
span: DUMMY_SP,
}
}
}
- Self::push_segment(&mut result, &mut buf, &mut alias_buf);
+ self.push_segment(&mut result, &mut buf, &mut alias_buf);
UseTree {
path: result,
span: DUMMY_SP,
let mut parser = Parser {
input: s.chars().peekable(),
+ version: Version::One,
};
parser.parse_in_list()
}