1# arrayref
2
3[![Build Status](https://travis-ci.org/droundy/arrayref.svg?branch=master)](https://travis-ci.org/droundy/arrayref)
4[![Coverage Status](https://coveralls.io/repos/droundy/arrayref/badge.svg?branch=master&service=github)](https://coveralls.io/github/droundy/arrayref?branch=master)
5
6[Documentation](https://docs.rs/arrayref)
7
8This is a very small rust module, which contains just four macros, for
9the taking of array references to slices of... sliceable things.
10These macros (which are awkwardly named) should be perfectly safe, and
11have seen just a tad of code review.
12
13## Why would I want this?
14
15The goal of arrayref is to enable the effective use of APIs that
16involve array references rather than slices, for situations where
17parameters must have a given size.  As an example, consider the
18`byteorder` crate.  This is a very nice crate with a simple API
19containing functions that look like:
20
21```rust
22fn read_u16(buf: &[u8]) -> u16;
23fn write_u16(buf: &mut [u8], n: u16);
24```
25
26Looking at this, you might wonder why they accept a slice reference as
27input.  After all, they always want just two bytes.  These functions
28must panic if given a slice that is too small, which means that unless
29they are inlined, then a runtime bounds-check is forced, even if it
30may be statically known that the input is the right size.
31
32Wouldn't it be nicer if we had functions more like
33
34```rust
35fn read_u16_array(buf: &[u8; 2]) -> u16;
36fn write_u16_array(buf: &mut [u8; 2], n: u16);
37```
38
39The type signature would tell users precisely what size of input is
40required, and the compiler could check at compile time that the input
41is of the appropriate size: this sounds like the zero-cost
42abstractions rust is famous for!  However, there is a catch, which
43arises when you try to *use* these nicer functions, which is that
44usually you are looking at two bytes in a stream.  So, e.g. consider
45that we are working with a hypothetical (and simplified) ipv6 address.
46
47Doing this with our array version (which looks so beautiful in terms
48of accurately describing what we want!) looks terrible:
49
50```rust
51let addr: &[u8; 16] = ...;
52let mut segments = [0u16; 8];
53// array-based API
54for i in 0 .. 8 {
55    let mut two_bytes = [addr[2*i], addr[2*i+1]];
56    segments[i] = read_u16_array(&two_bytes);
57}
58// slice-based API
59for i in 0 .. 8 {
60    segments[i] = read_u16(&addr[2*i..]);
61}
62```
63
64The array-based approach looks way worse.  We need to create a fresh
65copy of the bytes, just so it will be in an array of the proper size!
66Thus the whole "zero-cost abstraction" argument for using array
67references fails.  The trouble is that there is no (safe) way (until
68[RFC 495][1] lands) to obtain an array reference to a portion of a
69larger array or slice.  Doing so is the equivalent of taking a slice
70with a size known at compile time, and ought to be built into the
71language.
72
73[1]: https://github.com/rust-lang/rfcs/blob/master/text/0495-array-pattern-changes.md
74
75The arrayref crate allows you to do this kind of slicing.  So the
76above (very contrived) example can be implemented with array
77references as:
78
79```rust
80let addr: &[u8; 16] = ...;
81let mut segments = [0u16; 8];
82// array-based API with arrayref
83for i in 0 .. 8 {
84    segments[i] = read_u16_array(array_ref![addr,2*i,2]);
85}
86```
87
88Here the `array_ref![addr,2*i,2]` macro allows us to take an array
89reference to a slice consisting of two bytes starting at `2*i`.  Apart
90from the syntax (less nice than slicing), it is essentially the same
91as the slice approach.  However, this code makes explicit the
92need for precisely *two* bytes both in the caller, and in the function
93signature.
94
95This module provides three other macros providing related
96functionality, which you can read about in the
97[documentation](https://droundy.github.io/arrayref).
98
99For an example of how these macros can be used in an actual program,
100see [my rust translation of tweetnacl][2], which uses `arrayref`
101to almost exclusively accept array references in functions, with the
102only exception being those which truly expect data of arbitrary
103length.  In my opinion, the result is code that is far more legible
104than the original C code, since the size of each argument is
105explicit.  Moreover (although I have not tested this), the use of
106array references rather than slices *should* result in far fewer
107bounds checks, since almost all sizes are known at compile time.
108
109[2]: https://github.com/droundy/onionsalt/blob/master/src/crypto.rs
110