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).unwrap_or_else(|_| p.clone()).hash(&mut h);
52 }
53 Ok(FileStore {
54 path: dir.join(format!("{:016x}.session", h.finish())),
55 })
56 }
57}
58
59#[cfg(feature = "native")]
62fn base_dir() -> anyhow::Result<std::path::PathBuf> {
63 let root = if let Some(d) = std::env::var_os("QUARB_CACHE_DIR") {
64 std::path::PathBuf::from(d)
65 } else if let Some(home) = std::env::var_os("HOME") {
66 std::path::PathBuf::from(home).join(".quarb")
67 } else {
68 std::env::temp_dir().join("quarb")
69 };
70 Ok(root.join("quai"))
71}
72
73#[cfg(feature = "native")]
74impl Store for FileStore {
75 fn load(&self) -> Option<SessionState> {
76 let text = std::fs::read_to_string(&self.path).ok()?;
78 let (first, rest) = text.split_once('\n')?;
79 Some(SessionState {
80 line_no: first.trim().parse().ok()?,
81 defs_text: rest.to_string(),
82 })
83 }
84 fn save(&self, state: &SessionState) -> anyhow::Result<()> {
85 std::fs::write(&self.path, format!("{}\n{}", state.line_no, state.defs_text))?;
86 Ok(())
87 }
88}