1#[derive(Clone, Default)]
7pub struct SessionState {
8 pub defs_text: String,
9 pub line_no: usize,
10}
11
12pub trait Store {
17 fn load(&self) -> Option<SessionState>;
18 fn save(&self, state: &SessionState) -> anyhow::Result<()>;
19}
20
21pub struct MemStore;
23
24impl Store for MemStore {
25 fn load(&self) -> Option<SessionState> {
26 None
27 }
28 fn save(&self, _state: &SessionState) -> anyhow::Result<()> {
29 Ok(())
30 }
31}
32
33#[cfg(feature = "native")]
38pub struct FileStore {
39 path: std::path::PathBuf,
40}
41
42#[cfg(feature = "native")]
43impl FileStore {
44 pub fn new(sources: &[std::path::PathBuf]) -> anyhow::Result<Self> {
46 use std::hash::{Hash, Hasher};
47 let dir = base_dir()?;
48 std::fs::create_dir_all(&dir)?;
49 let mut h = std::collections::hash_map::DefaultHasher::new();
50 for p in sources {
51 std::fs::canonicalize(p)
52 .unwrap_or_else(|_| p.clone())
53 .hash(&mut h);
54 }
55 Ok(FileStore {
56 path: dir.join(format!("{:016x}.session", h.finish())),
57 })
58 }
59}
60
61#[cfg(feature = "native")]
64fn base_dir() -> anyhow::Result<std::path::PathBuf> {
65 let root = if let Some(d) = std::env::var_os("QUARB_CACHE_DIR") {
66 std::path::PathBuf::from(d)
67 } else if let Some(home) = std::env::var_os("HOME") {
68 std::path::PathBuf::from(home).join(".quarb")
69 } else {
70 std::env::temp_dir().join("quarb")
71 };
72 Ok(root.join("quai"))
73}
74
75#[cfg(feature = "native")]
76impl Store for FileStore {
77 fn load(&self) -> Option<SessionState> {
78 let text = std::fs::read_to_string(&self.path).ok()?;
80 let (first, rest) = text.split_once('\n')?;
81 Some(SessionState {
82 line_no: first.trim().parse().ok()?,
83 defs_text: rest.to_string(),
84 })
85 }
86 fn save(&self, state: &SessionState) -> anyhow::Result<()> {
87 std::fs::write(
88 &self.path,
89 format!("{}\n{}", state.line_no, state.defs_text),
90 )?;
91 Ok(())
92 }
93}