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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
<TeXmacs|2.1>
<project|scheme-gnunet.tm>
<style|tmmanual>
<\body>
<chapter|Bytevector slices><index|bytevector slices>
In Scheme, bytes are put in bytevectors. Often, when a procedure needs to
act on a bytevector, it does not need to act on the whole bytevector, but
only on a (contiguous) part of the bytevector. This can be accomplished by
passing the procedure position and length arguments, but this is prone to
errors such as incorrect bounds calculations.
To solve this, <dfn|bytevector slices> are implemented in <scm|(gnu gnunet
utils bv-slice)><index|(gnu gnunet utils bv-slice)>. A bytevector slice is
a structure referring to a bytevector, with a position inside the
bytevector and the length (in bytes) of the bytevector. They can be
accessed with <scm|slice-bv><index|slice-bv>,
<scm|slice-position><index|slice-position> and
<scm|slice-length><index|slice-length> respectively.
<\warning>
The first two procedures, <scm|slice-bv> and <scm|slice-position>, are
considered low-level \V it is intended to, at some point in the future,
replace them with a single pointer. Using them outside low-level code is
recommended against when alternatives are available.
</warning>
Bytevector slices also have a very limited <dfn|capability> system, to
avoid accidental writes when a slice should only be read and to avoid
accidental reads when a slice should only be written. However, this is not
a true capability model, as it can be circumvented by using <scm|slice-bv>
and <scm|bv-slice/read-write> (i.e., slices are forgable) and because the
only possible capabilities (read of write or read-write) are very
coarse-grained; it is impossible to refine it.
<section|Constructing bytevector slices>
<\explain>
<scm|(slice-slice <var|slice>)><index|slice-slice>
<scm|(slice-slice <var|slice> <var|offset>)>
<scm|(slice-slice <var|slice> <var|offset> <var|length>)>
<|explain>
Select a part of the bytevector slice <var|slice>, preserving
capabilities. Start at the byte at index <var|offset> in the old slice
and let the new slice have <var|length> as length.
If <var|offset> is absent, start at index 0. If <var|length> is absent,
select the whole remaining part of <var|slice>.
The new slice must remain within the old slice. If not, an error is
raised <todo|dedicated exception type>.
</explain>
<\explain>
<scm|slice/read-only><index|slice/read-only>,
<scm|slice/write-only><index|slice/write-only>,
<scm|slice/read-write><index|slice/write-only>
<|explain>
These procedures function exactly the same as <scm|slice-slice>, except
that the capabilities are changed to read-only, write-only and read-write
respectively. The old capabilities must be an upper bound on the new
capabilities; capabilities cannot be gained with these procedures. If the
new capabilities exceed the old capabilities, an
<scm|&missing-capabilities> exception is raised, with the
\<#2018\>what\<#2019\> field set to the symbol <scm|slice>.
</explain>
<\explain>
<scm|bv-slice/read-only><index|bv-slice/read-only>,
<scm|bv-slice/write-only><index|bv-slice/write-only>,
<scm|bv-slice/read-write><index|bv-slice/read-write>
<|explain>
These procedures behave like <scm|slice/read-only>,
<scm|slice/write-only> and <scm|slice/read-write>, except that as first
argument they accept a bytevector instead of a bytevector slice. They
also never raise a <scm|&missing-capabilities>.
<\warning>
In the future, <scm|bv-slice/write-only> and <scm|bv-slice/read-write>
could be modified to check if the bytevector is read-only or read-write
(bytevectors that are part of the program text may not be modified in
Guile Scheme).
</warning>
</explain>
<\explain>
<scm|(make-slice/read-write <var|length>)><index|make-slice/read-write>
</explain|Make a fresh, zero-initialised, read-write slice, of length
<var|length>.>
<\explain>
<scm|(slice-copy/read-write <var|original>)><index|slice-copy/read-write>
<scm|(slice-copy/read-only <var|original>)><index|slice-copy/read-only>
<scm|(slice-copy/bytevector <var|original>)><index|slice-copy/bytevector>
<|explain>
<scm|slice-copy/read-write> makes a fresh read-write slice with the same
contents as <var|original>. It requires <var|original> to be readable \U
if not, a <scm|&missing-capabilities> exception is raised, with the
\<#2018\>what\<#2019\> field set to the symbol <scm|original>.
<scm|slice-copy/read-only> behaves the same as
<scm|slice-copy/read-write>, except for returning a read-only slice
instead of a read-write slice.
<scm|slice-copy/bytevector> behave the same as
<scm|slice-copy/read-write>, except for returning a bytevector instead of
a read-write slice.
</explain>
<section|Predicates>
<\explain>
<scm|(slice? <var|object>)>
<|explain>
Return <scm|#true> if <var|object> is a slice, <scm|#false> otherwise.
</explain>
<\explain>
<scm|(slice-readable? <var|slice>)>
</explain|Return <scm|#true> if the slice <var|slice> is readable,
<scm|#false> otherwise.>
<\explain>
<scm|(slice-writable? <var|slice>)>
</explain|Return <scm|#true> if the slice <var|slice> is writable,
<scm|#false> otherwise.>
<\explain>
<scm|(slice-contents-equal? <var|this>
<var|that>)><index|slice-contents-equal?>
<|explain>
Return <scm|#true> if the two readable bytevector slices <var|this> and
<var|that> have the same contents, i.e., they have the same length and
the same octet at each index. If one of the slices is not readable, a
<scm|&missing-capabilities> exception is raised, with the
\<#2018\>what\<#2019\> field set to the name of the argument as a symbol.
If both slices are not readable, it is unspecified whether
\<#2018\>what\<#2019\> is \<#2018\>this\<#2019\> or
\<#2018\>that\<#2019\>.
</explain>
<section|Reading / modifying bytevector slices>
To read the value at a (byte) index in the slice, the procedures
<scm|slice-X-ref><index|slice-X-ref> are used. Likewise, to set the value
at a certain byte index, the procedures
<scm|slice-X-set!><index|slice-X-set!> are used. <scm|X> must be one of the
following:
<\description>
<item*|<scm|u8><index|u8>, u16<index|u16>, u32<index|u32>,
u64<index|u64>>An unsigned 8-bit, 16-bit, 32-bit and 64-bit integer,
respectively. I.e., an (exact) integer in the (closed) range
<math|<around*|[|0,2<rsup|N>-1|]>>, where <math|N> is the number of bits.
<item*|s8<index|s8>, s16<index|s16>, s32<index|s32>, s64<index|s64>>A
signed 8-bit, 16-bit, 32-bit and 64-bit integer, respectively, encoded in
the <hlink|two's complement|https://en.wikipedia.org/wiki/Two%27s_complement>
representation. I.e., an (exact) integer in the (closed) range
<math|<around*|[|-2<rsup|N-1>,2<rsup|N-1>-1|]>>.
<item*|<scm|ieee-double><index|ieee-double>>A <hlink|floating-point
number|https://en.wikipedia.org/wiki/Floating-point>, in
<hlink|IEEE<index|IEEE> binary64/double<index|binary64><index|double>|https://en.wikipedia.org/wiki/Double-precision_floating-point_format>
format.
</description>
Except for <scm|u8> and <scm|s8>, <scm|slice-X-ref> can be called as
<scm|(slice-X-ref slice <var|index> <var|endian>)>, where <var|slice> is
the bytevector slice, <var|index> is the byte index into the slice and
<var|endian> is the <dfn|endianness> according to which the bytes of the
type are ordered. Endianness is part of <scm|(rnrs bytevectors>). For
communication over the network (including communication between clients and
services), big-endian (i.e., <scm|(endianness big)>) is almost always used
in GNUnet.
Except for <scm|u8> and <scm|s8>, <scm|slice-X-set!> can be called as
<scm|(slice-X-ref slice <var|index> <var|endian> <var|value>)>, where
<var|slice>, <var|index> and <var|endian> have the same meaning as for
<scm|slice-X-ref>, and <var|value> is the value to set it to.
<todo|out-of-bounds, range and capabilities exceptions, can <var|value> be
a exact for <scm|ieee-double>>
For <scm|u8> and <scm|s8>, there is only a single byte and hence there is
no endianness. As such, <scm|slice-u8-ref>, <scm|slice-u8-set!>,
<scm|slice-s8-ref> and <scm|slice-s8-set!> do not have an endianness
argument. Aside from that, they behave similarly to the other
<scm|slice-X-ref> and <scm|slice-X-set!> procedures.
<scm|slice-X-ref> requires the slice to be readable, if not, an appropriate
<scm|&missing-capabilities> exception is raised. Likewise,
<scm|slice-X-set!> requires the slice to be writable. Both require the part
of the slice that is being read to be in-bounds.
<section|Quickcheck integration>
The module <scm|(gnu gnunet utils bv-slice-quickcheck)><index|(gnu gnunet
utils bv-slice-quickcheck)> defines a few <em|arbitraries> for use with
Guile-Quickcheck:
<\explain>
<scm|($sized-bytevector-slice/read-write
<var|size>)><index|$sized-bytevector-slice/read-write>
</explain|Arbitrary generating fresh read-write bytevector slices
consisting of <var|size> octets.>
<\explain>
<scm|($sized-bytevector-slice/read-only
<var|size>)><index|$sized-bytevector-slice/read-only>
</explain|Arbitrary generating fresh read-only bytevector slices consisting
of <var|size> octets.>
\ <todo|rename>
</body>
<\initial>
<\collection>
<associate|page-medium|paper>
<associate|save-aux|false>
</collection>
</initial>
|