Skip to content

Instantly share code, notes, and snippets.

@scott-wilson
Created February 21, 2018 04:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scott-wilson/3921dcde6677d11f7492afcb6528f0cc to your computer and use it in GitHub Desktop.
Save scott-wilson/3921dcde6677d11f7492afcb6528f0cc to your computer and use it in GitHub Desktop.

Hey, I have a question. I want to build something like the following. I have a trait that defines a bundle. The bundle is a bundle of chunks that can either come from a file, or a cache of chunks (more files). I could store the chunks in a vector in the bundle, but if I have really large files, then the amount of RAM used gets pretty huge, so I want to implement an iterator that can either read from the file and return the chunk, or read from the chunk cache and return the chunk. Right now I'm trying to define something like the following:

trait Bundle {
    fn id(&self) -> &ID;
    fn size(&self) -> u64;
    fn chunks<I: Iterator>(&self) -> Result<I, Error>;
}

pub struct FileBundle<P: AsRef<Path>> {
    id: ID,
    path: P,
    size: u64,
    ids: Vec<ID>,
}

impl<P: AsRef<Path>> Bundle for FileBundle<P> {
    fn id(&self) -> &ID {
        return &self.id;
    }
    fn size(&self) -> u64 {
        return self.size;
    }
    fn chunks<I: Iterator>(&self) -> Result<I, Error> {
        FileChunkInterator::new(&self.path)
    }
}

impl<P: AsRef<Path>> FileBundle<P> {
    pub fn path(&self) -> &P {
        return &self.path;
    }
}

struct FileChunkIterator {
    reader: BufReader<File>,
    buffer: [u8; MAX_CHUNK_SIZE],
}

impl FileChunkIterator {
    pub fn new<P: AsRef<Path>>(path: P) -> Result<FileChunkIterator, Error> {
        let buffer = [0; MAX_CHUNK_SIZE];
        let file = File::open(path)?;
        let reader = BufReader::new(file);

        Ok(FileChunkIterator { reader, buffer })
    }
}

impl Iterator for FileChunkIterator {
    type Item = Result<Chunk, Error>;

    fn next(&mut self) -> Option<Result<Chunk, Error>> {
        match self.reader.read(&mut self.buffer) {
            Ok(chunk_size) => {
                if chunk_size != 0 {
                    Some(Chunk::new(&self.buffer))
                } else {
                    None
                }
            }
            Err(err) => Some(Err(err)),
        }
    }
}

I realize that I probably can't do the FileChunkIterator directly in the chunks, but if I cahnge the signature of the chunks, then it is no longer valid for the trait.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment