1use serde::{de::DeserializeOwned, Serialize};
2use std::{
3 io::Write,
4 sync::{RwLock, RwLockReadGuard, RwLockWriteGuard},
5};
6use std::{
7 ops::{Deref, DerefMut},
8 path::{Path, PathBuf},
9 sync::Arc,
10};
11use thiserror::Error;
12
13#[derive(Error, Debug)]
14pub enum AcidJsonError {
15 #[error("I/O error: {0}")]
16 IoError(#[from] std::io::Error),
17 #[error("JSON parsing error: {0}")]
18 JsonError(#[from] serde_json::Error),
19}
20
21#[derive(Clone, Debug)]
23pub struct AcidJson<T: Serialize + DeserializeOwned + Sync> {
24 cached: Arc<RwLock<T>>,
25 fname: PathBuf,
26}
27
28impl<T: Serialize + DeserializeOwned + Sync> AcidJson<T> {
29 pub fn open(fname: &Path) -> Result<Self, AcidJsonError> {
31 let file_contents = std::fs::read(fname)?;
32 let parsed: T = serde_json::from_slice(&file_contents)?;
33 Ok(Self {
34 cached: RwLock::new(parsed).into(),
35 fname: fname.to_owned(),
36 })
37 }
38
39 pub fn open_or_else(fname: &Path, gen_def: impl FnOnce() -> T) -> Result<Self, AcidJsonError> {
41 if !fname.exists() {
42 std::fs::write(fname, serde_json::to_vec(&gen_def())?)?;
43 }
44 let file_contents = std::fs::read(fname)?;
45 let parsed: T = serde_json::from_slice(&file_contents)?;
46 Ok(Self {
47 cached: RwLock::new(parsed).into(),
48 fname: fname.to_owned(),
49 })
50 }
51
52 pub fn read(&self) -> AcidJsonReadGuard<T> {
54 let inner = self.cached.read().unwrap();
55 AcidJsonReadGuard { inner }
56 }
57
58 pub fn write(&self) -> AcidJsonWriteGuard<T> {
60 let inner = self.cached.write().unwrap();
61 let init_serialized = serde_json::to_vec(inner.deref()).expect("cannot serialize");
62 AcidJsonWriteGuard {
63 inner,
64 fname: self.fname.clone(),
65 init_serialized,
66 }
67 }
68}
69
70pub struct AcidJsonReadGuard<'a, T: Serialize + DeserializeOwned + Sync> {
72 inner: RwLockReadGuard<'a, T>,
73}
74
75impl<'a, T: Serialize + DeserializeOwned + Sync> Deref for AcidJsonReadGuard<'a, T> {
76 type Target = T;
77
78 fn deref(&self) -> &Self::Target {
79 &self.inner
80 }
81}
82
83pub struct AcidJsonWriteGuard<'a, T: Serialize + DeserializeOwned + Sync> {
85 inner: RwLockWriteGuard<'a, T>,
86 fname: PathBuf,
87 init_serialized: Vec<u8>,
88}
89
90impl<'a, T: Serialize + DeserializeOwned + Sync> Deref for AcidJsonWriteGuard<'a, T> {
91 type Target = T;
92
93 fn deref(&self) -> &Self::Target {
94 self.inner.deref()
95 }
96}
97
98impl<'a, T: Serialize + DeserializeOwned + Sync> DerefMut for AcidJsonWriteGuard<'a, T> {
99 fn deref_mut(&mut self) -> &mut Self::Target {
100 self.inner.deref_mut()
101 }
102}
103
104impl<'a, T: Serialize + DeserializeOwned + Sync> Drop for AcidJsonWriteGuard<'a, T> {
105 fn drop(&mut self) {
106 let serialized = serde_json::to_vec(self.inner.deref()).expect("cannot serialize");
107 if serialized != self.init_serialized {
108 atomicwrites::AtomicFile::new(
109 &self.fname,
110 atomicwrites::OverwriteBehavior::AllowOverwrite,
111 )
112 .write(|f| f.write_all(&serialized))
113 .expect("could not write acidjson");
114 log::debug!(
115 "wrote {} bytes to {}",
116 serialized.len(),
117 self.fname.as_os_str().to_string_lossy()
118 );
119 } else {
120 log::debug!("not writing because nothing changed")
121 }
122 }
123}