repo_description: A new way to see and navigate directory trees : https://dystroy.org/broot
repo_topics: balanced-bfs-descent command-line command-line-tool fuzzy-search hacktoberfest linux rust tree
code: /// compute consolidated data for directories: modified date, size, and count.
  /// A cache is used to avoid recomputing the same directories again and again.
  /// On unix, hard links are checked to avoid counting twice an inode.
  mod sum_computation;
  
  use {
      crate::{
          app::*,
          task_sync::Dam,
      },
      once_cell::sync::Lazy,
      rustc_hash::FxHashMap,
      std::{
          ops::AddAssign,
          path::{
              Path,
              PathBuf,
          },
          sync::Mutex,
      },
  };
  
  pub const DEFAULT_THREAD_COUNT: usize = 5;
  
  static SUM_CACHE: Lazy<Mutex<FxHashMap<PathBuf, FileSum>>> =
      Lazy::new(|| Mutex::new(FxHashMap::default()));
  
  pub fn clear_cache() {
      #[allow(clippy::missing_panics_doc)] // panics if the mutex is poisoned (in which case it's better)
      SUM_CACHE.lock().unwrap().clear();
  }
  
  /// Reduction of counts, dates and sizes on a file or directory
  #[derive(Debug, Copy, Clone)]
  pub struct FileSum {
      real_size: u64, // bytes, the space it takes on disk
      count: usize,   // number of files
      modified: u32,  // seconds from Epoch to last modification, or 0 if there was an error
      sparse: bool,   // only for non directories: tells whether the file is sparse
  }
  
  impl FileSum {
      pub fn new(
          real_size: u64,
          sparse: bool,
          count: usize,
          modified: u32,
      ) -> Self {
          Self {
              real_size,
              count,
              modified,
              sparse,
          }
      }
  
      pub fn zero() -> Self {
          Self::new(0, false, 0, 0)
      }
  
      pub fn incr(&mut self) {
          self.count += 1;
      }
  
      /// return the sum of the given file, which is assumed
      /// to be a normal file (ie not a directory)
      pub fn from_file(path: &Path) -> Self {
          sum_computation::compute_file_sum(path)
      }
  
      /// Return the sum of the directory, either by computing it of by
      ///  fetching it from cache.
      /// If the lifetime expires before complete computation, None is returned.
      pub fn from_dir(
          path: &Path,
          dam: &Dam,
          con: &AppContext,
      ) -> Option<Self> {
          #[allow(clippy::missing_panics_doc)] // panics on mutex poisoning (good)
          let mut sum_cache = SUM_CACHE.lock().unwrap();
          match sum_cache.get(path) {
              Some(sum) => Some(*sum),
              None => {
                  let sum = time!(
                      "sum computation",
                      path,
                      sum_computation::compute_dir_sum(path, &mut sum_cache, dam, con),
                  );
                  if let Some(sum) = sum {
                      sum_cache.insert(PathBuf::from(path), sum);
                  }
                  sum
              }
          }
      }
  
      pub fn part_of_size(
          self,
          total: Self,
      ) -> f32 {
          if total.real_size == 0 {
              0.0
          } else {
              self.real_size as f32 / total.real_size as f32
          }
      }
      /// return the number of files (normally at least 1)
      pub fn to_count(self) -> usize {
          self.count
      }
      /// return the number of seconds from Epoch to last modification,
      /// or 0 if the computation failed
      pub fn to_seconds(self) -> u32 {
          self.modified
      }
      /// return the size in bytes
      pub fn to_size(self) -> u64 {
          self.real_size
      }
      pub fn to_valid_seconds(self) -> Option<i64> {
          if self.modified != 0 {
              Some(i64::from(self.modified))
          } else {
              None
          }
      }
      /// tell whether the file has holes (in which case the size displayed by
      /// other tools may be greater than the "real" one returned by broot).
      /// Not computed (return false) on windows or for directories.
      pub fn is_sparse(self) -> bool {
          self.sparse
      }
  }
  
  impl AddAssign for FileSum {
      #[allow(clippy::suspicious_op_assign_impl)]
      fn add_assign(
          &mut self,
          other: Self,
      ) {
          *self = Self::new(
              self.real_size + other.real_size,
              self.sparse | other.sparse,
              self.count + other.count,
              self.modified.max(other.modified),
          );
      }
  }
  