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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//! Where everything sits in the file.
//!
//! ```text
//! +--------------------------------------------------+ 0
//! | header, 16 bytes |
//! +--------------------------------------------------+ 16
//! | sections, back to back, each 8 byte aligned |
//! +--------------------------------------------------+ footer_offset
//! | footer, a run of iris-abi records |
//! +--------------------------------------------------+ len - 56
//! | trailer, 56 bytes |
//! +--------------------------------------------------+ len
//! ```
//!
//! The directory lives at the end rather than the front, because a writer that streams a large
//! dataset does not know how long a section is until it has finished writing it, and the
//! alternative is either buffering the whole thing or seeking back over it. The magic appears at
//! both ends so that a file truncated in the middle is distinguishable from a file that was never
//! an iris container in the first place.
use Tag;
/// The first eight bytes of every container, and the last eight.
///
/// The carriage return and line feed catch a transport that helpfully converts line endings, and
/// the `0x1a` stops a Windows `type` from printing the rest of the file. Both of those are older
/// than most of the people who will read this and both still happen.
pub const MAGIC: = *b"IRIS\r\n\x1a\n";
/// The format major version this build writes and reads.
///
/// A major version goes up when a reader that does not know about the change would get the wrong
/// answer rather than an error.
pub const FORMAT_MAJOR: u16 = 0;
/// The format minor version this build writes.
///
/// A minor version goes up when something is added that an older reader can safely ignore, which in
/// practice means a new footer record or a new field at the end of an existing one.
pub const FORMAT_MINOR: u16 = 1;
/// How wide the header is, in bytes.
pub const HEADER_SIZE: usize = 16;
/// How wide the trailer is, in bytes.
pub const TRAILER_SIZE: usize = 56;
/// The smallest a container can possibly be, which is a header, an empty footer and a trailer.
pub const MIN_SIZE: usize = HEADER_SIZE + TRAILER_SIZE;
/// How wide a digest is, in bytes.
pub const DIGEST_SIZE: usize = 32;
/// The footer record tags.
///
/// These share the `Tag` newtype with the call protocol in `iris-abi` but not its number space. A
/// footer record and a call record never appear in the same byte stream, so there is nothing to
/// collide, and reusing the framing means the skip an unknown record rule is the one that is
/// already written down and already tested.
/// How the schema bytes are encoded.
/// What a section holds.
/// Where the decoder module for a dataset lives.