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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use std::io::{Read, Seek, SeekFrom, Write};
use std::mem::size_of;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use failure::{ensure, format_err, Error};
use ndarray::Array1;
use crate::io::private::{ChunkIdentifier, ReadChunk, TypeId, WriteChunk};
use crate::util::padding;
pub trait Norms {
fn norm(&self, idx: usize) -> f32;
}
#[derive(Clone, Debug)]
pub struct NdNorms(pub Array1<f32>);
impl Norms for NdNorms {
fn norm(&self, idx: usize) -> f32 {
self.0[idx]
}
}
impl ReadChunk for NdNorms {
fn read_chunk<R>(read: &mut R) -> Result<Self, Error>
where
R: Read + Seek,
{
let chunk_id = read.read_u32::<LittleEndian>()?;
let chunk_id = ChunkIdentifier::try_from(chunk_id)
.ok_or_else(|| format_err!("Unknown chunk identifier: {}", chunk_id))?;
ensure!(
chunk_id == ChunkIdentifier::NdNorms,
"Cannot read chunk {:?} as NdNorms",
chunk_id
);
read.read_u64::<LittleEndian>()?;
let len = read.read_u64::<LittleEndian>()? as usize;
ensure!(
read.read_u32::<LittleEndian>()? == f32::type_id(),
"Expected single precision floating point matrix for NdNorms."
);
let n_padding = padding::<f32>(read.seek(SeekFrom::Current(0))?);
read.seek(SeekFrom::Current(n_padding as i64))?;
let mut data = vec![0f32; len];
read.read_f32_into::<LittleEndian>(&mut data)?;
Ok(NdNorms(Array1::from_vec(data)))
}
}
impl WriteChunk for NdNorms {
fn chunk_identifier(&self) -> ChunkIdentifier {
ChunkIdentifier::NdNorms
}
fn write_chunk<W>(&self, write: &mut W) -> Result<(), Error>
where
W: Write + Seek,
{
write.write_u32::<LittleEndian>(ChunkIdentifier::NdNorms as u32)?;
let n_padding = padding::<f32>(write.seek(SeekFrom::Current(0))?);
let chunk_len = size_of::<u64>()
+ size_of::<u32>()
+ n_padding as usize
+ (self.0.len() * size_of::<f32>());
write.write_u64::<LittleEndian>(chunk_len as u64)?;
write.write_u64::<LittleEndian>(self.0.len() as u64)?;
write.write_u32::<LittleEndian>(f32::type_id())?;
let padding = vec![0; n_padding as usize];
write.write_all(&padding)?;
for &val in self.0.iter() {
write.write_f32::<LittleEndian>(val)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::io::{Cursor, Read, Seek, SeekFrom};
use byteorder::{LittleEndian, ReadBytesExt};
use ndarray::Array1;
use crate::io::private::{ReadChunk, WriteChunk};
use crate::norms::NdNorms;
const LEN: usize = 100;
fn test_ndnorms() -> NdNorms {
NdNorms(Array1::range(0., LEN as f32, 1.))
}
fn read_chunk_size(read: &mut impl Read) -> u64 {
read.read_u32::<LittleEndian>().unwrap();
read.read_u64::<LittleEndian>().unwrap()
}
#[test]
fn ndnorms_correct_chunk_size() {
let check_arr = test_ndnorms();
let mut cursor = Cursor::new(Vec::new());
check_arr.write_chunk(&mut cursor).unwrap();
cursor.seek(SeekFrom::Start(0)).unwrap();
let chunk_size = read_chunk_size(&mut cursor);
assert_eq!(
cursor.read_to_end(&mut Vec::new()).unwrap(),
chunk_size as usize
);
}
#[test]
fn ndnorms_write_read_roundtrip() {
let check_arr = test_ndnorms();
let mut cursor = Cursor::new(Vec::new());
check_arr.write_chunk(&mut cursor).unwrap();
cursor.seek(SeekFrom::Start(0)).unwrap();
let arr = NdNorms::read_chunk(&mut cursor).unwrap();
assert_eq!(arr.0, check_arr.0);
}
}