vrust 0.0.1

VRust game engine
#[cfg(not(target_os = "android"))]
use std::fs::File as StdFile;
use std::io::{Read, Result, Seek, SeekFrom};
#[cfg(not(target_os = "android"))]
use std::io::BufReader;
use std::mem::{size_of, transmute};
#[cfg(target_os = "android")]
use super::android::asset as aas;

#[derive(Debug)]
pub struct File {
    pub endian_compatible: bool,
    offset: usize,
    #[cfg(not(target_os = "android"))]
    pub reader: BufReader<StdFile>,
    #[cfg(target_os = "android")]
    pub asset: *mut aas::AAsset,
}

impl File {
    #[cfg(target_endian = "big")]
    fn check_endian(&mut self) {
        if self.read_bool() {
            self.endian_compatible = false;
        } else {
            self.endian_compatible = true;
        }
    }

    #[cfg(target_endian = "little")]
    fn check_endian(&mut self) {
        if self.read_bool() {
            self.endian_compatible = true;
        } else {
            self.endian_compatible = false;
        }
    }

    #[cfg(not(target_os = "android"))]
    pub fn new(file_name: &String) -> Self {
        match StdFile::open(file_name) {
            Ok(f) => {
                let mut s = File {
                    endian_compatible: true,
                    offset: 0,
                    reader: BufReader::new(f),
                };
                s.check_endian();
                s
            }
            Err(e) => {
                logf!("Error {:?} in file reading.", e);
            }
        }
    }

    #[cfg(target_os = "android")]
    pub fn new(file_name: &String, asset_manager: *mut aas::AAssetManager) -> Self {
        use std::ffi::CString;
        use std::ptr::null_mut;
        // let file_name: String = file_name.clone();
        let cstr_name = CString::new(file_name.clone().into_bytes()).unwrap();
        let asset = unsafe {
            aas::AAssetManager_open(asset_manager, cstr_name.as_ptr(), aas::AccesMode::O_RDONLY.bits())
        };
        if asset == null_mut() {
            logf!("File {} not found!", file_name);
        }
        let mut file = File {
            endian_compatible: true,
            offset: 0,
            asset: asset,
        };
        file.check_endian();
        return file;
    }

    pub fn read_typed_bytes(&mut self, des: *mut u8, count: usize) {
        let b = self.read_bytes(count);
        if self.endian_compatible {
            for i in 0..count {
                unsafe {
                    *des.offset(i as isize) = b[i];
                }
            }
        } else {
            let mut i = 0isize;
            let mut j = count - 1;
            let count = count as isize;
            while i < count {
                unsafe {
                    *des.offset(i) = b[j];
                }
                i += 1;
                j -= 1;
            }
        }
    }

    pub fn read_bytes(&mut self, count: usize) -> Vec<u8> {
        let mut b = vec![0u8; count];
        let mut read_count = 0;
        while read_count < count {
            let tmp_count = match self.read(&mut b[read_count..count]) {
                Ok(c) => c,
                Err(_) => {
                    logf!("Error in reading stream.");
                }
            };
            read_count += tmp_count;
            if tmp_count == 0 {
                logf!(
                    "Expected bytes count is {} but the read bytes count is {}.",
                    count,
                    read_count
                );
            }
        }
        return b;
    }

    pub fn read_bool(&mut self) -> bool {
        let b = self.read_bytes(1);
        if b[0] == 1 {
            return true;
        }
        return false;
    }

    pub fn read_type<T>(&mut self) -> T
    where
        T: Default,
    {
        let mut r = T::default();
        self.read_typed_bytes(unsafe { transmute(&mut r) }, size_of::<T>());
        r
    }

    pub fn read_id(&mut self) -> u64 {
        self.read_type()
    }

    pub fn read_count(&mut self) -> u64 {
        self.read_type()
    }

    pub fn read_offset(&mut self) -> u64 {
        self.read_type()
    }

    pub fn tell(&self) -> usize {
        return self.offset;
    }

    pub fn goto(&mut self, offset: usize) {
        if offset == self.offset {
            return;
        }
        let _ = self.seek(SeekFrom::Start(offset as u64));
    }
}

impl Read for File {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        #[cfg(not(target_os = "android"))]
        let result = self.reader.read(buf);
        #[cfg(target_os = "android")]
        let result = Ok(unsafe {
            aas::AAsset_read(self.asset, transmute(buf.as_mut_ptr()), buf.len()) as usize
        });
        match result {
            Ok(c) => self.offset += c,
            _ => {
                logf!("Error in reading stream.");
            }
        };
        return result;
    }
}

impl Seek for File {
    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
        #[cfg(not(target_os = "android"))]
        {
            let result = self.reader.seek(pos);
            match result {
                Ok(c) => {
                    self.offset = c as usize;
                }
                _ => {
                    logf!("Error in file seeking!");
                }
            }
            return result;
        }
        #[cfg(target_os = "android")]
        {
            return Ok(match pos {
                SeekFrom::Start(pos) => unsafe {
                    aas::AAsset_seek(self.asset, pos as isize, aas::SeekDir::SEEK_SET.bits()) as u64
                },
                SeekFrom::End(pos) => unsafe {
                    aas::AAsset_seek(self.asset, pos as isize, aas::SeekDir::SEEK_END.bits()) as u64
                },
                SeekFrom::Current(pos) => unsafe {
                    aas::AAsset_seek(self.asset, pos as isize, aas::SeekDir::SEEK_CUR.bits()) as u64
                },
            });
        }
    }
}