1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
//! Traits and implementations for lending iterators for hunks and metadata.
//! These APIs should be considered unstable and will be replaced with APIs
//! based around GATs and `LendingIterator` once stabilized. See [rust#44265](https://github.com/rust-lang/rust/issues/44265)
//! for the tracking issue on GAT stabilization.
//!
//! ## Iterating over hunks with `LendingIterator`
//! `LendingIterator` allows a more ergonomic interface to iterate over hunks.
//!```rust
//! use std::fs::File;
//! use std::io::BufReader;
//! use lending_iterator::LendingIterator;
//! use chd::Chd;
//!
//! let mut f = BufReader::new(File::open("file.chd")?);
//! let mut chd = Chd::open(&mut f, None)?;
//!
//! // buffer to store uncompressed hunk data must be the same length as the hunk size.
//! let mut hunk_buf = chd.get_hunksized_buffer();
//! // buffer to store compressed data.
//! let mut cmp_buf = Vec::new();
//! let mut hunks = chd.hunks();
//! while let Some(mut hunk) = hunks.next() {
//! hunk.read_hunk_in(&mut cmp_buf, &mut hunk_buf)?;
//! }
//! ```
//!
//! ## Iterating over metadata with `LendingIterator`
//! LendingIterator allows iterating over metadata without keeping a reference to the source file.
//!```rust
//! use std::fs::File;
//! use std::io::BufReader;
//! use lending_iterator::LendingIterator;
//! use chd::Chd;
//!
//! let mut f = BufReader::new(File::open("file.chd")?);
//! let mut chd = Chd::open(&mut f, None)?;
//! let mut metadata = chd.metadata();
//! while let Some(mut metadata) = metadata.next() {
//! let metadata = metadata.read()?;
//! }
//! ```
use crate::metadata::{Metadata, MetadataRef, MetadataRefs, MetadataTag};
use crate::Result;
use crate::{Chd, Hunk};
use lending_iterator::prelude::*;
use std::io::{Read, Seek};
#[::nougat::gat(Item)]
/// A `LendingIterator` definition re-exported from the [lending-iterator](https://crates.io/crates/lending-iterator)
/// crate. Provides an lending iterator interface with various [adapters](https://docs.rs/lending-iterator/0.1.5/lending_iterator/lending_iterator/adapters/index.html)
/// that map to those from [`Iterator`](core::iter::Iterator).
///
/// This crate defined `LendingIterator` will be replaced once a stabilized trait lands in `std`, and should
/// not be considered stable.
///
pub use lending_iterator::lending_iterator::LendingIterator;
/// An iterator over the hunks of a CHD file.
pub struct Hunks<'a, F: Read + Seek> {
inner: &'a mut Chd<F>,
last_hunk: u32,
current_hunk: u32,
}
impl<'a, F: Read + Seek> Hunks<'a, F> {
pub(crate) fn new(inner: &'a mut Chd<F>) -> Self {
let last_hunk = inner.header().hunk_count();
Hunks {
inner,
last_hunk,
current_hunk: 0,
}
}
}
#[::nougat::gat]
impl<'a, F: Read + Seek> LendingIterator for Hunks<'a, F> {
type Item<'next>
where
Self: 'next,
= Hunk<'next, F>;
fn next(&'_ mut self) -> Option<Hunk<'_, F>> {
if self.current_hunk == self.last_hunk {
return None;
}
let curr = self.current_hunk;
self.current_hunk += 1;
self.inner.hunk(curr).ok()
}
}
/// An iterator over the metadata entries of a CHD file.
pub struct MetadataEntries<'a, F: Read + Seek + 'a> {
inner: MetadataRefs<'a, F>,
}
impl<'a, F: Read + Seek + 'a> MetadataEntries<'a, F> {
pub(crate) fn new(inner: MetadataRefs<'a, F>) -> Self {
MetadataEntries { inner }
}
}
impl<'a, F: Read + Seek + 'a> MetadataEntry<'a, F> {
/// Read the contents of the metadata from the input stream.
pub fn read(&mut self) -> Result<Metadata> {
self.meta_ref.read(self.file)
}
}
/// A metadata entry for a CHD file that has a reference to the source file,
/// allowing read metadata from the stream without an explicit reference.
pub struct MetadataEntry<'a, F: Read + Seek + 'a> {
meta_ref: MetadataRef,
file: &'a mut F,
}
impl<'a, F: Read + Seek + 'a> MetadataTag for MetadataEntry<'a, F> {
fn metatag(&self) -> u32 {
self.meta_ref.metatag()
}
}
#[::nougat::gat]
impl<'a, F: Read + Seek> LendingIterator for MetadataEntries<'a, F> {
type Item<'next>
where
Self: 'next,
= MetadataEntry<'next, F>;
fn next(&'_ mut self) -> Option<Item<'_, Self>> {
let next = self.inner.next();
if let Some(next) = next {
Some(MetadataEntry {
meta_ref: next,
file: self.inner.file,
})
} else {
None
}
}
}