squinter 0.3.1

Library to interface with SquashFS filesystems
Documentation
use std::io::{Read, Seek, SeekFrom};
use std::cell::{RefCell, RefMut};
use std::rc::Rc;

#[derive(Debug)]
pub struct ReaderMux<R> {
    inner: Rc<RefCell<SharedReader<R>>>,
    next_client_id: usize,
}

#[derive(Debug)]
pub struct SharedReader<R> {
    inner: R,
    active_id: usize,
}

impl<R> ReaderMux<R>
where R: Read + Seek
{
    pub fn new(reader: R) -> Self {
        Self {
            inner: Rc::new(RefCell::new(SharedReader { inner: reader, active_id: 0 })),
            next_client_id: 1,
        }
    }

    pub fn client(&mut self) -> ReaderClient<R> {
        let id = self.next_client_id;
        self.next_client_id += 1;
        ReaderClient {
            inner: self.inner.clone(),
            id,
            pos: 0,
        }
    }

    pub fn into_inner(self) -> R {
        Rc::into_inner(self.inner).unwrap().into_inner().inner
    }
}

#[derive(Debug)]
pub struct ReaderClient<R> {
    inner: Rc<RefCell<SharedReader<R>>>,
    id: usize,
    pos: u64,
}

impl<R> ReaderClient<R>
where R: Seek
{
    fn activate(&self, sr: &mut RefMut<SharedReader<R>>) -> std::io::Result<u64> {
        if sr.active_id != self.id {
            sr.active_id = self.id;
            let new_pos = sr.inner.seek(SeekFrom::Start(self.pos))?;
            assert!(new_pos == self.pos);
            Ok(new_pos)
        } else {
            Ok(self.pos)
        }
    }
}

impl<R> Read for ReaderClient<R>
where R: Read + Seek
{
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        let mut sr = self.inner.borrow_mut();
        self.activate(&mut sr)?;
        let r = sr.inner.read(buf);
        if let Ok(size) = r {
            self.pos += size as u64;
        }
        r
    }
}

impl<R> Seek for ReaderClient<R>
where R: Seek
{
    fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
        let mut sr = self.inner.borrow_mut();
        self.activate(&mut sr)?;
        let r = sr.inner.seek(pos);
        if let Ok(new_pos) = r {
            self.pos = new_pos;
        }
        r
    }
}