1use crate::Parameters;
2use chrono::{DateTime, Utc};
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Clone, Copy, PartialEq, Debug, Default, Eq)]
8#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9pub enum State {
10 #[default]
11 New = 0,
12 Learning = 1,
13 Review = 2,
14 Relearning = 3,
15}
16
17#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19pub enum Rating {
20 Again = 1,
21 Hard = 2,
22 Good = 3,
23 Easy = 4,
24}
25
26impl Rating {
27 pub fn iter() -> std::slice::Iter<'static, Self> {
28 static VARIANTS: [Rating; 4] = [Rating::Again, Rating::Hard, Rating::Good, Rating::Easy];
29 VARIANTS.iter()
30 }
31}
32
33#[derive(Debug, Clone)]
34pub struct SchedulingInfo {
35 pub card: Card,
36 pub review_log: ReviewLog,
37}
38
39pub type RecordLog = HashMap<Rating, SchedulingInfo>;
40
41#[derive(Clone, Debug, PartialEq, Eq)]
42#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
43pub struct ReviewLog {
44 pub rating: Rating,
45 pub elapsed_days: i64,
46 pub scheduled_days: i64,
47 pub state: State,
48 pub reviewed_date: DateTime<Utc>,
49}
50
51#[derive(Clone, Debug, Default, PartialEq)]
52#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
53pub struct Card {
54 pub due: DateTime<Utc>,
55 pub stability: f64,
56 pub difficulty: f64,
57 pub elapsed_days: i64,
58 pub scheduled_days: i64,
59 pub reps: i32,
60 pub lapses: i32,
61 pub state: State,
62 pub last_review: DateTime<Utc>,
63}
64
65impl Card {
66 pub fn new() -> Self {
67 Self {
68 due: Utc::now(),
69 last_review: Utc::now(),
70 ..Default::default()
71 }
72 }
73
74 pub fn get_retrievability(&self, now: DateTime<Utc>) -> f64 {
75 match self.state {
76 State::New => 0.0,
77 _ => {
78 let elapsed_days = now.signed_duration_since(self.last_review).num_days();
79 Parameters::forgetting_curve(elapsed_days as f64, self.stability)
80 }
81 }
82 }
83}