diff --git a/rslib/src/scheduler/fsrs/memory_state.rs b/rslib/src/scheduler/fsrs/memory_state.rs index 5efef07a6..90920f4bb 100644 --- a/rslib/src/scheduler/fsrs/memory_state.rs +++ b/rslib/src/scheduler/fsrs/memory_state.rs @@ -242,6 +242,7 @@ pub(crate) struct FsrsItemForMemoryState { /// When revlogs have been truncated, this stores the initial state at first /// review pub starting_state: Option, + pub filtered_revlogs: Vec, } /// Like [fsrs_item_for_memory_state], but for updating multiple cards at once. @@ -330,6 +331,7 @@ pub(crate) fn fsrs_item_for_memory_state( Ok(Some(FsrsItemForMemoryState { item, starting_state: None, + filtered_revlogs: output.filtered_revlogs, })) } else if let Some(first_user_grade) = output.filtered_revlogs.first() { // the revlog has been truncated, but not fully @@ -356,6 +358,7 @@ pub(crate) fn fsrs_item_for_memory_state( Ok(Some(FsrsItemForMemoryState { item, starting_state: Some(starting_state), + filtered_revlogs: output.filtered_revlogs, })) } else { // only manual and rescheduled revlogs; treat like empty diff --git a/rslib/src/stats/card.rs b/rslib/src/stats/card.rs index 1db368445..48fdc3457 100644 --- a/rslib/src/stats/card.rs +++ b/rslib/src/stats/card.rs @@ -4,6 +4,7 @@ use fsrs::FSRS; use crate::card::CardType; +use crate::card::FsrsMemoryState; use crate::prelude::*; use crate::revlog::RevlogEntry; use crate::scheduler::fsrs::memory_state::fsrs_item_for_memory_state; @@ -140,26 +141,31 @@ impl Collection { let ignore_before = ignore_revlogs_before_ms_from_config(&config)?; let mut result = Vec::new(); - let mut accumulated_revlog = Vec::new(); - - for entry in revlog { - accumulated_revlog.push(entry.clone()); - let item = fsrs_item_for_memory_state( - &fsrs, - accumulated_revlog.clone(), - next_day_at, - historical_retention, - ignore_before, - )?; - let mut card_clone = card.clone(); - card_clone.set_memory_state(&fsrs, item, historical_retention)?; - - let mut stats_entry = stats_revlog_entry(&entry); - stats_entry.memory_state = card_clone.memory_state.map(Into::into); - result.push(stats_entry); + if let Some(item) = fsrs_item_for_memory_state( + &fsrs, + revlog.clone(), + next_day_at, + historical_retention, + ignore_before, + )? { + let memory_states = fsrs.historical_memory_states(item.item, item.starting_state)?; + let mut revlog_index = 0; + for entry in revlog { + let mut stats_entry = stats_revlog_entry(&entry); + let memory_state: FsrsMemoryState = + if entry.id == item.filtered_revlogs[revlog_index].id { + revlog_index += 1; + memory_states[revlog_index - 1].into() + } else { + memory_states[revlog_index].into() + }; + stats_entry.memory_state = Some(memory_state.into()); + result.push(stats_entry); + } + Ok(result.into_iter().rev().collect()) + } else { + Ok(revlog.iter().map(stats_revlog_entry).collect()) } - - Ok(result.into_iter().rev().collect()) } }