forne/
set.rs

1use std::collections::HashMap;
2
3use anyhow::Result;
4use rhai::Dynamic;
5use serde::{Deserialize, Serialize};
6use uuid::Uuid;
7
8/// A single key-value pair that represents an element in the set.
9#[derive(Serialize, Deserialize)]
10pub struct Card {
11    /// The prompt the user will be given for this card.
12    pub question: String,
13    /// The answer this card has (which will be shown to the user).
14    pub answer: String,
15    /// Whether or not this card has been seen yet in the active test.
16    pub seen_in_test: bool,
17    /// Whether or not this card has been marked as difficult. Difficult cards are intended to
18    /// be identified during the learning process, and the marking of them as such should be
19    /// automated.
20    pub difficult: bool,
21    /// Whether or not this card has been starred. Cards are automatically starred if a user gets
22    /// them wrong in a test, and they will be unstarred if the user later gets them right in a test. This
23    /// behaviour can be customised with flags.
24    pub starred: bool,
25    /// Data about this card stored by the current method. This can be serialized and deserialized, but
26    /// is completely arbitrary, and different cards may store completely different data here. This should
27    /// be passed to and from method scripts with no intervention from Rust.
28    pub method_data: Dynamic,
29}
30
31/// A slim representation of a card without internal metadata, which will be returned when polling a
32/// [`crate::Driver`].
33#[derive(Clone)]
34pub struct SlimCard {
35    /// The question on the card.
36    pub question: String,
37    /// The answer on the 'other side' of the card.
38    pub answer: String,
39    /// Whether or not the card has been automatically marked as difficult. Callers may wish to highlight this
40    /// to users when a question is displayed, or not.
41    pub difficult: bool,
42    /// Whether or not the card has been starred, which, likewise, callers may wish to highlight or not when
43    /// displaying this card.
44    pub starred: bool,
45}
46
47/// The different card categories that operations on sets can be classed into.
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
49#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
50pub enum CardType {
51    /// All the cards in the set.
52    All,
53    /// Only cards that have been automatically marked as difficult.
54    Difficult,
55    /// Only cards that have been automatically starred when the user got them wrong in a test.
56    Starred,
57}
58
59/// A set of cards with associated data about how learning this set has progressed.
60#[derive(Serialize, Deserialize)]
61pub struct Set {
62    /// The name of the method used on this set. As methods provide their own custom metadata for each card, it
63    /// is not generally possible to transition a set from one learning method to another while keeping your
64    /// progress, unless a transformer is provided by the methods to do so. This acts as a guard to prevent
65    /// the user from accidentally deleting all their hard work!
66    pub method: String,
67    /// A list of all the cards in the set.
68    pub cards: HashMap<Uuid, Card>,
69    /// The state of the set in terms of tests. This will be `Some(..)` if there was a previous
70    /// test, and the attached string will be the name of the method used. Runs on different targets
71    /// will not interfere with each other, and this program is built to support them.
72    pub run_state: Option<String>,
73    /// Whether or not there is a test currently in progress. Card weightings are calculated with an
74    /// internal system in tests, but no internal card metadata will be modified, this is instead used to keep
75    /// track of which cards have already been shown to the user.
76    ///
77    /// Note that, if a test is started on one target, and a later test is begun on a different subset target,
78    /// it is possible that the latter will cause the prior to be forgotten about (since this will be set back
79    /// to `false` once the active test is finished). This kind of issue does not affect learn mode, because there
80    /// is no such thing as a finished learn mode, until all weightings are set to zero, meaning things are kept
81    /// track of on a card-by-card basis, unlike in tests.
82    pub test_in_progress: bool,
83}
84impl Set {
85    /// Saves this set to the given JSON file, preserving all progress.
86    pub fn save(&self) -> Result<String> {
87        let json = serde_json::to_string(&self)?;
88        Ok(json)
89    }
90    /// Loads this set from the given JSON.
91    pub fn from_json(json: &str) -> Result<Self> {
92        let set = serde_json::from_str(json)?;
93        Ok(set)
94    }
95    /// Resets all cards in a learn back to the default metadata values prescribed by the learning method.
96    pub(crate) fn reset_learn(&mut self, default_data: Dynamic) {
97        for card in self.cards.values_mut() {
98            card.method_data = default_data.clone();
99        }
100    }
101    /// Resets all test progress for this set. This is irreversible!
102    ///
103    /// This will not change whether or not cards are starred.
104    pub(crate) fn reset_test(&mut self) {
105        for card in self.cards.values_mut() {
106            card.seen_in_test = false;
107        }
108    }
109    /// Resets all stars for this set. This is irreversible!
110    pub fn reset_stars(&mut self) {
111        for card in self.cards.values_mut() {
112            card.starred = false;
113        }
114    }
115}