From 3864857b07227ae043ef43ea1099146ff9ecc480 Mon Sep 17 00:00:00 2001 From: RumovZ Date: Sat, 30 Apr 2022 18:21:31 +0200 Subject: [PATCH] Outsource incrementing into Incrementor --- rslib/src/import_export/mod.rs | 85 ++++++++----------- .../package/apkg/import/media.rs | 8 +- .../package/apkg/import/notes.rs | 4 +- .../import_export/package/colpkg/export.rs | 3 +- .../import_export/package/colpkg/import.rs | 4 +- 5 files changed, 47 insertions(+), 57 deletions(-) diff --git a/rslib/src/import_export/mod.rs b/rslib/src/import_export/mod.rs index 171c7bd32..b1e2944af 100644 --- a/rslib/src/import_export/mod.rs +++ b/rslib/src/import_export/mod.rs @@ -5,6 +5,8 @@ mod gather; mod insert; pub mod package; +use std::marker::PhantomData; + use crate::prelude::*; #[derive(Debug, Clone, Copy, PartialEq)] @@ -17,59 +19,30 @@ pub enum ImportProgress { /// Wrapper around a progress function, usually passed by the [crate::backend::Backend], /// to make repeated calls more ergonomic. -pub(crate) struct IncrementableProgress

{ - progress_fn: Box bool>, - count_map: Option P>>, - count: usize, - update_interval: usize, -} +pub(crate) struct IncrementableProgress

(Box bool>); impl

IncrementableProgress

{ /// `progress_fn: (progress, throttle) -> should_continue` pub(crate) fn new(progress_fn: impl 'static + FnMut(P, bool) -> bool) -> Self { - Self { - progress_fn: Box::new(progress_fn), - count_map: None, - count: 0, - update_interval: 17, - } + Self(Box::new(progress_fn)) } - /// Resets the count, and defines how it should be mapped to a progress value - /// in the future. - pub(crate) fn set_count_map(&mut self, count_map: impl 'static + FnMut(usize) -> P) { - self.count_map = Some(Box::new(count_map)); - self.count = 0; + /// Returns an [Incrementor] with an `increment()` function for use in loops. + pub(crate) fn incrementor<'inc, 'progress: 'inc, 'map: 'inc>( + &'progress mut self, + mut count_map: impl 'map + FnMut(usize) -> P, + ) -> Incrementor<'inc, impl FnMut(usize) -> Result<()> + 'inc> { + Incrementor::new(move |u| self.update(count_map(u), true)) } - /// Increment the progress counter, periodically triggering an update. - /// Returns [AnkiError::Interrupted] if the operation should be cancelled. - /// Must have called `set_count_map()` before calling this. - pub(crate) fn increment(&mut self) -> Result<()> { - self.count += 1; - if self.count % self.update_interval != 0 { - return Ok(()); - } - let progress = self.mapped_progress()?; - self.update(progress, true) - } - - /// Manually trigger an update. + /// Manually triggers an update. /// Returns [AnkiError::Interrupted] if the operation should be cancelled. pub(crate) fn call(&mut self, progress: P) -> Result<()> { self.update(progress, false) } - fn mapped_progress(&mut self) -> Result

{ - if let Some(count_map) = self.count_map.as_mut() { - Ok(count_map(self.count)) - } else { - Err(AnkiError::invalid_input("count_map not set")) - } - } - fn update(&mut self, progress: P, throttle: bool) -> Result<()> { - if (self.progress_fn)(progress, throttle) { + if (self.0)(progress, throttle) { Ok(()) } else { Err(AnkiError::Interrupted) @@ -81,18 +54,34 @@ impl

IncrementableProgress

{ &mut self, count_map: impl 'static + Fn(usize) -> P, ) -> Result bool + '_> { - Ok(move |count| (self.progress_fn)(count_map(count), true)) + Ok(move |count| (self.0)(count_map(count), true)) } } -impl IncrementableProgress { - /// Allows incrementing without a map, if the progress is of type [usize]. - pub(crate) fn increment_flat(&mut self) -> Result<()> { - self.count += 1; - if self.count % 17 == 0 { - self.update(self.count, true) - } else { - Ok(()) +pub(crate) struct Incrementor<'f, F: 'f + FnMut(usize) -> Result<()>> { + update_fn: F, + count: usize, + update_interval: usize, + _phantom: PhantomData<&'f ()>, +} + +impl<'f, F: 'f + FnMut(usize) -> Result<()>> Incrementor<'f, F> { + fn new(update_fn: F) -> Self { + Self { + update_fn, + count: 0, + update_interval: 17, + _phantom: PhantomData, } } + + /// Increments the progress counter, periodically triggering an update. + /// Returns [AnkiError::Interrupted] if the operation should be cancelled. + pub(crate) fn increment(&mut self) -> Result<()> { + self.count += 1; + if self.count % self.update_interval != 0 { + return Ok(()); + } + (self.update_fn)(self.count) + } } diff --git a/rslib/src/import_export/package/apkg/import/media.rs b/rslib/src/import_export/package/apkg/import/media.rs index 5a1495e4b..bffd28f2f 100644 --- a/rslib/src/import_export/package/apkg/import/media.rs +++ b/rslib/src/import_export/package/apkg/import/media.rs @@ -45,9 +45,9 @@ impl Context<'_> { } pub(super) fn copy_media(&mut self, media_map: &mut MediaUseMap) -> Result<()> { - self.progress.set_count_map(ImportProgress::Media); + let mut incrementor = self.progress.incrementor(ImportProgress::Media); for entry in media_map.used_entries() { - self.progress.increment()?; + incrementor.increment()?; entry.copy_from_archive(&mut self.archive, &self.target_col.media_folder)?; } Ok(()) @@ -71,10 +71,10 @@ fn prepare_media( progress: &mut IncrementableProgress, ) -> Result { let mut media_map = MediaUseMap::default(); - progress.set_count_map(ImportProgress::MediaCheck); + let mut incrementor = progress.incrementor(ImportProgress::MediaCheck); for mut entry in extract_media_entries(meta, archive)? { - progress.increment()?; + incrementor.increment()?; if entry.is_static() { if !existing_sha1s.contains_key(&entry.name) { diff --git a/rslib/src/import_export/package/apkg/import/notes.rs b/rslib/src/import_export/package/apkg/import/notes.rs index de3fe5143..787453745 100644 --- a/rslib/src/import_export/package/apkg/import/notes.rs +++ b/rslib/src/import_export/package/apkg/import/notes.rs @@ -189,10 +189,10 @@ impl<'n> NoteContext<'n> { notes: Vec, progress: &mut IncrementableProgress, ) -> Result<()> { - progress.set_count_map(ImportProgress::Notes); + let mut incrementor = progress.incrementor(ImportProgress::Notes); for mut note in notes { - progress.increment()?; + incrementor.increment()?; if let Some(notetype_id) = self.remapped_notetypes.get(¬e.notetype_id) { if self.target_guids.contains_key(¬e.guid) { self.imports.log_conflicting(note); diff --git a/rslib/src/import_export/package/colpkg/export.rs b/rslib/src/import_export/package/colpkg/export.rs index 1cc3ead04..09e98023d 100644 --- a/rslib/src/import_export/package/colpkg/export.rs +++ b/rslib/src/import_export/package/colpkg/export.rs @@ -281,8 +281,9 @@ fn write_media_files( progress: &mut IncrementableProgress, ) -> Result<()> { let mut copier = MediaCopier::new(meta); + let mut incrementor = progress.incrementor(|u| u); for (index, res) in media.0.enumerate() { - progress.increment_flat()?; + incrementor.increment()?; let path = res?; zip.start_file(index.to_string(), file_options_stored())?; diff --git a/rslib/src/import_export/package/colpkg/import.rs b/rslib/src/import_export/package/colpkg/import.rs index 6c69abb31..0cc38f791 100644 --- a/rslib/src/import_export/package/colpkg/import.rs +++ b/rslib/src/import_export/package/colpkg/import.rs @@ -92,9 +92,9 @@ fn restore_media( let media_manager = MediaManager::new(media_folder, media_db)?; let mut media_comparer = MediaComparer::new(meta, progress, &media_manager, log)?; - progress.set_count_map(ImportProgress::Media); + let mut incrementor = progress.incrementor(ImportProgress::Media); for mut entry in media_entries { - progress.increment()?; + incrementor.increment()?; maybe_restore_media_file(meta, media_folder, archive, &mut entry, &mut media_comparer)?; }