ve-tos-rust-sdk 2.0.0

volcengine offical tos rust sdk
Documentation
/*
 * Copyright (2024) Volcengine
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
use std::fmt::Debug;
use std::fs::File;
use std::io::{Cursor, Error, ErrorKind, Read, Seek, SeekFrom};

use crate::constant::DEFAULT_READ_BUFFER_SIZE;
use crate::error::{GenericError, TosError};

pub(crate) fn read_at_most(reader: &mut dyn Read, buf: &mut Vec<u8>, most: usize) -> Result<usize, TosError> {
    if most == 0 {
        return Ok(0);
    }

    let mut temp_buf = [0u8; DEFAULT_READ_BUFFER_SIZE];
    let mut read_total = 0usize;
    loop {
        match reader.read(&mut temp_buf) {
            Err(e) if e.kind() == ErrorKind::Interrupted => continue,
            Err(e) => return Err(TosError::client_error_with_cause("io read error", GenericError::IoError(e.to_string()))),
            Ok(mut read_once) => {
                if read_once == 0 {
                    return Ok(read_total);
                }
                if read_total + read_once > most {
                    read_once = most - read_total;
                }
                buf.extend_from_slice(&temp_buf[0..read_once]);
                read_total += read_once;
                if read_total >= most {
                    return Ok(read_total);
                }
            }
        }
    }
}

pub(crate) trait BuildFileReader: Read + Sized {
    fn new(input: &str) -> Result<(Self, Option<usize>), TosError>;
    fn new_with_offset(input: &str, offset: i64) -> Result<(Self, Option<usize>), TosError>;
}


impl BuildFileReader for InternalReader<File> {
    fn new(input: &str) -> Result<(Self, Option<usize>), TosError> {
        match File::open(input) {
            Ok(fd) => {
                if let Ok(x) = fd.metadata() {
                    let len = x.len() as usize;
                    return Ok((Self { b: fd, total_size: Some(len), read_size: 0 }, Some(len)));
                }
                Ok((Self { b: fd, total_size: None, read_size: 0 }, None))
            }
            Err(e) => Err(TosError::client_error_with_cause("open file error", GenericError::IoError(e.to_string()))),
        }
    }

    fn new_with_offset(input: &str, offset: i64) -> Result<(Self, Option<usize>), TosError> {
        let (mut fd, len) = <Self as BuildFileReader>::new(input)?;
        if offset > 0 {
            if let Err(e) = fd.seek(SeekFrom::Start(offset as u64)) {
                return Err(TosError::client_error_with_cause("seek file error", GenericError::IoError(e.to_string())));
            }
        }
        Ok((fd, len))
    }
}

pub(crate) trait BuildBufferReader: Sized {
    fn new(input: Vec<u8>) -> Result<(Self, usize), TosError>;
}

impl BuildBufferReader for InternalReader<Cursor<Vec<u8>>> {
    fn new(input: Vec<u8>) -> Result<(Self, usize), TosError> {
        let len = input.len();
        Ok(
            (Self {
                b: Cursor::new(input),
                total_size: Some(len),
                read_size: 0,
            }, len)
        )
    }
}

#[derive(Debug)]
pub(crate) struct InternalReader<B> {
    pub(crate) b: B,
    pub(crate) total_size: Option<usize>,
    pub(crate) read_size: usize,
}

impl<B> InternalReader<B> {
    pub(crate) fn new(b: B) -> Self {
        Self {
            b,
            total_size: None,
            read_size: 0,
        }
    }

    pub(crate) fn sized(b: B, len: usize) -> Self {
        Self {
            b,
            total_size: Some(len),
            read_size: 0,
        }
    }
}

impl<B> Read for InternalReader<B> where B: Read {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        if buf.len() == 0 {
            return Ok(0);
        }
        let read_once = self.b.read(buf)?;
        self.read_size += read_once;
        if read_once == 0 {
            if let Some(total_size) = self.total_size {
                if self.read_size < total_size {
                    return Err(Error::new(ErrorKind::UnexpectedEof,
                                          format!("premature end, expected {}, actual {}", total_size, self.read_size)));
                }
            }
        }
        Ok(read_once)
    }
}

impl<B> Seek for InternalReader<B> where B: Seek {
    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
        self.b.seek(pos)
    }

    fn rewind(&mut self) -> std::io::Result<()> {
        self.b.rewind()
    }
    fn stream_position(&mut self) -> std::io::Result<u64> {
        self.b.stream_position()
    }
}

unsafe impl<B> Send for InternalReader<B> where B: Send {}