Przeglądaj źródła

Better referencing

This commit makes changes to the way variables are referenced:

• Make types Copy when possible
• Make methods take `self` instead of `&self` where possible (trivially_copy_pass_by_ref)
• Remove unnecessary borrowing (needless_ref)
• Remove unnecessary cloning (clone_on_copy)
• Remove `ref` from match arms where possible (new Rust match ergonomics)
Benjamin Sago 5 lat temu
rodzic
commit
f0c139ca68

+ 10 - 10
src/fs/dir_action.rs

@@ -39,19 +39,19 @@ pub enum DirAction {
 impl DirAction {
 
     /// Gets the recurse options, if this dir action has any.
-    pub fn recurse_options(&self) -> Option<RecurseOptions> {
-        match *self {
-            Self::Recurse(o) => Some(o),
-            _                     => None,
+    pub fn recurse_options(self) -> Option<RecurseOptions> {
+        match self {
+            Self::Recurse(o)  => Some(o),
+            _                 => None,
         }
     }
 
     /// Whether to treat directories as regular files or not.
-    pub fn treat_dirs_as_files(&self) -> bool {
-        match *self {
+    pub fn treat_dirs_as_files(self) -> bool {
+        match self {
             Self::AsFile      => true,
             Self::Recurse(o)  => o.tree,
-            _                      => false,
+            _                 => false,
         }
     }
 }
@@ -73,10 +73,10 @@ pub struct RecurseOptions {
 impl RecurseOptions {
 
     /// Returns whether a directory of the given depth would be too deep.
-    pub fn is_too_deep(&self, depth: usize) -> bool {
+    pub fn is_too_deep(self, depth: usize) -> bool {
         match self.max_depth {
-            None    => false,
-            Some(d) => d <= depth
+            None     => false,
+            Some(d)  => d <= depth
         }
     }
 }

+ 15 - 4
src/fs/fields.rs

@@ -43,19 +43,20 @@ pub type uid_t = u32;
 /// regular file. (See the `filetype` module for those checks.)
 ///
 /// Its ordering is used when sorting by type.
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
+#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
 pub enum Type {
     Directory, File, Link, Pipe, Socket, CharDevice, BlockDevice, Special,
 }
 
 impl Type {
-    pub fn is_regular_file(&self) -> bool {
-        matches!(*self, Self::File)
+    pub fn is_regular_file(self) -> bool {
+        matches!(self, Self::File)
     }
 }
 
 
 /// The file’s Unix permission bitfield, with one entry per bit.
+#[derive(Copy, Clone)]
 pub struct Permissions {
     pub user_read:      bool,
     pub user_write:     bool,
@@ -77,6 +78,7 @@ pub struct Permissions {
 /// The three pieces of information that are displayed as a single column in
 /// the details view. These values are fused together to make the output a
 /// little more compressed.
+#[derive(Copy, Clone)]
 pub struct PermissionsPlus {
     pub file_type:   Type,
     pub permissions: Permissions,
@@ -85,6 +87,7 @@ pub struct PermissionsPlus {
 
 
 /// The permissions encoded as octal values
+#[derive(Copy, Clone)]
 pub struct OctalPermissions {
     pub permissions: Permissions,
 }
@@ -95,6 +98,7 @@ pub struct OctalPermissions {
 /// multiple directories. However, it’s rare (but occasionally useful!) for a
 /// regular file to have a link count greater than 1, so we highlight the
 /// block count specifically for this case.
+#[derive(Copy, Clone)]
 pub struct Links {
 
     /// The actual link count.
@@ -108,10 +112,12 @@ pub struct Links {
 /// A file’s inode. Every directory entry on a Unix filesystem has an inode,
 /// including directories and links, so this is applicable to everything exa
 /// can deal with.
+#[derive(Copy, Clone)]
 pub struct Inode(pub ino_t);
 
 
 /// The number of blocks that a file takes up on the filesystem, if any.
+#[derive(Copy, Clone)]
 pub enum Blocks {
 
     /// This file has the given number of blocks.
@@ -124,14 +130,17 @@ pub enum Blocks {
 
 /// The ID of the user that owns a file. This will only ever be a number;
 /// looking up the username is done in the `display` module.
+#[derive(Copy, Clone)]
 pub struct User(pub uid_t);
 
 /// The ID of the group that a file belongs to.
+#[derive(Copy, Clone)]
 pub struct Group(pub gid_t);
 
 
 /// A file’s size, in bytes. This is usually formatted by the `number_prefix`
 /// crate into something human-readable.
+#[derive(Copy, Clone)]
 pub enum Size {
 
     /// This file has a defined size.
@@ -162,6 +171,7 @@ pub enum Size {
 /// You can see what these device numbers mean:
 /// - http://www.lanana.org/docs/device-list/
 /// - http://www.lanana.org/docs/device-list/devices-2.6+.txt
+#[derive(Copy, Clone)]
 pub struct DeviceIDs {
     pub major: u8,
     pub minor: u8,
@@ -179,7 +189,7 @@ pub struct Time {
 /// A file’s status in a Git repository. Whether a file is in a repository or
 /// not is handled by the Git module, rather than having a “null” variant in
 /// this enum.
-#[derive(PartialEq)]
+#[derive(PartialEq, Copy, Clone)]
 pub enum GitStatus {
 
     /// This file hasn’t changed since the last commit.
@@ -211,6 +221,7 @@ pub enum GitStatus {
 /// A file’s complete Git status. It’s possible to make changes to a file, add
 /// it to the staging area, then make *more* changes, so we need to list each
 /// file’s status for both of these.
+#[derive(Copy, Clone)]
 pub struct Git {
     pub staged:   GitStatus,
     pub unstaged: GitStatus,

+ 4 - 7
src/fs/file.rs

@@ -417,9 +417,9 @@ impl<'dir> File<'dir> {
     ///
     /// This will always return `false` if the file has no extension.
     pub fn extension_is_one_of(&self, choices: &[&str]) -> bool {
-        match self.ext {
-            Some(ref ext)  => choices.contains(&&ext[..]),
-            None           => false,
+        match &self.ext {
+            Some(ext)  => choices.contains(&&ext[..]),
+            None       => false,
         }
     }
 
@@ -463,10 +463,7 @@ impl<'dir> FileTarget<'dir> {
     /// Whether this link doesn’t lead to a file, for whatever reason. This
     /// gets used to determine how to highlight the link in grid views.
     pub fn is_broken(&self) -> bool {
-        match *self {
-            FileTarget::Ok(_)                           => false,
-            FileTarget::Broken(_) | FileTarget::Err(_)  => true,
-        }
+        matches!(self, Self::Broken(_) | Self::Err(_))
     }
 }
 

+ 1 - 1
src/info/sources.rs

@@ -14,7 +14,7 @@ impl<'a> File<'a> {
     /// don't want to always blindly highlight `*.js` as compiled.
     /// (See also `FileExtensions#is_compiled`)
     pub fn get_source_files(&self) -> Vec<PathBuf> {
-        if let Some(ref ext) = self.ext {
+        if let Some(ext) = &self.ext {
             match &ext[..] {
                 "css"   => vec![self.path.with_extension("sass"),   self.path.with_extension("less")],  // SASS, Less
                 "js"    => vec![self.path.with_extension("coffee"), self.path.with_extension("ts")],  // CoffeeScript, TypeScript

+ 1 - 1
src/main.rs

@@ -228,7 +228,7 @@ impl<'args> Exa<'args> {
         if !files.is_empty() {
             let View { ref mode, ref colours, ref style } = self.options.view;
 
-            match *mode {
+            match mode {
                 Mode::Lines(ref opts) => {
                     let r = lines::Render { files, colours, style, opts };
                     r.render(&mut self.writer)

+ 2 - 2
src/options/filter.rs

@@ -37,8 +37,8 @@ impl SortField {
 
         // Get String because we can’t match an OsStr
         let word = match word.to_str() {
-            Some(ref w) => *w,
-            None => return Err(Misfire::BadArgument(&flags::SORT, word.into()))
+            Some(w)  => w,
+            None     => return Err(Misfire::BadArgument(&flags::SORT, word.into()))
         };
 
         let field = match word {

+ 1 - 1
src/options/help.rs

@@ -64,7 +64,7 @@ static OCTAL_HELP:    &str = r##"  --octal-permissions list each file's permissi
 /// All the information needed to display the help text, which depends
 /// on which features are enabled and whether the user only wants to
 /// see one section’s help.
-#[derive(PartialEq, Debug)]
+#[derive(PartialEq, Debug, Copy, Clone)]
 pub struct HelpString {
 
     /// Only show the help for the long section, not all the help.

+ 35 - 34
src/options/misfire.rs

@@ -55,10 +55,10 @@ impl Misfire {
 
     /// The OS return code this misfire should signify.
     pub fn is_error(&self) -> bool {
-        match *self {
-            Self::Help(_)    => false,
-            Self::Version(_) => false,
-            _                   => true,
+        match self {
+            Self::Help(_)     |
+            Self::Version(_)  => false,
+            _                 => true,
         }
     }
 }
@@ -72,10 +72,9 @@ impl From<glob::PatternError> for Misfire {
 impl fmt::Display for Misfire {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         use crate::options::parser::TakesValue;
-        use self::Misfire::*;
 
-        match *self {
-            BadArgument(ref arg, ref attempt) => {
+        match self {
+            Self::BadArgument(arg, attempt) => {
                 if let TakesValue::Necessary(Some(values)) = arg.takes_value {
                     write!(f, "Option {} has no {:?} setting ({})", arg, attempt, Choices(values))
                 }
@@ -83,33 +82,31 @@ impl fmt::Display for Misfire {
                     write!(f, "Option {} has no {:?} setting", arg, attempt)
                 }
             },
-            InvalidOptions(ref e)            => write!(f, "{}", e),
-            Unsupported(ref e)               => write!(f, "{}", e),
-            Help(ref text)                   => write!(f, "{}", text),
-            Version(ref version)             => write!(f, "{}", version),
-            Conflict(ref a, ref b)           => write!(f, "Option {} conflicts with option {}", a, b),
-            Duplicate(ref a, ref b)          => if a == b { write!(f, "Flag {} was given twice", a) }
-                                                     else { write!(f, "Flag {} conflicts with flag {}", a, b) },
-            Useless(ref a, false, ref b)     => write!(f, "Option {} is useless without option {}", a, b),
-            Useless(ref a, true, ref b)      => write!(f, "Option {} is useless given option {}", a, b),
-            Useless2(ref a, ref b1, ref b2)  => write!(f, "Option {} is useless without options {} or {}", a, b1, b2),
-            TreeAllAll                       => write!(f, "Option --tree is useless given --all --all"),
-            FailedParse(ref e)               => write!(f, "Failed to parse number: {}", e),
-            FailedGlobPattern(ref e)         => write!(f, "Failed to parse glob pattern: {}", e),
+            Self::InvalidOptions(e)         => write!(f, "{}", e),
+            Self::Unsupported(e)            => write!(f, "{}", e),
+            Self::Help(text)                => write!(f, "{}", text),
+            Self::Version(version)          => write!(f, "{}", version),
+            Self::Conflict(a, b)            => write!(f, "Option {} conflicts with option {}", a, b),
+            Self::Duplicate(a, b) if a == b => write!(f, "Flag {} was given twice", a),
+            Self::Duplicate(a, b)           => write!(f, "Flag {} conflicts with flag {}", a, b),
+            Self::Useless(a, false, b)      => write!(f, "Option {} is useless without option {}", a, b),
+            Self::Useless(a, true, b)       => write!(f, "Option {} is useless given option {}", a, b),
+            Self::Useless2(a, b1, b2)       => write!(f, "Option {} is useless without options {} or {}", a, b1, b2),
+            Self::TreeAllAll                => write!(f, "Option --tree is useless given --all --all"),
+            Self::FailedParse(ref e)        => write!(f, "Failed to parse number: {}", e),
+            Self::FailedGlobPattern(ref e)  => write!(f, "Failed to parse glob pattern: {}", e),
         }
     }
 }
 
 impl fmt::Display for ParseError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use self::ParseError::*;
-
-        match *self {
-            NeedsValue { ref flag, values: None }     => write!(f, "Flag {} needs a value", flag),
-            NeedsValue { ref flag, values: Some(cs) } => write!(f, "Flag {} needs a value ({})", flag, Choices(cs)),
-            ForbiddenValue { ref flag }               => write!(f, "Flag {} cannot take a value", flag),
-            UnknownShortArgument { ref attempt }      => write!(f, "Unknown argument -{}", *attempt as char),
-            UnknownArgument { ref attempt }           => write!(f, "Unknown argument --{}", attempt.to_string_lossy()),
+        match self {
+            Self::NeedsValue { flag, values: None }     => write!(f, "Flag {} needs a value", flag),
+            Self::NeedsValue { flag, values: Some(cs) } => write!(f, "Flag {} needs a value ({})", flag, Choices(cs)),
+            Self::ForbiddenValue { flag }               => write!(f, "Flag {} cannot take a value", flag),
+            Self::UnknownShortArgument { attempt }      => write!(f, "Unknown argument -{}", *attempt as char),
+            Self::UnknownArgument { attempt }           => write!(f, "Unknown argument --{}", attempt.to_string_lossy()),
         }
     }
 }
@@ -119,12 +116,16 @@ impl Misfire {
     /// went wrong.
     pub fn suggestion(&self) -> Option<&'static str> {
         // ‘ls -lt’ and ‘ls -ltr’ are common combinations
-        match *self {
-            Self::BadArgument(ref time, ref r) if *time == &flags::TIME && r == "r" =>
-                Some("To sort oldest files last, try \"--sort oldest\", or just \"-sold\""),
-            Self::InvalidOptions(ParseError::NeedsValue { ref flag, .. }) if *flag == Flag::Short(b't') =>
-                Some("To sort newest files last, try \"--sort newest\", or just \"-snew\""),
-            _ => None
+        match self {
+            Self::BadArgument(time, r) if *time == &flags::TIME && r == "r" => {
+                Some("To sort oldest files last, try \"--sort oldest\", or just \"-sold\"")
+            }
+            Self::InvalidOptions(ParseError::NeedsValue { ref flag, .. }) if *flag == Flag::Short(b't') => {
+                Some("To sort newest files last, try \"--sort newest\", or just \"-snew\"")
+            }
+            _ => {
+                None
+            }
         }
     }
 }

+ 9 - 9
src/options/parser.rs

@@ -52,7 +52,7 @@ pub type Values = &'static [&'static str];
 
 /// A **flag** is either of the two argument types, because they have to
 /// be in the same array together.
-#[derive(PartialEq, Debug, Clone)]
+#[derive(PartialEq, Debug, Copy, Clone)]
 pub enum Flag {
     Short(ShortArg),
     Long(LongArg),
@@ -60,17 +60,17 @@ pub enum Flag {
 
 impl Flag {
     pub fn matches(&self, arg: &Arg) -> bool {
-        match *self {
-            Self::Short(short)  => arg.short == Some(short),
-            Self::Long(long)    => arg.long == long,
+        match self {
+            Self::Short(short)  => arg.short == Some(*short),
+            Self::Long(long)    => arg.long == *long,
         }
     }
 }
 
 impl fmt::Display for Flag {
     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
-        match *self {
-            Self::Short(short) => write!(f, "-{}", short as char),
+        match self {
+            Self::Short(short) => write!(f, "-{}", *short as char),
             Self::Long(long)   => write!(f, "--{}", long),
         }
     }
@@ -108,7 +108,7 @@ pub enum TakesValue {
 
 
 /// An **argument** can be matched by one of the user’s input strings.
-#[derive(PartialEq, Debug)]
+#[derive(PartialEq, Debug, Copy, Clone)]
 pub struct Arg {
 
     /// The short argument that matches it, if any.
@@ -372,7 +372,7 @@ impl<'a> MatchedFlags<'a> {
                           .collect::<Vec<_>>();
 
             if all.len() < 2 { Ok(all.first().map(|t| &t.0)) }
-                        else { Err(Misfire::Duplicate(all[0].0.clone(), all[1].0.clone())) }
+                        else { Err(Misfire::Duplicate(all[0].0, all[1].0)) }
         }
         else {
             let any = self.flags.iter().rev()
@@ -406,7 +406,7 @@ impl<'a> MatchedFlags<'a> {
                             .collect::<Vec<_>>();
 
             if those.len() < 2 { Ok(those.first().cloned().map(|t| t.1.unwrap())) }
-                          else { Err(Misfire::Duplicate(those[0].0.clone(), those[1].0.clone())) }
+                          else { Err(Misfire::Duplicate(those[0].0, those[1].0)) }
         }
         else {
             let found = self.flags.iter().rev()

+ 1 - 1
src/options/version.rs

@@ -8,7 +8,7 @@ use crate::options::flags;
 use crate::options::parser::MatchedFlags;
 
 
-#[derive(PartialEq, Debug)]
+#[derive(PartialEq, Debug, Copy, Clone)]
 pub struct VersionString;
 // There were options here once, but there aren’t anymore!
 

+ 3 - 3
src/options/view.rs

@@ -143,7 +143,7 @@ impl Mode {
 
 
 /// The width of the terminal requested by the user.
-#[derive(PartialEq, Debug)]
+#[derive(PartialEq, Debug, Copy, Clone)]
 enum TerminalWidth {
 
     /// The user requested this specific number of columns.
@@ -178,8 +178,8 @@ impl TerminalWidth {
         }
     }
 
-    fn width(&self) -> Option<usize> {
-        match *self {
+    fn width(self) -> Option<usize> {
+        match self {
             Self::Set(width)       |
             Self::Terminal(width)  => Some(width),
             Self::Unset            => None,

+ 5 - 5
src/output/details.rs

@@ -162,7 +162,7 @@ impl<'a> Render<'a> {
                 (None,    _)        => {/* Keep Git how it is */},
             }
 
-            let mut table = Table::new(&table, git, &self.colours);
+            let mut table = Table::new(table, git, self.colours);
 
             if self.opts.header {
                 let header = table.header_row();
@@ -248,7 +248,7 @@ impl<'a> Render<'a> {
                         }
                     }
 
-                    let table_row = table.as_ref().map(|t| t.row_for_file(&file, !xattrs.is_empty()));
+                    let table_row = table.as_ref().map(|t| t.row_for_file(file, !xattrs.is_empty()));
 
                     if !self.opts.xattr {
                         xattrs.clear();
@@ -266,7 +266,7 @@ impl<'a> Render<'a> {
                     };
 
                     let icon = if self.opts.icons {
-                        Some(painted_icon(&file, &self.style))
+                        Some(painted_icon(file, self.style))
                     } else { None };
 
                     let egg = Egg { table_row, xattrs, errors, dir, file, icon };
@@ -283,7 +283,7 @@ impl<'a> Render<'a> {
             let mut files = Vec::new();
             let mut errors = egg.errors;
 
-            if let (Some(ref mut t), Some(ref row)) = (table.as_mut(), egg.table_row.as_ref()) {
+            if let (Some(ref mut t), Some(row)) = (table.as_mut(), egg.table_row.as_ref()) {
                 t.add_widths(row);
             }
 
@@ -291,7 +291,7 @@ impl<'a> Render<'a> {
             if let Some(icon) = egg.icon {
                 name_cell.push(ANSIGenericString::from(icon), 2)
             }
-            name_cell.append(self.style.for_file(&egg.file, self.colours)
+            name_cell.append(self.style.for_file(egg.file, self.colours)
                                   .with_link_paths()
                                   .paint()
                                   .promote());

+ 3 - 3
src/output/file_name.rs

@@ -133,8 +133,8 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
         }
 
         if let (LinkStyle::FullLinkPaths, Some(target)) = (self.link_style, self.target.as_ref()) {
-            match *target {
-                FileTarget::Ok(ref target) => {
+            match target {
+                FileTarget::Ok(target) => {
                     bits.push(Style::default().paint(" "));
                     bits.push(self.colours.normal_arrow().paint("->"));
                     bits.push(Style::default().paint(" "));
@@ -159,7 +159,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
                     }
                 },
 
-                FileTarget::Broken(ref broken_path) => {
+                FileTarget::Broken(broken_path) => {
                     bits.push(Style::default().paint(" "));
                     bits.push(self.colours.broken_symlink().paint("->"));
                     bits.push(Style::default().paint(" "));

+ 2 - 2
src/output/grid.rs

@@ -41,7 +41,7 @@ impl<'a> Render<'a> {
         grid.reserve(self.files.len());
 
         for file in &self.files {
-            let icon = if self.opts.icons { Some(painted_icon(&file, &self.style)) } else { None };
+            let icon = if self.opts.icons { Some(painted_icon(file, self.style)) } else { None };
             let filename = self.style.for_file(file, self.colours).paint();
             let width = if self.opts.icons {
                 DisplayWidth::from(2) + filename.width()
@@ -64,7 +64,7 @@ impl<'a> Render<'a> {
             // displays full link paths.
             for file in &self.files {
                 if self.opts.icons {
-                    write!(w, "{}", painted_icon(&file, &self.style))?;
+                    write!(w, "{}", painted_icon(file, self.style))?;
                 }
                 let name_cell = self.style.for_file(file, self.colours).paint();
                 writeln!(w, "{}", name_cell.strings())?;

+ 2 - 2
src/output/grid_details.rs

@@ -112,7 +112,7 @@ impl<'a> Render<'a> {
             style: self.style,
             opts: self.details,
             recurse: None,
-            filter: &self.filter,
+            filter: self.filter,
             git_ignoring: self.git_ignoring,
         }
     }
@@ -144,7 +144,7 @@ impl<'a> Render<'a> {
                              .map(|file| {
                                  if self.details.icons {
                                     let mut icon_cell = TextCell::default();
-                                    icon_cell.push(ANSIGenericString::from(painted_icon(&file, &self.style)), 2);
+                                    icon_cell.push(ANSIGenericString::from(painted_icon(file, self.style)), 2);
                                     let file_cell = self.style.for_file(file, self.colours).paint().promote();
                                     icon_cell.append(file_cell);
                                     icon_cell

+ 5 - 4
src/output/icons.rs

@@ -8,6 +8,7 @@ pub trait FileIcon {
     fn icon_file(&self, file: &File) -> Option<char>;
 }
 
+#[derive(Copy, Clone)]
 pub enum Icons {
     Audio,
     Image,
@@ -15,8 +16,8 @@ pub enum Icons {
 }
 
 impl Icons {
-    pub fn value(&self) -> char {
-        match *self {
+    pub fn value(self) -> char {
+        match self {
             Self::Audio => '\u{f001}',
             Self::Image => '\u{f1c5}',
             Self::Video => '\u{f03d}',
@@ -25,9 +26,9 @@ impl Icons {
 }
 
 pub fn painted_icon(file: &File, style: &FileStyle) -> String {
-    let file_icon = icon(&file).to_string();
+    let file_icon = icon(file).to_string();
     let painted = style.exts
-            .colour_file(&file)
+            .colour_file(file)
             .map_or(file_icon.to_string(), |c| {
                 // Remove underline from icon
                 if c.is_underline {

+ 1 - 1
src/output/lines.rs

@@ -28,7 +28,7 @@ impl<'a> Render<'a> {
             if self.opts.icons {
                 // Create a TextCell for the icon then append the text to it
                 let mut cell = TextCell::default();
-                let icon = painted_icon(&file, self.style);
+                let icon = painted_icon(file, self.style);
                 cell.push(ANSIGenericString::from(icon), 2);
                 cell.append(name_cell.promote());
                 writeln!(w, "{}", ANSIStrings(&cell))?;

+ 3 - 3
src/output/render/blocks.rs

@@ -6,9 +6,9 @@ use crate::fs::fields as f;
 
 impl f::Blocks {
     pub fn render<C: Colours>(&self, colours: &C) -> TextCell {
-        match *self {
-            Self::Some(ref blk)  => TextCell::paint(colours.block_count(), blk.to_string()),
-            Self::None           => TextCell::blank(colours.no_blocks()),
+        match self {
+            Self::Some(blk)  => TextCell::paint(colours.block_count(), blk.to_string()),
+            Self::None       => TextCell::blank(colours.no_blocks()),
         }
     }
 }

+ 2 - 2
src/output/render/filetype.rs

@@ -4,8 +4,8 @@ use crate::fs::fields as f;
 
 
 impl f::Type {
-    pub fn render<C: Colours>(&self, colours: &C) -> ANSIString<'static> {
-        match *self {
+    pub fn render<C: Colours>(self, colours: &C) -> ANSIString<'static> {
+        match self {
             Self::File        => colours.normal().paint("."),
             Self::Directory   => colours.directory().paint("d"),
             Self::Pipe        => colours.pipe().paint("|"),

+ 3 - 3
src/output/render/git.rs

@@ -5,7 +5,7 @@ use crate::fs::fields as f;
 
 
 impl f::Git {
-    pub fn render(&self, colours: &dyn Colours) -> TextCell {
+    pub fn render(self, colours: &dyn Colours) -> TextCell {
         TextCell {
             width: DisplayWidth::from(2),
             contents: vec![
@@ -18,8 +18,8 @@ impl f::Git {
 
 
 impl f::GitStatus {
-    fn render(&self, colours: &dyn Colours) -> ANSIString<'static> {
-        match *self {
+    fn render(self, colours: &dyn Colours) -> ANSIString<'static> {
+        match self {
             Self::NotModified  => colours.not_modified().paint("-"),
             Self::New          => colours.new().paint("N"),
             Self::Modified     => colours.modified().paint("M"),

+ 1 - 1
src/output/render/groups.rs

@@ -6,7 +6,7 @@ use crate::output::cell::TextCell;
 
 
 impl f::Group {
-    pub fn render<C: Colours, U: Users+Groups>(&self, colours: &C, users: &U) -> TextCell {
+    pub fn render<C: Colours, U: Users+Groups>(self, colours: &C, users: &U) -> TextCell {
         use users::os::unix::GroupExt;
 
         let mut style = colours.not_yours();

+ 1 - 1
src/output/render/inode.rs

@@ -5,7 +5,7 @@ use crate::fs::fields as f;
 
 
 impl f::Inode {
-    pub fn render(&self, style: Style) -> TextCell {
+    pub fn render(self, style: Style) -> TextCell {
         TextCell::paint(style, self.0.to_string())
     }
 }

+ 3 - 3
src/output/render/size.rs

@@ -8,10 +8,10 @@ use crate::output::table::SizeFormat;
 
 
 impl f::Size {
-    pub fn render<C: Colours>(&self, colours: &C, size_format: SizeFormat, numerics: &NumericLocale) -> TextCell {
+    pub fn render<C: Colours>(self, colours: &C, size_format: SizeFormat, numerics: &NumericLocale) -> TextCell {
         use number_prefix::NumberPrefix;
 
-        let size = match *self {
+        let size = match self {
             Self::Some(s)             => s,
             Self::None                => return TextCell::blank(colours.no_size()),
             Self::DeviceIDs(ref ids)  => return ids.render(colours),
@@ -57,7 +57,7 @@ impl f::Size {
 
 
 impl f::DeviceIDs {
-    fn render<C: Colours>(&self, colours: &C) -> TextCell {
+    fn render<C: Colours>(self, colours: &C) -> TextCell {
         let major = self.major.to_string();
         let minor = self.minor.to_string();
 

+ 1 - 1
src/output/render/users.rs

@@ -7,7 +7,7 @@ use crate::output::cell::TextCell;
 
 
 impl f::User {
-    pub fn render<C: Colours, U: Users>(&self, colours: &C, users: &U) -> TextCell {
+    pub fn render<C: Colours, U: Users>(self, colours: &C, users: &U) -> TextCell {
         let user_name = match users.get_user_by_uid(self.0) {
             Some(user)  => user.name().to_string_lossy().into(),
             None        => self.0.to_string(),

+ 13 - 13
src/output/table.rs

@@ -36,7 +36,7 @@ impl fmt::Debug for Options {
 }
 
 /// Extra columns to display in the table.
-#[derive(PartialEq, Debug)]
+#[derive(PartialEq, Debug, Copy, Clone)]
 pub struct Columns {
 
     /// At least one of these timestamps will be shown.
@@ -118,7 +118,7 @@ impl Columns {
 
 
 /// A table contains these.
-#[derive(Debug)]
+#[derive(Debug, Copy, Clone)]
 pub enum Column {
     Permissions,
     FileSize,
@@ -142,8 +142,8 @@ pub enum Alignment {
 impl Column {
 
     /// Get the alignment this column should use.
-    pub fn alignment(&self) -> Alignment {
-        match *self {
+    pub fn alignment(self) -> Alignment {
+        match self {
             Self::FileSize  |
             Self::HardLinks |
             Self::Inode     |
@@ -155,8 +155,8 @@ impl Column {
 
     /// Get the text that should be printed at the top, when the user elects
     /// to have a header row printed.
-    pub fn header(&self) -> &'static str {
-        match *self {
+    pub fn header(self) -> &'static str {
+        match self {
             Self::Permissions   => "Permissions",
             Self::FileSize      => "Size",
             Self::Timestamp(t)  => t.header(),
@@ -342,7 +342,7 @@ impl<'a, 'f> Table<'a> {
 
     pub fn row_for_file(&self, file: &File, xattrs: bool) -> Row {
         let cells = self.columns.iter()
-                        .map(|c| self.display(file, c, xattrs))
+                        .map(|c| self.display(file, *c, xattrs))
                         .collect();
 
         Row { cells }
@@ -366,10 +366,10 @@ impl<'a, 'f> Table<'a> {
         }
     }
 
-    fn display(&self, file: &File, column: &Column, xattrs: bool) -> TextCell {
+    fn display(&self, file: &File, column: Column, xattrs: bool) -> TextCell {
         use crate::output::table::TimeType::*;
 
-        match *column {
+        match column {
             Column::Permissions    => self.permissions_plus(file, xattrs).render(self.colours),
             Column::FileSize       => file.size().render(self.colours, self.size_format, &self.env.numeric),
             Column::HardLinks      => file.links().render(self.colours, &self.env.numeric),
@@ -380,10 +380,10 @@ impl<'a, 'f> Table<'a> {
             Column::GitStatus      => self.git_status(file).render(self.colours),
             Column::Octal          => self.octal_permissions(file).render(self.colours.octal),
 
-            Column::Timestamp(Modified)  => file.modified_time().render(self.colours.date, &self.env.tz, &self.time_format),
-            Column::Timestamp(Changed)   => file.changed_time() .render(self.colours.date, &self.env.tz, &self.time_format),
-            Column::Timestamp(Created)   => file.created_time() .render(self.colours.date, &self.env.tz, &self.time_format),
-            Column::Timestamp(Accessed)  => file.accessed_time().render(self.colours.date, &self.env.tz, &self.time_format),
+            Column::Timestamp(Modified)  => file.modified_time().render(self.colours.date, &self.env.tz, self.time_format),
+            Column::Timestamp(Changed)   => file.changed_time() .render(self.colours.date, &self.env.tz, self.time_format),
+            Column::Timestamp(Created)   => file.created_time() .render(self.colours.date, &self.env.tz, self.time_format),
+            Column::Timestamp(Accessed)  => file.accessed_time().render(self.colours.date, &self.env.tz, self.time_format),
         }
     }
 

+ 14 - 14
src/output/time.rs

@@ -51,20 +51,20 @@ pub enum TimeFormat {
 
 impl TimeFormat {
     pub fn format_local(&self, time: SystemTime) -> String {
-        match *self {
-            Self::DefaultFormat(ref fmt) => fmt.format_local(time),
-            Self::ISOFormat(ref iso)     => iso.format_local(time),
-            Self::LongISO                => long_local(time),
-            Self::FullISO                => full_local(time),
+        match self {
+            Self::DefaultFormat(fmt)  => fmt.format_local(time),
+            Self::ISOFormat(iso)      => iso.format_local(time),
+            Self::LongISO             => long_local(time),
+            Self::FullISO             => full_local(time),
         }
     }
 
     pub fn format_zoned(&self, time: SystemTime, zone: &TimeZone) -> String {
-        match *self {
-            Self::DefaultFormat(ref fmt) => fmt.format_zoned(time, zone),
-            Self::ISOFormat(ref iso)     => iso.format_zoned(time, zone),
-            Self::LongISO                => long_zoned(time, zone),
-            Self::FullISO                => full_zoned(time, zone),
+        match self {
+            Self::DefaultFormat(fmt)  => fmt.format_zoned(time, zone),
+            Self::ISOFormat(iso)      => iso.format_zoned(time, zone),
+            Self::LongISO             => long_zoned(time, zone),
+            Self::FullISO             => full_zoned(time, zone),
         }
     }
 }
@@ -241,7 +241,7 @@ fn full_zoned(time: SystemTime, zone: &TimeZone) -> String {
 
 
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Copy, Clone)]
 pub struct ISOFormat {
 
     /// The year of the current time. This gets used to determine which date
@@ -257,12 +257,12 @@ impl ISOFormat {
 }
 
 impl ISOFormat {
-    fn is_recent(&self, date: LocalDateTime) -> bool {
+    fn is_recent(self, date: LocalDateTime) -> bool {
         date.year() == self.current_year
     }
 
     #[allow(trivial_numeric_casts)]
-    fn format_local(&self, time: SystemTime) -> String {
+    fn format_local(self, time: SystemTime) -> String {
         let date = LocalDateTime::at(systemtime_epoch(time));
 
         if self.is_recent(date) {
@@ -277,7 +277,7 @@ impl ISOFormat {
     }
 
     #[allow(trivial_numeric_casts)]
-    fn format_zoned(&self, time: SystemTime, zone: &TimeZone) -> String {
+    fn format_zoned(self, time: SystemTime, zone: &TimeZone) -> String {
         let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));
 
         if self.is_recent(date) {

+ 3 - 3
src/output/tree.rs

@@ -39,7 +39,7 @@
 //! each directory)
 
 
-#[derive(PartialEq, Debug, Clone)]
+#[derive(PartialEq, Debug, Copy, Clone)]
 pub enum TreePart {
 
     /// Rightmost column, *not* the last in the directory.
@@ -59,8 +59,8 @@ impl TreePart {
 
     /// Turn this tree part into ASCII-licious box drawing characters!
     /// (Warning: not actually ASCII)
-    pub fn ascii_art(&self) -> &'static str {
-        match *self {
+    pub fn ascii_art(self) -> &'static str {
+        match self {
             Self::Edge    => "├──",
             Self::Line    => "│  ",
             Self::Corner  => "└──",