1use crate::{
2 config::Config,
3 error::{OpenError, OpenMemoryError, PE},
4 persy::PersyImpl,
5 Persy, Recover,
6};
7use std::{fs, fs::File, path::Path, sync::Arc};
8
9pub struct OpenOptions {
36 truncate: bool,
37 create: bool,
38 create_new: bool,
39 config: Config,
40 prepare: Option<Box<dyn Fn(&Persy) -> Result<(), Box<dyn std::error::Error>>>>,
41 recover: Option<Box<dyn Fn(&Vec<u8>) -> bool>>,
42}
43
44impl OpenOptions {
45 pub fn new() -> OpenOptions {
46 OpenOptions {
47 truncate: false,
48 create: false,
49 create_new: false,
50 config: Config::new(),
51 prepare: None,
52 recover: None,
53 }
54 }
55 pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
57 self.truncate = truncate;
58 self
59 }
60
61 pub fn create(&mut self, create: bool) -> &mut OpenOptions {
63 self.create = create;
64 self
65 }
66
67 pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
69 self.create_new = create_new;
70 self
71 }
72
73 pub fn prepare_with<F>(&mut self, prepare: F) -> &mut OpenOptions
76 where
77 F: Fn(&Persy) -> Result<(), Box<dyn std::error::Error>> + 'static,
78 {
79 self.prepare = Some(Box::new(prepare));
80 self
81 }
82
83 pub fn recover_with<F>(&mut self, recover: F) -> &mut OpenOptions
86 where
87 F: Fn(&Vec<u8>) -> bool + 'static,
88 {
89 self.recover = Some(Box::new(recover));
90 self
91 }
92
93 pub fn config(&mut self, config: Config) -> &mut OpenOptions {
95 self.config = config;
96 self
97 }
98
99 pub fn recover<P>(&mut self, path: P) -> Result<Recover, PE<OpenError>>
102 where
103 P: AsRef<Path>,
104 {
105 let path = path.as_ref();
106 let exists = path.exists();
107
108 let file = fs::OpenOptions::new()
109 .read(true)
110 .write(true)
111 .create(self.create)
112 .create_new(self.create_new)
113 .open(path)?;
114 self.int_recover_file(file, exists)
115 }
116
117 pub fn recover_file(&mut self, file: File) -> Result<Recover, PE<OpenError>> {
120 self.int_recover_file(file, true)
121 }
122 fn int_recover_file(&mut self, file: File, exists: bool) -> Result<Recover, PE<OpenError>> {
125 let must_prepare = !exists || self.truncate;
126
127 let config = self.config.clone();
128
129 if must_prepare {
130 let (persy_impl, recov) = if self.truncate {
131 PersyImpl::truncate_and_open(file, config)?
132 } else {
133 PersyImpl::create_and_open(file, config)?
134 };
135 let p = Arc::new(persy_impl);
136 if let Some(prepare) = &mut self.prepare {
137 let persy = Persy { persy_impl: p.clone() };
138 (prepare)(&persy).map_err(|e| OpenError::InitError(format!("{}", e)))?;
139 }
140 Ok(Recover::new(recov, p))
141 } else if let Some(recover) = &self.recover {
142 let (persy_impl, mut recov) = PersyImpl::open_recover(file, config)?;
143 recov.apply(recover)?;
144 Ok(Recover::new(recov, Arc::new(persy_impl)))
145 } else {
146 let (persy_impl, recov) = PersyImpl::open_recover(file, config)?;
147 Ok(Recover::new(recov, Arc::new(persy_impl)))
148 }
149 }
150
151 pub fn open<P>(&mut self, path: P) -> Result<Persy, PE<OpenError>>
153 where
154 P: AsRef<Path>,
155 {
156 let recover = self.recover(path)?;
157 recover.finalize().map_err(|e| PE::PE(OpenError::from(e.error())))
158 }
159
160 pub fn memory(&mut self) -> Result<Persy, PE<OpenMemoryError>> {
174 let config = self.config.clone();
175 let persy_impl = PersyImpl::memory(config)?;
176 let persy = Persy {
177 persy_impl: Arc::new(persy_impl),
178 };
179 if let Some(prepare) = &mut self.prepare {
180 (prepare)(&persy).map_err(|e| OpenMemoryError::InitError(format!("{}", e)))?;
181 }
182 Ok(persy)
183 }
184}
185
186impl Default for OpenOptions {
187 fn default() -> OpenOptions {
188 OpenOptions::new()
189 }
190}