termusic 0.7.8

Terminal Music and Podcast Player written in Rust. Can download music from youtube(netease/migu/kugou) and then embed lyrics and album photos into mp3/m4a/flac/wav/ogg vorbis files.
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom};

use reqwest::blocking::{get, Response};

use super::super::Cache;

pub struct SeekableRequest {}

impl SeekableRequest {
    pub fn get(url: &str) -> SeekableResponse {
        SeekableResponse::from(get(url).unwrap())
    }
}

pub struct SeekableResponse {
    inner: Response,
    position: usize,
    buffer: Vec<u8>,
}

impl From<Response> for SeekableResponse {
    fn from(inner: Response) -> Self {
        SeekableResponse {
            inner,
            position: 0,
            buffer: Vec::default(),
        }
    }
}

impl Cache for SeekableResponse {
    fn available(&self) -> usize {
        self.buffer.len()
    }

    fn position(&self) -> usize {
        self.position
    }

    fn get(&mut self, index: usize) -> Option<&u8> {
        if self.buffer.len() <= index {
            self.cache_to_index(index);
        }
        self.buffer.get(index)
    }

    fn slice(&mut self, from: usize, to: usize) -> &[u8] {
        if self.buffer.len() <= to {
            self.cache_to_index(to);
        }
        if self.buffer.len() <= from {
            return &[];
        }
        if self.buffer.len() <= to {
            return &self.buffer[from..];
        }
        &self.buffer[from..to]
    }

    #[allow(unused_must_use)]
    fn cache_to_index(&mut self, index: usize) {
        let available = self.buffer.len();
        if index >= available {
            self.read(&mut vec![0u8; index - available]);
        }
    }

    #[allow(unused_must_use)]
    fn cache_to_end(&mut self) {
        self.read_to_end(&mut Vec::default());
    }
}

impl Read for SeekableResponse {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
        Ok(self.inner.read(buf).map(|len| {
            self.buffer.extend(&buf[..len]);
            len
        })?)
    }
}

impl Seek for SeekableResponse {
    fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error> {
        let (position, offset) = match pos {
            SeekFrom::Start(position) => (0, position as i64),
            SeekFrom::Current(position) => (self.position, position),
            SeekFrom::End(position) => (self.buffer.len(), position),
        };
        let position = if offset < 0 {
            position.checked_sub(offset.wrapping_neg() as usize)
        } else {
            position.checked_add(offset as usize)
        };
        match position {
            Some(position) => {
                self.position = position;
                Ok(position as u64)
            }
            None => Err(Error::new(
                ErrorKind::InvalidInput,
                "invalid seek to a negative or overflowing position",
            )),
        }
    }
}