You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: lists.rs
    path of file: ./repos/rustfmt/src
    
    the code of the file until where you have to start completion: //! Format list-like expressions and items.

use std::cmp;
use std::iter::Peekable;

use rustc_span::BytePos;

use crate::comment::{find_comment_end, rewrite_comment, FindUncommented};
use crate::config::lists::*;
use crate::config::{Config, IndentStyle};
use crate::rewrite::RewriteContext;
use crate::shape::{Indent, Shape};
use crate::utils::{
    count_newlines, first_line_width, last_line_width, mk_sp, starts_with_newline,
    unicode_str_width,
};
use crate::visitor::SnippetProvider;

pub(crate) struct ListFormatting<'a> {
    tactic: DefinitiveListTactic,
    separator: &'a str,
    trailing_separator: SeparatorTactic,
    separator_place: SeparatorPlace,
    shape: Shape,
    // Non-expressions, e.g., items, will have a new line at the end of the list.
    // Important for comment styles.
    ends_with_newline: bool,
    // Remove newlines between list elements for expressions.
    preserve_newline: bool,
    // Nested import lists get some special handling for the "Mixed" list type
    nested: bool,
    // Whether comments should be visually aligned.
    align_comments: bool,
    config: &'a Config,
}

impl<'a> ListFormatting<'a> {
    pub(crate) fn new(shape: Shape, config: &'a Config) -> Self {
        ListFormatting {
            tactic: DefinitiveListTactic::Vertical,
            separator: ",",
            trailing_separator: SeparatorTactic::Never,
            separator_place: SeparatorPlace::Back,
            shape,
            ends_with_newline: true,
        
    
    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next().map(|item| {
            // Pre-comment
            let pre_snippet = self
                .snippet_provider
                .span_to_snippet(mk_sp(self.prev_span_end, (self.get_lo)(&item)))
                .unwrap_or("");
            let (pre_comment, pre_comment_style) = extract_pre_comment(pre_snippet);

            // Post-comment
            let next_start = match self.inner.peek() {
                Some(next_item) => (self.get_lo)(next_item),
                None => self.next_span_start,
            };
            let post_snippet = self
                .snippet_provider
                .span_to_snippet(mk_sp((self.get_hi)(&item), next_start))
                .unwrap_or("");
            let is_last = self.inner.peek().is_none();
            let comment_end =
                get_comment_end(post_snippet, self.separator, self.terminator, is_last);
            let new_lines = has_extra_newline(post_snippet, comment_end);
            let post_comment =
                extract_post_comment(post_snippet, comment_end, self.separator, is_last);

            self.prev_span_end = (self.get_hi)(&item) + BytePos(comment_end as u32);

            ListItem {
                pre_comment,
                pre_comment_style,
                item: if self.inner.peek().is_none() && self.leave_last {
                    None
                } else {
                    (self.get_item_string)(&item)
                },
                post_comment,
                new_lines,
            }
        })
    }