Documentation
use std::io::{Cursor, Read};
use std::sync::Arc;

use reqwest::{Client, Error as reqwest_Error};
use url::Url;

use crate::asset::{AssetError, AssetFileBox, AssetFileTrait, AssetResult};
use crate::net::Request;

pub struct AssetFileRequest {
    url: Url,
}

impl AssetFileRequest {
    pub fn new(url: Url) -> Self {
        Self {
            url,
        }
    }
}

impl Request for AssetFileRequest {
    type Response = AssetFileBox;
    type Error = reqwest_Error;

    async fn exec(self, client: Client) -> Result<Self::Response, Self::Error> {
        let buf = client.get(self.url)
            .send()
            .await?
            .error_for_status()?
            .bytes()
            .await?;

        Ok(Box::new(AssetFile::new(buf.as_ref())))
    }
}

struct AssetFile {
    buf: Arc<[u8]>,
}

impl AssetFile {
    fn new(buf: &[u8]) -> Self {
        Self {
            buf: Arc::from(buf),
        }
    }
}

impl AssetFileTrait for AssetFile {
    fn read(&self) -> AssetResult<Box<dyn Read + Send + Sync>> {
        Ok(Box::new(Cursor::new(Arc::clone(&self.buf))))
    }

    fn read_str(&self) -> AssetResult<String> {
        Ok(String::from(str::from_utf8(&self.buf).map_err(|_| AssetError::Decode)?))
    }
}