Skip to content

Commit 4bf0fe7

Browse files
committed
writer: Borrow values instead of requiring ownership
1 parent 7a31084 commit 4bf0fe7

File tree

5 files changed

+87
-77
lines changed

5 files changed

+87
-77
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ use seeyou_cupx::cup::CupFile;
4848
use seeyou_cupx::CupxWriter;
4949
use std::path::Path;
5050
51-
CupxWriter::new(CupFile::default())
51+
let cup_file = CupFile::default();
52+
53+
CupxWriter::new(&cup_file)
5254
.add_picture("airport.jpg", Path::new("images/airport.jpg"))
5355
.add_picture("runway.jpg", Path::new("images/runway.jpg"))
5456
.write_to_path("output.cupx")?;

benches/cupx_writing.rs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
use criterion::{criterion_group, criterion_main, Criterion};
1+
use criterion::{Criterion, criterion_group, criterion_main};
22
use seeyou_cup::CupFile;
33
use seeyou_cupx::CupxWriter;
4-
use std::hint::black_box;
54
use std::io::Cursor;
6-
use std::path::PathBuf;
5+
use std::path::Path;
76

87
fn bench_write_empty(c: &mut Criterion) {
98
c.bench_function("CupxWriter::write (empty)", |b| {
109
let mut buffer = Vec::with_capacity(10_000);
1110
b.iter(|| {
1211
buffer.clear();
13-
let writer = CupxWriter::new(CupFile::default());
14-
black_box(writer.write(Cursor::new(&mut buffer)).unwrap());
15-
black_box(buffer.len())
12+
let cup_file = CupFile::default();
13+
let writer = CupxWriter::new(&cup_file);
14+
writer.write(Cursor::new(&mut buffer)).unwrap();
1615
})
1716
});
1817
}
@@ -24,10 +23,10 @@ fn bench_write_with_single_picture(c: &mut Criterion) {
2423
let mut buffer = Vec::with_capacity(50_000);
2524
b.iter(|| {
2625
buffer.clear();
27-
let mut writer = CupxWriter::new(CupFile::default());
28-
writer.add_picture("test.jpg", picture_data.clone());
29-
black_box(writer.write(Cursor::new(&mut buffer)).unwrap());
30-
black_box(buffer.len())
26+
let cup_file = CupFile::default();
27+
let mut writer = CupxWriter::new(&cup_file);
28+
writer.add_picture("test.jpg", picture_data.as_slice());
29+
writer.write(Cursor::new(&mut buffer)).unwrap();
3130
})
3231
});
3332
}
@@ -37,10 +36,10 @@ fn bench_write_with_picture_from_path(c: &mut Criterion) {
3736
let mut buffer = Vec::with_capacity(50_000);
3837
b.iter(|| {
3938
buffer.clear();
40-
let mut writer = CupxWriter::new(CupFile::default());
41-
writer.add_picture("2_1034.jpg", PathBuf::from("tests/fixtures/2_1034.jpg"));
42-
black_box(writer.write(Cursor::new(&mut buffer)).unwrap());
43-
black_box(buffer.len())
39+
let cup_file = CupFile::default();
40+
let mut writer = CupxWriter::new(&cup_file);
41+
writer.add_picture("2_1034.jpg", Path::new("tests/fixtures/2_1034.jpg"));
42+
writer.write(Cursor::new(&mut buffer)).unwrap();
4443
})
4544
});
4645
}
@@ -54,12 +53,12 @@ fn bench_write_with_multiple_pictures(c: &mut Criterion) {
5453
let mut buffer = Vec::with_capacity(200_000);
5554
b.iter(|| {
5655
buffer.clear();
57-
let mut writer = CupxWriter::new(CupFile::default());
58-
writer.add_picture("small.jpg", picture_data_small.clone());
59-
writer.add_picture("medium.jpg", picture_data_medium.clone());
60-
writer.add_picture("large.jpg", picture_data_large.clone());
61-
black_box(writer.write(Cursor::new(&mut buffer)).unwrap());
62-
black_box(buffer.len())
56+
let cup_file = CupFile::default();
57+
let mut writer = CupxWriter::new(&cup_file);
58+
writer.add_picture("small.jpg", picture_data_small.as_slice());
59+
writer.add_picture("medium.jpg", picture_data_medium.as_slice());
60+
writer.add_picture("large.jpg", picture_data_large.as_slice());
61+
writer.write(Cursor::new(&mut buffer)).unwrap();
6362
})
6463
});
6564
}

src/writer.rs

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use seeyou_cup::CupFile;
33
use std::collections::HashMap;
44
use std::fs::File;
55
use std::io::{Cursor, Seek, Write};
6-
use std::path::{Path, PathBuf};
6+
use std::path::Path;
77

88
/// A builder for creating CUPX files with waypoint data and pictures.
99
///
@@ -18,46 +18,41 @@ use std::path::{Path, PathBuf};
1818
/// use seeyou_cup::CupFile;
1919
/// # use std::path::Path;
2020
///
21-
/// CupxWriter::new(CupFile::default())
21+
/// # let cup_file = CupFile::default();
22+
/// CupxWriter::new(&cup_file)
2223
/// .add_picture("photo.jpg", Path::new("images/photo.jpg"))
2324
/// .write_to_path("output.cupx")?;
2425
/// # Ok::<(), seeyou_cupx::Error>(())
2526
/// ```
26-
pub struct CupxWriter {
27-
cup_file: CupFile,
28-
pictures: HashMap<String, PictureSource>,
27+
pub struct CupxWriter<'a> {
28+
cup_file: &'a CupFile,
29+
pictures: HashMap<&'a str, PictureSource<'a>>,
2930
}
3031

3132
/// Source of picture data for inclusion in a CUPX file.
3233
///
33-
/// Pictures can be provided either as in-memory byte vectors or as file paths
34+
/// Pictures can be provided either as in-memory byte slices or as file paths
3435
/// that will be read when the CUPX file is written.
35-
pub enum PictureSource {
36-
/// Picture data provided as a byte vector in memory.
37-
Bytes(Vec<u8>),
36+
pub enum PictureSource<'a> {
37+
/// Picture data provided as a borrowed byte slice.
38+
Bytes(&'a [u8]),
3839
/// Picture data will be read from a file at the given path.
39-
Path(PathBuf),
40+
Path(&'a Path),
4041
}
4142

42-
impl From<Vec<u8>> for PictureSource {
43-
fn from(bytes: Vec<u8>) -> Self {
43+
impl<'a> From<&'a [u8]> for PictureSource<'a> {
44+
fn from(bytes: &'a [u8]) -> Self {
4445
PictureSource::Bytes(bytes)
4546
}
4647
}
4748

48-
impl From<PathBuf> for PictureSource {
49-
fn from(path: PathBuf) -> Self {
49+
impl<'a> From<&'a Path> for PictureSource<'a> {
50+
fn from(path: &'a Path) -> Self {
5051
PictureSource::Path(path)
5152
}
5253
}
5354

54-
impl From<&Path> for PictureSource {
55-
fn from(path: &Path) -> Self {
56-
PictureSource::Path(path.to_path_buf())
57-
}
58-
}
59-
60-
impl CupxWriter {
55+
impl<'a> CupxWriter<'a> {
6156
/// Creates a new CUPX writer with the given waypoint/task data.
6257
///
6358
/// Pictures can be added using [`add_picture`](Self::add_picture).
@@ -69,10 +64,10 @@ impl CupxWriter {
6964
/// use seeyou_cup::CupFile;
7065
///
7166
/// let cup_file = CupFile::default();
72-
/// let writer = CupxWriter::new(cup_file);
67+
/// let writer = CupxWriter::new(&cup_file);
7368
/// # Ok::<(), seeyou_cupx::Error>(())
7469
/// ```
75-
pub fn new(cup_file: CupFile) -> Self {
70+
pub fn new(cup_file: &'a CupFile) -> Self {
7671
Self {
7772
cup_file,
7873
pictures: HashMap::new(),
@@ -93,18 +88,20 @@ impl CupxWriter {
9388
/// use seeyou_cup::CupFile;
9489
/// # use std::path::Path;
9590
///
96-
/// CupxWriter::new(CupFile::default())
91+
/// # let cup_file = CupFile::default();
92+
/// # let image_data = vec![0u8; 100];
93+
/// CupxWriter::new(&cup_file)
9794
/// .add_picture("photo1.jpg", Path::new("images/photo1.jpg"))
98-
/// .add_picture("photo2.jpg", vec![0u8; 100])
95+
/// .add_picture("photo2.jpg", &image_data[..])
9996
/// .write_to_path("output.cupx")?;
10097
/// # Ok::<(), seeyou_cupx::Error>(())
10198
/// ```
10299
pub fn add_picture(
103100
&mut self,
104-
filename: impl Into<String>,
105-
source: impl Into<PictureSource>,
101+
filename: &'a str,
102+
source: impl Into<PictureSource<'a>>,
106103
) -> &mut Self {
107-
self.pictures.insert(filename.into(), source.into());
104+
self.pictures.insert(filename, source.into());
108105
self
109106
}
110107

@@ -121,7 +118,7 @@ impl CupxWriter {
121118
pub fn write<W: Write + Seek>(&self, writer: W) -> Result<(), Error> {
122119
for filename in self.pictures.keys() {
123120
if filename.is_empty() || filename.contains('/') || filename.contains('\\') {
124-
return Err(Error::InvalidFilename(filename.clone()));
121+
return Err(Error::InvalidFilename(filename.to_string()));
125122
}
126123
}
127124

@@ -168,7 +165,8 @@ impl CupxWriter {
168165
/// use seeyou_cupx::CupxWriter;
169166
/// use seeyou_cup::CupFile;
170167
///
171-
/// let bytes = CupxWriter::new(CupFile::default()).write_to_vec()?;
168+
/// let cup_file = CupFile::default();
169+
/// let bytes = CupxWriter::new(&cup_file).write_to_vec()?;
172170
/// # Ok::<(), seeyou_cupx::Error>(())
173171
/// ```
174172
///
@@ -190,7 +188,8 @@ impl CupxWriter {
190188
/// use seeyou_cupx::CupxWriter;
191189
/// use seeyou_cup::CupFile;
192190
///
193-
/// CupxWriter::new(CupFile::default()).write_to_path("output.cupx")?;
191+
/// let cup_file = CupFile::default();
192+
/// CupxWriter::new(&cup_file).write_to_path("output.cupx")?;
194193
/// # Ok::<(), seeyou_cupx::Error>(())
195194
/// ```
196195
///

tests/large_cup_file_test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ fn test_large_cup_file() {
1818
}
1919

2020
// Write the CUPX file with a small picture to ensure we have two ZIP archives
21-
let cupx_buffer = CupxWriter::new(cup_file)
22-
.add_picture("test.jpg", b"small test image data".to_vec())
21+
let cupx_buffer = CupxWriter::new(&cup_file)
22+
.add_picture("test.jpg", &b"small test image data"[..])
2323
.write_to_vec()
2424
.unwrap();
2525

tests/writer_test.rs

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ use insta::{assert_binary_snapshot, assert_compact_debug_snapshot};
22
use seeyou_cupx::cup::CupFile;
33
use seeyou_cupx::{CupxFile, CupxWriter};
44
use std::io::{Cursor, Read};
5-
use std::path::PathBuf;
5+
use std::path::Path;
66

77
#[test]
88
fn test_write_empty() {
9-
let buffer = CupxWriter::new(CupFile::default()).write_to_vec().unwrap();
9+
let cup_file = CupFile::default();
10+
let buffer = CupxWriter::new(&cup_file).write_to_vec().unwrap();
1011

1112
let (result, _) = CupxFile::from_reader(Cursor::new(&buffer)).unwrap();
1213
assert_eq!(result.waypoints().len(), 0);
@@ -16,10 +17,11 @@ fn test_write_empty() {
1617

1718
#[test]
1819
fn test_write_with_bytes_picture() {
20+
let cup_file = CupFile::default();
1921
let picture_data = b"fake image data".to_vec();
2022

21-
let buffer = CupxWriter::new(CupFile::default())
22-
.add_picture("test.jpg", picture_data.clone())
23+
let buffer = CupxWriter::new(&cup_file)
24+
.add_picture("test.jpg", &picture_data[..])
2325
.write_to_vec()
2426
.unwrap();
2527

@@ -38,8 +40,9 @@ fn test_write_with_bytes_picture() {
3840

3941
#[test]
4042
fn test_write_with_path_picture() {
41-
let buffer = CupxWriter::new(CupFile::default())
42-
.add_picture("2_1034.jpg", PathBuf::from("tests/fixtures/2_1034.jpg"))
43+
let cup_file = CupFile::default();
44+
let buffer = CupxWriter::new(&cup_file)
45+
.add_picture("2_1034.jpg", Path::new("tests/fixtures/2_1034.jpg"))
4346
.write_to_vec()
4447
.unwrap();
4548

@@ -58,12 +61,13 @@ fn test_write_with_path_picture() {
5861

5962
#[test]
6063
fn test_write_duplicate_filename_replaces() {
64+
let cup_file = CupFile::default();
6165
let first_data = b"first".to_vec();
6266
let second_data = b"second".to_vec();
6367

64-
let buffer = CupxWriter::new(CupFile::default())
65-
.add_picture("test.jpg", first_data)
66-
.add_picture("test.jpg", second_data.clone())
68+
let buffer = CupxWriter::new(&cup_file)
69+
.add_picture("test.jpg", &first_data[..])
70+
.add_picture("test.jpg", &second_data[..])
6771
.write_to_vec()
6872
.unwrap();
6973

@@ -82,10 +86,11 @@ fn test_write_duplicate_filename_replaces() {
8286

8387
#[test]
8488
fn test_write_multiple_pictures() {
85-
let buffer = CupxWriter::new(CupFile::default())
86-
.add_picture("a.jpg", b"data a".to_vec())
87-
.add_picture("b.jpg", b"data b".to_vec())
88-
.add_picture("c.jpg", b"data c".to_vec())
89+
let cup_file = CupFile::default();
90+
let buffer = CupxWriter::new(&cup_file)
91+
.add_picture("a.jpg", &b"data a"[..])
92+
.add_picture("b.jpg", &b"data b"[..])
93+
.add_picture("c.jpg", &b"data c"[..])
8994
.write_to_vec()
9095
.unwrap();
9196

@@ -97,46 +102,51 @@ fn test_write_multiple_pictures() {
97102

98103
#[test]
99104
fn test_write_invalid_filename_empty() {
100-
let result = CupxWriter::new(CupFile::default())
101-
.add_picture("", b"data".to_vec())
105+
let cup_file = CupFile::default();
106+
let result = CupxWriter::new(&cup_file)
107+
.add_picture("", &b"data"[..])
102108
.write_to_vec();
103109

104110
assert_compact_debug_snapshot!(result, @r#"Err(InvalidFilename(""))"#);
105111
}
106112

107113
#[test]
108114
fn test_write_invalid_filename_with_slash() {
109-
let result = CupxWriter::new(CupFile::default())
110-
.add_picture("path/to/file.jpg", b"data".to_vec())
115+
let cup_file = CupFile::default();
116+
let result = CupxWriter::new(&cup_file)
117+
.add_picture("path/to/file.jpg", &b"data"[..])
111118
.write_to_vec();
112119

113120
assert_compact_debug_snapshot!(result, @r#"Err(InvalidFilename("path/to/file.jpg"))"#);
114121
}
115122

116123
#[test]
117124
fn test_write_invalid_filename_with_backslash() {
118-
let result = CupxWriter::new(CupFile::default())
119-
.add_picture("path\\to\\file.jpg", b"data".to_vec())
125+
let cup_file = CupFile::default();
126+
let result = CupxWriter::new(&cup_file)
127+
.add_picture("path\\to\\file.jpg", &b"data"[..])
120128
.write_to_vec();
121129

122130
assert_compact_debug_snapshot!(result, @r#"Err(InvalidFilename("path\\to\\file.jpg"))"#);
123131
}
124132

125133
#[test]
126134
fn test_write_nonexistent_path() {
127-
let result = CupxWriter::new(CupFile::default())
128-
.add_picture("test.jpg", PathBuf::from("nonexistent/file.jpg"))
135+
let cup_file = CupFile::default();
136+
let result = CupxWriter::new(&cup_file)
137+
.add_picture("test.jpg", Path::new("nonexistent/file.jpg"))
129138
.write_to_vec();
130139

131140
assert_compact_debug_snapshot!(result, @r#"Err(Io(Os { code: 2, kind: NotFound, message: "No such file or directory" }))"#);
132141
}
133142

134143
#[test]
135144
fn test_write_to_path() {
145+
let cup_file = CupFile::default();
136146
let temp_path = std::env::temp_dir().join("test_cupx_writer.cupx");
137147

138-
CupxWriter::new(CupFile::default())
139-
.add_picture("test.jpg", b"test data".to_vec())
148+
CupxWriter::new(&cup_file)
149+
.add_picture("test.jpg", &b"test data"[..])
140150
.write_to_path(&temp_path)
141151
.unwrap();
142152

0 commit comments

Comments
 (0)