pub struct ReadOptions { /* private fields */ }Expand description
Sector format, retry policy, and read speed options for track, streaming, and sector-range reads.
The defaults read audio sectors using the default retry policy and leave the drive’s current read speed unchanged. Use the builder methods to override only the options you need.
Implementations§
Source§impl ReadOptions
impl ReadOptions
Sourcepub fn with_format(self, format: SectorReadFormat) -> Self
pub fn with_format(self, format: SectorReadFormat) -> Self
Select the sector format requested from the drive.
Examples found in repository?
examples/save_data_track.rs (line 99)
92fn stream_track_to_file(
93 reader: &CdReader,
94 toc: &Toc,
95 track_no: u8,
96 format: SectorReadFormat,
97 path: &Path,
98) -> Result<u64, Box<dyn std::error::Error>> {
99 let options = ReadOptions::default().with_format(format);
100 let mut stream = reader.open_track_stream_with_options(toc, track_no, &options)?;
101
102 let total_sectors = stream.total_sectors();
103 let mut writer = BufWriter::new(File::create(path)?);
104 let mut written = 0u64;
105
106 while let Some(chunk) = stream.next_chunk()? {
107 writer.write_all(&chunk)?;
108 written += chunk.len() as u64;
109
110 let done = stream.current_sector();
111 let pct = done as f32 / total_sectors as f32 * 100.0;
112 eprint!("\r {done}/{total_sectors} sectors ({pct:5.1}%)");
113 }
114 eprintln!("\r {total_sectors}/{total_sectors} sectors (100.0%)");
115
116 writer.flush()?;
117 Ok(written)
118}More examples
examples/read_data_track.rs (line 33)
17fn main() -> Result<(), Box<dyn std::error::Error>> {
18 let reader = CdReader::open_default()?;
19 let toc = reader.read_toc()?;
20
21 let data_track = toc
22 .tracks
23 .iter()
24 .find(|t| !t.is_audio)
25 .ok_or("no data track on this disc (need a mixed-mode / enhanced CD)")?;
26
27 let pvd_lba = data_track.start_lba + PVD_SECTOR_OFFSET;
28 println!(
29 "Data track #{} starts at LBA {}; reading PVD at LBA {}\n",
30 data_track.number, data_track.start_lba, pvd_lba
31 );
32
33 let mut options = ReadOptions::default().with_format(SectorReadFormat::Mode1Raw);
34
35 // --- raw read (2352 B) -------------------------------------------------
36 let raw = reader.read_sector_range(pvd_lba, 1, &options)?;
37 if raw.len() != 2352 {
38 return Err(format!("raw read returned {} bytes, expected 2352", raw.len()).into());
39 }
40
41 let sync_ok = raw[0] == 0x00 && raw[1..11].iter().all(|&b| b == 0xFF) && raw[11] == 0x00;
42 let mode = raw[15];
43 println!("raw sync pattern : {}", pass(sync_ok));
44 println!("raw sector mode : Mode {mode}");
45
46 // User data sits after sync(12) + header(4) for Mode 1, and additionally
47 // after an 8-byte subheader for Mode 2 Form 1.
48 let user_offset = match mode {
49 1 => 16,
50 2 => 24,
51 other => return Err(format!("unexpected sector mode {other}").into()),
52 };
53 let raw_user = &raw[user_offset..user_offset + 2048];
54
55 let iso_ok = raw_user[0] == 0x01 && &raw_user[1..6] == b"CD001";
56 println!("ISO 9660 'CD001' : {}", pass(iso_ok));
57
58 // --- cooked read (2048 B) ---------------------------------------------
59 // The cooked format is specifically Mode 1, so only cross-check it there.
60 if mode == 1 {
61 options = options.with_format(SectorReadFormat::Mode1Cooked);
62 let cooked = reader.read_sector_range(pvd_lba, 1, &options)?;
63 if cooked.len() != 2048 {
64 return Err(
65 format!("cooked read returned {} bytes, expected 2048", cooked.len()).into(),
66 );
67 }
68 let matches_raw = cooked == raw_user;
69 println!("cooked == raw[16..]: {}", pass(matches_raw));
70
71 if sync_ok && iso_ok && matches_raw {
72 println!("\nALL CHECKS PASSED — cooked and raw data reads are correct.");
73 return Ok(());
74 }
75 } else {
76 println!(
77 "\nData track is Mode {mode} (e.g. CD-Extra / Mode 2 Form 1). The cooked path \
78 targets Mode 1, so only the raw checks apply here."
79 );
80 if sync_ok && iso_ok {
81 println!("Raw read verified against on-disc ISO structure.");
82 return Ok(());
83 }
84 }
85
86 Err("one or more verification checks FAILED — see output above".into())
87}Sourcepub fn with_retry(self, retry: RetryConfig) -> Self
pub fn with_retry(self, retry: RetryConfig) -> Self
Set the retry policy applied to each read command.
Examples found in repository?
examples/custom_retry.rs (line 31)
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13 let output_dir = common::fresh_output_dir("custom_retry")?;
14 let reader = CdReader::open_default()?;
15 let toc = reader.read_toc()?;
16
17 let first_audio = toc
18 .tracks
19 .iter()
20 .find(|t| t.is_audio)
21 .ok_or("no audio tracks found")?;
22
23 // More attempts, longer backoff, and sector reduction down to 1
24 // for maximum resilience on scratched media.
25 let retry = RetryConfig::default()
26 .with_max_attempts(8)
27 .with_initial_backoff(Duration::from_millis(50))
28 .with_max_backoff(Duration::from_secs(1))
29 .with_chunk_reduction(true)
30 .with_min_sectors_per_read(1);
31 let options = ReadOptions::default().with_retry(retry);
32
33 println!(
34 "Reading track {} with aggressive retry...",
35 first_audio.number
36 );
37 let data = reader.read_track_with_options(&toc, first_audio.number, &options)?;
38
39 let wav = create_wav(data);
40 let output_path = output_dir.join(format!("track{:02}.wav", first_audio.number));
41 std::fs::write(&output_path, wav)?;
42 println!("Saved {}", output_path.display());
43
44 Ok(())
45}Sourcepub fn with_read_speed(self, read_speed: ReadSpeed) -> Self
pub fn with_read_speed(self, read_speed: ReadSpeed) -> Self
Set the read speed to request from the drive. See ReadSpeed for
details. Streaming reads apply this request once when the stream is opened.
§Note
For simplicity, this crate doesn’t restore the previous speed setting.
Examples found in repository?
examples/read_speed.rs (line 36)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8 let reader = CdReader::open_default()?;
9 let toc = reader.read_toc()?;
10
11 let first_audio = toc
12 .tracks
13 .iter()
14 .find(|track| track.is_audio)
15 .ok_or("no audio tracks found")?;
16
17 // Keep "unchanged" immediately after 1x so it tests whether the previous speed
18 // request remains in effect when no new speed command is sent.
19 let speed_tests = [
20 ("1x", ReadSpeed::CustomMultiplier(1)),
21 ("unchanged (after 1x)", ReadSpeed::Unchanged),
22 ("10x", ReadSpeed::CustomMultiplier(10)),
23 ("30x", ReadSpeed::CustomMultiplier(30)),
24 ("optimal", ReadSpeed::Optimal),
25 ];
26
27 println!(
28 "Reading audio track {} {} times\n",
29 first_audio.number,
30 speed_tests.len()
31 );
32
33 let mut timings = Vec::with_capacity(speed_tests.len());
34
35 for (label, read_speed) in speed_tests {
36 let options = ReadOptions::default().with_read_speed(read_speed);
37
38 println!("Reading at {label}...");
39 let started = Instant::now();
40 let data = reader.read_track_with_options(&toc, first_audio.number, &options)?;
41 let elapsed = started.elapsed();
42
43 println!(
44 "Read {} bytes in {:.3} seconds\n",
45 data.len(),
46 elapsed.as_secs_f64()
47 );
48 timings.push((label, elapsed));
49 }
50
51 println!("Timing summary:");
52 for (label, elapsed) in timings {
53 println!(" {label:<22} {:>10.3} seconds", elapsed.as_secs_f64());
54 }
55
56 Ok(())
57}Trait Implementations§
Source§impl Clone for ReadOptions
impl Clone for ReadOptions
Source§fn clone(&self) -> ReadOptions
fn clone(&self) -> ReadOptions
Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreSource§impl Debug for ReadOptions
impl Debug for ReadOptions
Auto Trait Implementations§
impl Freeze for ReadOptions
impl RefUnwindSafe for ReadOptions
impl Send for ReadOptions
impl Sync for ReadOptions
impl Unpin for ReadOptions
impl UnsafeUnpin for ReadOptions
impl UnwindSafe for ReadOptions
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more