lattice_host/tutor/
scores.rs1use std::collections::HashMap;
16use std::path::PathBuf;
17
18use serde::{Deserialize, Serialize};
19
20#[derive(Debug, Default, Clone, Serialize, Deserialize)]
23pub struct TutorScores {
24 #[serde(default)]
26 pub lessons: HashMap<u32, u32>,
27}
28
29impl TutorScores {
30 pub fn high_score(&self, lesson: u32) -> u32 {
32 self.lessons.get(&lesson).copied().unwrap_or(0)
33 }
34
35 pub fn record(&mut self, lesson: u32, score: u32) -> bool {
38 let entry = self.lessons.entry(lesson).or_insert(0);
39 if score > *entry {
40 *entry = score;
41 true
42 } else {
43 false
44 }
45 }
46
47 pub fn load_or_default() -> Self {
52 let Some(path) = scores_path() else {
53 return Self::default();
54 };
55 let Ok(bytes) = std::fs::read_to_string(&path) else {
56 return Self::default();
57 };
58 match toml::from_str::<Self>(&bytes) {
59 Ok(s) => s,
60 Err(e) => {
61 tracing::debug!(
62 target: "lattice_host::tutor_scores",
63 path = %path.display(),
64 error = %e,
65 "tutor-scores: parse error, starting fresh"
66 );
67 Self::default()
68 }
69 }
70 }
71
72 pub fn save(&self) {
74 let Some(path) = scores_path() else { return };
75 if let Some(parent) = path.parent()
76 && let Err(e) = std::fs::create_dir_all(parent)
77 {
78 tracing::debug!(
79 target: "lattice_host::tutor_scores",
80 path = %parent.display(),
81 error = %e,
82 "tutor-scores: could not create data dir"
83 );
84 return;
85 }
86 match toml::to_string_pretty(self) {
87 Ok(text) => {
88 if let Err(e) = std::fs::write(&path, text) {
89 tracing::debug!(
90 target: "lattice_host::tutor_scores",
91 path = %path.display(),
92 error = %e,
93 "tutor-scores: write failed"
94 );
95 }
96 }
97 Err(e) => {
98 tracing::debug!(
99 target: "lattice_host::tutor_scores",
100 error = %e,
101 "tutor-scores: serialization failed"
102 );
103 }
104 }
105 }
106}
107
108fn scores_path() -> Option<PathBuf> {
109 let path = lattice_config::config_home().map(|d| d.join("lattice").join(SCORES_FILE))?;
110 if !path.exists()
111 && let Some(legacy) = dirs::data_local_dir().map(|d| d.join("lattice").join(SCORES_FILE))
112 && legacy.exists()
113 {
114 if let Some(parent) = path.parent() {
118 let _ = std::fs::create_dir_all(parent);
119 }
120 match std::fs::rename(&legacy, &path) {
121 Ok(()) => tracing::debug!(
122 target: "lattice_host::tutor_scores",
123 to = %path.display(),
124 "tutor-scores: moved under the config home"
125 ),
126 Err(e) => tracing::debug!(
127 target: "lattice_host::tutor_scores",
128 error = %e,
129 "tutor-scores: could not move the old file"
130 ),
131 }
132 }
133 Some(path)
134}
135
136const SCORES_FILE: &str = "tutor-scores.toml";