diff --git a/exa.rs b/exa.rs index 0d053cf93221c0a2773534c9148a5b31046fa534..c866ded442cda41ce78e8656cfdfa520ef51ee37 100644 --- a/exa.rs +++ b/exa.rs @@ -7,6 +7,7 @@ use std::os; use file::File; use dir::Dir; use options::Options; +use unix::Unix; pub mod colours; pub mod column; @@ -61,8 +62,10 @@ fn exa(options: &Options, string: String) { // width of each column based on the length of the results and // padding the fields during output. + let mut cache = Unix::empty_cache(); + let table: Vec> = files.iter() - .map(|f| options.columns.iter().map(|c| f.display(c)).collect()) + .map(|f| options.columns.iter().map(|c| f.display(c, &mut cache)).collect()) .collect(); // Each column needs to have its invisible colour-formatting diff --git a/file.rs b/file.rs index d4886a92ab57a9107cdb757fe0c09ef6fcc99de1..e8c30d63e3c522594f023b7e3af5c3afc3deaa55 100644 --- a/file.rs +++ b/file.rs @@ -4,7 +4,7 @@ use std::io; use column::{Column, Permissions, FileName, FileSize, User, Group}; use format::{format_metric_bytes, format_IEC_bytes}; -use unix::{get_user_name, get_group_name}; +use unix::Unix; use sort::SortPart; use dir::Dir; use filetype::HasType; @@ -89,7 +89,7 @@ impl<'a> File<'a> { } } - pub fn display(&self, column: &Column) -> String { + pub fn display(&self, column: &Column, unix: &mut Unix) -> String { match *column { Permissions => self.permissions_string(), FileName => self.file_name(), @@ -99,10 +99,10 @@ impl<'a> File<'a> { // usually means it was deleted but its files weren't. User(uid) => { let style = if uid == self.stat.unstable.uid { Yellow.bold() } else { Plain }; - let string = get_user_name(self.stat.unstable.uid as i32).unwrap_or(self.stat.unstable.uid.to_str()); + let string = unix.get_user_name(self.stat.unstable.uid as i32).unwrap_or(self.stat.unstable.uid.to_str()); return style.paint(string.as_slice()); }, - Group => get_group_name(self.stat.unstable.gid as u32).unwrap_or(self.stat.unstable.gid.to_str()), + Group => unix.get_group_name(self.stat.unstable.gid as u32).unwrap_or(self.stat.unstable.gid.to_str()), } } diff --git a/unix.rs b/unix.rs index 862b866a3b86f9487c6c7f1c6a2dd7fa74d8d287..14c110c95e36c3e5b457c548a0fdbd5ade168068 100644 --- a/unix.rs +++ b/unix.rs @@ -1,5 +1,6 @@ use std::str::raw::from_c_str; use std::ptr::read; +use std::collections::hashmap::HashMap; mod c { #![allow(non_camel_case_types)] @@ -34,24 +35,41 @@ mod c { pub fn getuid() -> libc::c_int; } } +pub struct Unix { + user_names: HashMap>, + group_names: HashMap>, +} -pub fn get_user_name(uid: i32) -> Option { - let pw = unsafe { c::getpwuid(uid) }; - if pw.is_not_null() { - return unsafe { Some(from_c_str(read(pw).pw_name)) }; - } - else { - return None; +impl Unix { + pub fn empty_cache() -> Unix { + Unix { + user_names: HashMap::new(), + group_names: HashMap::new(), + } } -} -pub fn get_group_name(gid: u32) -> Option { - let gr = unsafe { c::getgrgid(gid) }; - if gr.is_not_null() { - return unsafe { Some(from_c_str(read(gr).gr_name)) }; + pub fn get_user_name<'a> (&'a mut self, uid: i32) -> Option { + self.user_names.find_or_insert_with(uid, |&u| { + let pw = unsafe { c::getpwuid(u) }; + if pw.is_not_null() { + return unsafe { Some(from_c_str(read(pw).pw_name)) }; + } + else { + return None; + } + }).clone() } - else { - return None; + + pub fn get_group_name<'a>(&'a mut self, gid: u32) -> Option { + self.group_names.find_or_insert_with(gid, |&gid| { + let gr = unsafe { c::getgrgid(gid) }; + if gr.is_not_null() { + return unsafe { Some(from_c_str(read(gr).gr_name)) }; + } + else { + return None; + } + }).clone() } }