objstr 0.1.1

File stream abstraction for Rust
Documentation
use core::panic;
use std::{fs::File, io::{Error, ErrorKind, Read as _, Seek as _, SeekFrom, Write as _}};

pub const EMPTY: [u8; 1] = [0; 1];
pub const OP_LEN: u8 = 4;

pub fn write_empty_byte(file: &mut File) {
    let res = file.write(&EMPTY);
    if let Err(e) = res {
        panic!("Failed to write empty byte: {}", e);
    }
    if res.unwrap() != EMPTY.len() {
        panic!("Failed to write empty byte: {}", "Write length mismatch.");
    }
}

pub fn cut(file: &mut File) {
    
    let pos = file.seek(SeekFrom::Current(0));

    if let Err(e) = pos {
        panic!("Failed to cut file: {}", e);
    }

    let pos = pos.unwrap();

    let res = file.set_len(pos);

    if let Err(e) = res {
        panic!("Failed to cut file: {}", e);
    }

    write_empty_byte(file); 
}

pub fn truncate(file: &mut File) {
    let res = file.set_len(0);

    if let Err(e) = res {
        panic!("Failed to truncate file: {}", e);
    }

    write_empty_byte(file);
    jump_stream_start(file);
}

pub fn jump_stream_start(file: &mut File) {
    let res = file.seek(SeekFrom::Start(0));

    if let Err(e) = res {
        panic!("Failed to jump stream start: {}", e);
    }
}

pub fn jump_stream_end(file: &mut File) {
    let res = file.seek(SeekFrom::End(-1));

    if let Err(e) = res {
        panic!("Failed to jump stream end: {}", e);
    }
}

pub fn catch_stream_read(file: &mut File, read: usize, predict: usize, fix_fn: fn(file: &mut File)) -> Result<(), Error> {
    if read != predict {
        fix_fn(file);
        return Err(
            Error::new(
                ErrorKind::UnexpectedEof,
                "Readed data length mismatch."
            )
        );
    }
    Ok(())
}

pub fn write(file: &mut File, data: Vec<u8>) -> Result<(), Error> {

    if data.len() > u32::MAX as usize {
        return Err(
            Error::new(
                ErrorKind::InvalidInput,
                "Data length is too long."
            )
        );
    }

    let mut obj = Vec::new();
    let op = u32::to_be_bytes(data.len() as u32);

    obj.extend_from_slice(&op);
    obj.extend_from_slice(&data);
    obj.extend_from_slice(&op);

    let res = file.write(&obj);

    if let Err(e) = res {
        panic!("Failed to write data: {}", e);
    }

    Ok(())
}

pub fn read(file: &mut File) -> Result<Vec<u8>, Error> {

    let mut len_buf_left: [u8; OP_LEN as usize] = [0; OP_LEN as usize];
    let res = file.read(&mut len_buf_left);

    if let Err(e) = res {
        panic!("Failed to read data: {}", e);
    }

    let res = res.unwrap();

    catch_stream_read(
        file,
        res,
        OP_LEN as usize,
        jump_stream_end
    )?;

    let len_left = u32::from_be_bytes(len_buf_left) as usize;

    let mut data = vec![0; len_left];
    let res = file.read(&mut data);

    if let Err(e) = res {
        panic!("Failed to read data: {}", e);
    }

    let res = res.unwrap();

    let catch = catch_stream_read(
        file,
        res,
        len_left,
        jump_stream_start
    );

    if let Err(e) = catch {
        panic!("Failed to read data: {}", e);
    }

    let mut len_buf_right: [u8; OP_LEN as usize] = [0; OP_LEN as usize];
    let res = file.read(&mut len_buf_right);

    if let Err(e) = res {
        panic!("Failed to read data: {}", e);
    }

    let res = res.unwrap();

    let catch = catch_stream_read(
        file,
        res,
        OP_LEN as usize,
        jump_stream_start
    );

    if let Err(e) = catch {
        panic!("Failed to read data: {}", e);
    }

    let len_right = u32::from_be_bytes(len_buf_right) as usize;
    
    if len_left != len_right {
        panic!("Data length mismatch.");
    }

    Ok(data)
}

pub fn seek_forward(file: &mut File) -> Result<(), Error> {
    let mut len_buf: [u8; OP_LEN as usize] = [0; OP_LEN as usize];

    let res = file.read(&mut len_buf);

    if let Err(e) = res {
        panic!("Failed to read data: {}", e);
    }

    catch_stream_read(
        file,
        res?,
        OP_LEN as usize,
        jump_stream_end
    )?;

    let len = u32::from_be_bytes(len_buf) as i64;

    let catch = file.seek(SeekFrom::Current(len));

    if let Err(e) = catch {
        panic!("Failed to seek forward: {}", e);
    }

    let catch = file.seek(SeekFrom::Current(OP_LEN as i64));

    if let Err(e) = catch {
        panic!("Failed to seek forward: {}", e);
    }

    Ok(())
}

pub fn seek_backward(file: &mut File) -> Result<(), Error> {
    let mut len_buf: [u8; OP_LEN as usize] = [0; OP_LEN as usize];

    let res = file.seek(SeekFrom::Current(-(OP_LEN as i64)));

    if let Err(e) = res {
        if e.kind() == ErrorKind::InvalidInput {
            return Err(
                Error::new(
                    ErrorKind::UnexpectedEof,
                    "Reached stream start."
                )
            )
        }
        panic!("Failed to seek backward: {}", e);
    }

    let res = file.read(&mut len_buf);
    let catch = catch_stream_read(
        file,
        res?,
        OP_LEN as usize,
        jump_stream_start
    );

    if let Err(e) = catch {
        panic!("Failed to seek backward: {}", e);
    }

    let len = u32::from_be_bytes(len_buf) as i64;

    let res =  file.seek(SeekFrom::Current(-len -2*OP_LEN as i64));

    if let Err(e) = res {
        if e.kind() == ErrorKind::InvalidInput {
            return Err(
                Error::new(
                    ErrorKind::UnexpectedEof,
                    "Reached stream start."
                )
            )
        }
        panic!("Failed to seek backward: {}", e);
    }

    Ok(())
}

pub fn seek_forward_n(file: &mut File, n: u64) -> Result<(), Error> {
    for _ in 0..n {
        seek_forward(file)?;
    }
    Ok(())
}

pub fn seek_backward_n(file: &mut File, n: u64) -> Result<(), Error> {
    for _ in 0..n {
        seek_backward(file)?;
    }
    Ok(())
}

pub fn inner_len(file: &mut File) -> Result<u32, Error> {
    let mut len_buf: [u8; OP_LEN as usize] = [0; OP_LEN as usize];
    let res = file.read(&mut len_buf);

    if let Err(e) = res {
        panic!("Failed to read data: {}", e);
    }

    catch_stream_read(
        file,
        res?,
        OP_LEN as usize,
        jump_stream_end
    )?;

    let len = u32::from_be_bytes(len_buf) as u32;

    let res = file.seek(SeekFrom::Current(-(OP_LEN as i64)));

    if let Err(e) = res {
        panic!("Failed to seek backward: {}", e);
    }

    Ok(len)
}

pub fn len_calc(inner_lens: Vec<u32>, op_sets: u8) -> i64 {
    let mut len = 0;
    for inner_len in inner_lens {
        len += inner_len as u64 + 2*OP_LEN as u64;
    }
    let len = len as i64 - OP_LEN as i64 * 2 * op_sets as i64;
    len
}