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
use std::io::{self,Write,BufWriter,Seek,SeekFrom};
use std::fs::File;
use std::path::Path;
use std::marker::PhantomData;
use byteorder::{WriteBytesExt, LittleEndian};
use npy_data::NpyRecord;
const FILLER: &'static [u8] = &[42; 19];
pub struct OutFile<Row: NpyRecord> {
shape_pos: usize,
len: usize,
fw: BufWriter<File>,
_t: PhantomData<Row>
}
impl<Row: NpyRecord> OutFile<Row> {
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let mut fw = BufWriter::new(File::create(path)?);
fw.write(&[0x93u8])?;
fw.write(b"NUMPY")?;
fw.write(&[0x01u8, 0x00])?;
let mut header: Vec<u8> = vec![];
header.extend(&b"{'descr': ["[..]);
for (id, t) in Row::get_dtype() {
if t.shape.len() == 0 {
header.extend(format!("('{}', '{}'), ", id, t.ty).as_bytes());
} else {
let shape_str = t.shape.into_iter().fold(String::new(), |o,n| o + &format!("{},", n));
header.extend(format!("('{}', '{}', ({})), ", id, t.ty, shape_str).as_bytes());
}
}
header.extend(&b"], 'fortran_order': False, 'shape': ("[..]);
let shape_pos = header.len() + 10;
header.extend(FILLER);
header.extend(&b",), }"[..]);
let mut padding: Vec<u8> = vec![];
padding.extend(&::std::iter::repeat(b' ').take(15 - ((header.len() + 10) % 16)).collect::<Vec<_>>());
padding.extend(&[b'\n']);
let len = header.len() + padding.len();
assert! (len <= ::std::u16::MAX as usize);
assert!((len + 10) % 16 == 0);
fw.write_u16::<LittleEndian>(len as u16)?;
fw.write(&header)?;
fw.write(&padding)?;
Ok(OutFile {
shape_pos: shape_pos,
len: 0,
fw: fw,
_t: PhantomData,
})
}
pub fn push(&mut self, row: &Row) -> io::Result<()> {
self.len += 1;
row.write(&mut self.fw)
}
fn close_(&mut self) -> io::Result<()> {
self.fw.seek(SeekFrom::Start(self.shape_pos as u64))?;
let length = format!("{}", self.len);
self.fw.write(length.as_bytes())?;
self.fw.write(&b",), }"[..])?;
self.fw.write(&::std::iter::repeat(b' ').take(FILLER.len() - length.len()).collect::<Vec<_>>())?;
Ok(())
}
pub fn close(mut self) -> io::Result<()> {
self.close_()
}
}
impl<Row: NpyRecord> Drop for OutFile<Row> {
fn drop(&mut self) {
let _ = self.close_();
}
}
pub fn to_file<'a, S, T, P>(filename: P, data: T) -> ::std::io::Result<()> where
P: AsRef<Path>,
S: NpyRecord + 'a,
T: IntoIterator<Item=S> {
let mut of = OutFile::open(filename)?;
for row in data {
of.push(&row)?;
}
of.close()
}