1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright (c) 2019 10X Genomics, Inc. All rights reserved.

// Write and read functions to which one passes a File, a ref to a number type
// defining the start of a 'vector' of entries, and the number of entries.
//
// See also crate memmap.

extern crate failure;

use self::failure::Error;
use std::io::Write;

pub trait BinaryInputOutputSafe {}
impl BinaryInputOutputSafe for i8 {}
impl BinaryInputOutputSafe for i16 {}
impl BinaryInputOutputSafe for i32 {}
impl BinaryInputOutputSafe for i64 {}
impl BinaryInputOutputSafe for u8 {}
impl BinaryInputOutputSafe for u16 {}
impl BinaryInputOutputSafe for u32 {}
impl BinaryInputOutputSafe for u64 {}
impl BinaryInputOutputSafe for f32 {}
impl BinaryInputOutputSafe for f64 {}
// i128, u128?

#[allow(dead_code)]
pub fn binary_write_from_ref<T>(f: &mut std::fs::File, p: &T, n: usize) -> Result<(), Error> {
    let raw = p as *const T as *const u8;
    unsafe {
        let sli: &[u8] = std::slice::from_raw_parts(raw, n * (std::mem::size_of::<T>()));
        f.write_all(sli)?;
        Ok(())
    }
}

pub fn binary_read_to_ref<T>(f: &mut std::fs::File, p: &mut T, n: usize) -> Result<(), Error> {
    let raw = p as *mut T as *mut u8;
    unsafe {
        let sli: &mut [u8] = std::slice::from_raw_parts_mut(raw, n * (std::mem::size_of::<T>()));
        // We use read_exact instead of read because read can return less than
        // the full number of bytes, and we observed this on large reads.
        use std::io::Read;
        f.read_exact(sli)?;
    }
    Ok(())
}

// The functions binary_write_vec and binary_read_vec append, either to a file,
// in the first case, or to a vector, in the second case.

#[allow(dead_code)]
pub fn binary_write_vec<T>(f: &mut std::fs::File, x: &Vec<T>) -> Result<(), Error>
where
    T: BinaryInputOutputSafe,
{
    let n = x.len();
    binary_write_from_ref::<usize>(f, &n, 1)?;
    binary_write_from_ref::<T>(f, &x[0], x.len())
}

#[allow(dead_code)]
pub fn binary_read_vec<T>(f: &mut std::fs::File, x: &mut Vec<T>) -> Result<(), Error>
where
    T: BinaryInputOutputSafe,
{
    // Read the vector size.

    let mut n: usize = 0;
    binary_read_to_ref::<usize>(f, &mut n, 1)?;

    // Resize the vector without setting any of its entries.
    // (could use resize_without_setting)

    let len = x.len();
    if len + n > x.capacity() {
        let extra: usize = len + n - x.capacity();
        x.reserve(extra);
    }
    unsafe {
        x.set_len(len + n);
    }

    // Read the vector entries.

    binary_read_to_ref::<T>(f, &mut x[len], n)
}

pub fn _binary_write_vec_vec<T>(f: &mut std::fs::File, x: &Vec<Vec<T>>) -> Result<(), Error>
where
    T: BinaryInputOutputSafe,
{
    let n = x.len();
    binary_write_from_ref::<usize>(f, &n, 1)?;
    for i in 0..n {
        binary_write_vec::<T>(f, &x[i])?;
    }
    Ok(())
}

pub fn _binary_read_vec_vec<T>(f: &mut std::fs::File, x: &mut Vec<Vec<T>>) -> Result<(), Error>
where
    T: BinaryInputOutputSafe,
{
    let mut n: usize = 0;
    binary_read_to_ref::<usize>(f, &mut n, 1)?;
    let len = x.len();
    if len + n > x.capacity() {
        let extra: usize = len + n - x.capacity();
        x.reserve(extra);
    }
    unsafe {
        x.set_len(len + n);
    }
    for i in 0..n {
        binary_read_vec::<T>(f, &mut x[i])?;
    }
    Ok(())
}