Skip to content

Commit 9ccf0a6

Browse files
committed
Refactor I/O and error handling in pyskani._skani
1 parent b5ff2fe commit 9ccf0a6

File tree

2 files changed

+23
-76
lines changed

2 files changed

+23
-76
lines changed

src/pyskani/_skani/lib.rs

Lines changed: 7 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ mod build {
1515
use std::borrow::Cow;
1616
use std::collections::HashMap;
1717
use std::collections::HashSet;
18-
use std::fs::File;
19-
use std::io::BufReader;
2018
use std::io::Read;
2119
use std::path::Path;
2220
use std::path::PathBuf;
@@ -54,17 +52,7 @@ impl DatabaseStorage {
5452
}
5553
DatabaseStorage::Folder(folder) => {
5654
let sketch_path = folder.join(format!("{}.sketch", &sketch.as_ref().file_name));
57-
let writer = match File::create(&sketch_path) {
58-
Ok(writer) => writer,
59-
Err(err) => {
60-
return if let Some(code) = err.raw_os_error() {
61-
let msg = format!("Failed to create {}", sketch_path.display());
62-
Err(PyOSError::new_err((code, msg)))
63-
} else {
64-
Err(PyRuntimeError::new_err(err.to_string()))
65-
}
66-
}
67-
};
55+
let writer = utils::buffered_create(&sketch_path)?;
6856
match bincode::serialize_into(writer, &(params, sketch.as_ref())) {
6957
Ok(()) => Ok(()),
7058
Err(err) => return Err(PyValueError::new_err(err.to_string())),
@@ -82,17 +70,7 @@ impl DatabaseStorage {
8270
},
8371
DatabaseStorage::Folder(path) => {
8472
let entry_path = path.join(format!("{}.sketch", name));
85-
let reader = match File::open(&entry_path).map(BufReader::new) {
86-
Ok(reader) => reader,
87-
Err(err) => {
88-
return if let Some(code) = err.raw_os_error() {
89-
let msg = format!("Failed to open {}", entry_path.display());
90-
Err(PyOSError::new_err((code, msg)))
91-
} else {
92-
Err(PyRuntimeError::new_err(err.to_string()))
93-
}
94-
}
95-
};
73+
let reader = utils::buffered_open(&entry_path)?;
9674
match bincode::deserialize_from::<_, (SketchParams, skani::types::Sketch)>(reader) {
9775
Err(err) => Err(PyValueError::new_err(err.to_string())),
9876
Ok((_, raw_sketch)) => Ok(Cow::Owned(Sketch::from(raw_sketch))),
@@ -103,17 +81,7 @@ impl DatabaseStorage {
10381
Some(entry) => entry,
10482
None => return Err(PyKeyError::new_err(name.to_string())),
10583
};
106-
let mut reader = match File::open(&path.join("sketches.db")).map(BufReader::new) {
107-
Ok(reader) => reader,
108-
Err(err) => {
109-
return if let Some(code) = err.raw_os_error() {
110-
let msg = format!("Failed to open {}", path.display());
111-
Err(PyOSError::new_err((code, msg)))
112-
} else {
113-
Err(PyRuntimeError::new_err(err.to_string()))
114-
}
115-
}
116-
};
84+
let mut reader = utils::buffered_open(&path.join("sketches.db"))?;
11785
let mut buffer = vec![0; entry.length as usize];
11886
reader.seek_relative(entry.offset as i64)?;
11987
reader.read_exact(&mut buffer)?;
@@ -192,18 +160,7 @@ impl Database {
192160
where
193161
P: AsRef<Path>,
194162
{
195-
let writer = match File::create(&path) {
196-
Ok(writer) => writer,
197-
Err(err) => {
198-
return if let Some(code) = err.raw_os_error() {
199-
let msg = format!("Failed to create {}", path.as_ref().display());
200-
Err(PyOSError::new_err((code, msg)))
201-
} else {
202-
Err(PyRuntimeError::new_err(err.to_string()))
203-
}
204-
}
205-
};
206-
163+
let writer = utils::buffered_create(path.as_ref())?;
207164
if let Ok(vec) = self.markers.read() {
208165
let refs = vec.iter().map(|s| s.as_ref()).collect::<Vec<_>>();
209166
match bincode::serialize_into(writer, &(&self.params, &refs)) {
@@ -219,17 +176,7 @@ impl Database {
219176
where
220177
P: AsRef<Path>,
221178
{
222-
let writer = match File::create(path.as_ref()) {
223-
Ok(writer) => writer,
224-
Err(err) => {
225-
return if let Some(code) = err.raw_os_error() {
226-
let msg = format!("Failed to create {}", path.as_ref().display());
227-
Err(PyOSError::new_err((code, msg)))
228-
} else {
229-
Err(PyRuntimeError::new_err(err.to_string()))
230-
}
231-
}
232-
};
179+
let writer = utils::buffered_create(path.as_ref())?;
233180
match bincode::serialize_into(writer, &(&self.params, sketch.as_ref())) {
234181
Ok(()) => Ok(()),
235182
Err(err) => return Err(PyValueError::new_err(err.to_string())),
@@ -304,29 +251,13 @@ impl Database {
304251
#[classmethod]
305252
#[allow(unused)]
306253
pub fn open<'py>(cls: &Bound<'py, PyType>, path: &Bound<'py, PyAny>) -> PyResult<Self> {
307-
macro_rules! open_or_fail {
308-
($path:ident) => {
309-
match File::open(&$path).map(BufReader::new) {
310-
Ok(reader) => reader,
311-
Err(err) => {
312-
return if let Some(code) = err.raw_os_error() {
313-
let msg = format!("Failed to open {}", $path.display());
314-
Err(PyOSError::new_err((code, msg)))
315-
} else {
316-
Err(PyRuntimeError::new_err(err.to_string()))
317-
}
318-
}
319-
}
320-
}
321-
}
322-
323254
// obtain Unicode representation of path
324255
let decoded = self::utils::fsdecode(path)?;
325256
let fspath = Path::new(decoded.to_str()?);
326257

327258
// load marker sketches
328259
let markers_path = fspath.join("markers.bin");
329-
let reader = open_or_fail!(markers_path);
260+
let reader = utils::buffered_open(&markers_path)?;
330261
let (params, raw_markers) =
331262
match bincode::deserialize_from::<_, (SketchParams, Vec<skani::types::Sketch>)>(reader)
332263
{
@@ -339,7 +270,7 @@ impl Database {
339270
let index_path = fspath.join("index.db");
340271
let sketches_path = fspath.join("sketches.db");
341272
if index_path.exists() && sketches_path.exists() {
342-
let reader = open_or_fail!(index_path);
273+
let reader = utils::buffered_open(&index_path)?;
343274
let index = match bincode::deserialize_from::<_, Vec<IndexEntry>>(reader) {
344275
Ok(v) => v.into_iter().map(|entry| (entry.file_name.clone(), entry)).collect::<HashMap<_, _>>(),
345276
Err(err) => return Err(PyValueError::new_err(err.to_string())),

src/pyskani/_skani/utils.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::io::BufReader;
22
use std::fs::File;
3+
use std::io::BufWriter;
34
use std::path::Path;
45

56
use pyo3::buffer::PyBuffer;
@@ -35,6 +36,21 @@ pub fn buffered_open(path: &Path) -> PyResult<BufReader<File>> {
3536
}
3637
}
3738

39+
/// Try to create a file or fail with Python error handling.
40+
pub fn buffered_create(path: &Path) -> PyResult<BufWriter<File>> {
41+
match File::create(&path).map(BufWriter::new) {
42+
Ok(writer) => Ok(writer),
43+
Err(err) => {
44+
return if let Some(code) = err.raw_os_error() {
45+
let msg = format!("Failed to create {}", path.display());
46+
Err(PyOSError::new_err((code, msg)))
47+
} else {
48+
Err(PyRuntimeError::new_err(err.to_string()))
49+
}
50+
}
51+
}
52+
}
53+
3854
pub enum Text {
3955
Bytes(PyBackedBytes),
4056
Str(PyBackedStr),

0 commit comments

Comments
 (0)