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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
// Copyright (c) 2022 Nathaniel Bennett
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Extensible interface for converting data to/from wire protocols.
//!
//! The purpose of this crate is to provide a simplified interface for reading from/writing to a
//! buffer of bytes in an efficient and memory-safe way. It provides default implementations for
//! reading/writing primitive types--integers (u8, i32, f64, etc), strings (&str), byte slices
//! and arrays (&[u8; 3]). It also offers extensibilty to other types and more complex structs
//! via traits ([`WireRead`], [`WireWrite`], and their variants).
//!
//! In addition to supporting standard single-slice buffers, this crate provides equivalent
//! support for non-contiguous buffers by means of the [`VectoredReader`] and [`VectoredWriter`],
//! along with corresponding [`VectoredRead`] and [`VectoredWrite`] traits and their variants.
//! Instead of operating on a single slice (`&[u8]`), these operate on a slice of slices
//! (`&[&[u8]]`) and transparently handle reading from/writing to a chunk that spans multiple
//! slices. This can be useful in cases where it is not desirable or feasible to guarantee
//! contiguous memory--ring buffers, two-dimensional arrays, `iovec` API calls,
//! `PACKET_MMAP` buffers and the like.
//!
//! The Reader and Writer data structures exposed by this crate are effectively light-weight
//! wrappers around slices, meaning that they can be created, copied and dropped freely with
//! very little memory overhead.
//!
//! ## Examples
//!
//! To read data from a simple slice:
//!
//! ```rust
//! use wire_rs::{WireError, WireReader};
//!
//! fn read_data<'a>(slice: &'a [u8]) -> Result<(u16, i8, &'a str), WireError> {
//!     let mut reader: WireReader = WireReader::new(slice);
//!     let s1 = reader.read()?;
//!     let s2 = reader.read()?;
//!     let s3 = reader.read_ref(7)?;
//!     Ok((s1, s2, s3))
//! }
//!
//! ```
//!
//! To write data to a slice:
//!
//! ```rust
//! use wire_rs::{WireError, WireWriter};
//!
//! fn write_data(slice: &mut [u8]) -> Result<(), WireError> {
//!     let mut writer: WireWriter = WireWriter::new(slice);
//!     writer.write(&10i32)?;
//!     writer.write_part::<u64, 3>(&0xFFu64)?; // Write the least significant 3 bytes of the given value to the wire (as long as the value will fit)
//!     writer.write("Hello, world!")?;
//!     writer.finalize()?; // Return an error if there were more bytes available on `slice` that we didn't write to
//!     Ok(())
//! }
//!
//! ```
//!
//! To read/write data in little endian:
//!
//! ```rust
//! use wire_rs::{WireReader, WireWriter};
//!
//! fn endianness() {
//!     let default_reader: WireReader = WireReader::new(&[]);
//!     // ^ Big-endian by default (same for WireWriter)
//!     // Note: you may need to explicitly specify the `WireReader` type
//!     // such as in this case to use the default.
//!
//!     let be_reader = WireReader::<true>::new(&[]);
//!     // Explicitly set to big-endian ^
//!
//!     let le_writer = WireWriter::<false>::new(&mut []);
//!     // Explicitly set to little-endian ^
//! }
//!
//! ```

#![cfg_attr(not(feature = "std"), no_std)]

mod reader;
mod writer;

pub use reader::{
    VectoredCursor, VectoredRead, VectoredReadComp, VectoredReadPart, VectoredReadRef,
    VectoredReader, WireCursor, WireRead, WireReadComp, WireReadPart, WireReadRef, WireReader,
};

pub use writer::{
    VectoredBufMut, VectoredCursorMut, VectoredWrite, VectoredWritePart, VectoredWriter,
    WireCursorMut, WireWrite, WireWritePart, WireWriter,
};

use core::convert;
use reader::*;
use writer::*;

/// An error in reading from or writing to a wire.
///
/// New error types may be added to this enum, so it should not be exhaustively matched against.
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum WireError {
    /// Returned when a Reader or Writer contains too few remaining bytes to fully read or write
    /// the desired type.
    InsufficientBytes,
    /// Returned when some bytes remain on the wire after the final data type is read or written.
    ///
    /// The `finalize()` or `finalize_after()` methods can be used to check that all of the slice
    /// passed into a Reader or Writer is used. This is particularly useful for wire protocols
    /// that include a length field at the beginning of a packet that needs to be validated.
    /// When bytes remain in a Reader or Writer and one of the above methods is called, the
    /// `InsufficientBytes` error will be returned.
    ExtraBytes,
    /// Returned when the type being read requires a particular format that the bytes on the
    /// wire do not adhere to, or when the type being written is not within a certain range of
    /// values that can be serialized.
    ///
    /// The latter case can only occur for types that implement either the [`WireWritePart`]
    /// trait or the [`VectoredWritePart`] trait. For example, the following would return an
    /// `InvalidData` error:
    ///
    /// ```rust
    /// use wire_rs::{WireError, WireWriter};
    ///
    /// fn decode_partial_out_of_range() -> Result<(), WireError> {
    ///     let mut buf = [0u8; 4];
    ///     let out_of_range = 0x0100u16;
    ///     let mut writer: WireWriter = WireWriter::new(buf.as_mut_slice());
    ///     writer.write_part::<u16, 1>(&out_of_range) // Returns Err(WireError::InvalidData)
    /// }
    /// ```
    ///
    /// Whereas a number within the range of values that can be encoded for the given size
    /// would return Ok(()):
    ///
    /// ```rust
    /// use wire_rs::{WireError, WireWriter};
    ///
    /// fn decode_partial_within_range() -> Result<(), WireError> {
    ///     let mut buf = [0u8; 4];
    ///     let within_range = 0xFFu64;
    ///     let mut writer: WireWriter = WireWriter::new(buf.as_mut_slice());
    ///     writer.write_part::<u64, 1>(&within_range)
    ///     // Returns Ok(())
    /// }
    /// ```
    ///
    /// As an example of the former case, a Reader would return an error when invalid UTF-8
    /// is read in for a `str` type, such as:
    ///
    /// ```rust
    /// use wire_rs::{WireError, WireReader};
    ///
    /// fn decode_bad_utf8() -> Result<(), WireError> {
    ///     let buf = [0xC3, 0x28]; // Invalid 2-octet UTF-8 sequence
    ///     let mut reader: WireReader = WireReader::new(buf.as_slice());
    ///     let s: &str = reader.read_remaining()?;
    ///     // Returns Err(WireError::InvalidData)
    ///     return Ok(())
    /// }
    /// ```
    InvalidData(&'static str),
    /// An internal error in the Reader or Writer.
    ///
    /// This will not be raised unless there is some bug in the implementation of the Reader of
    /// Writer, most likely caused by an invariant not holding. If encountered, this error should
    /// be counted as a fatal error in (de/)serializing data from the wire, and the Reader or
    /// Writer that returned this error should not be used for subsequent operations.
    Internal,
}

/// An index of a buffer or vectored buffers.
///
/// This type is created from a Wire or Vectored Reader/Writer type.
/// Its primary use is to provide a mechanism for advancing a slice or vectored slice
/// up by the amount consumed by the Reader/Writer without causing any lifetime issues.
///
/// Readers and Writers carry a reference to the buffer they are reading,
/// which means that no mutations can be performed on the referenced buffer while a Reader is
/// in scope. Converting a reader into a `WireIndex` provides a mechanism to drop the Reader
/// while retaining the index that the Reader had reached. Once the buffer has been mutated
/// (e.g. additional data being written into it), a slice of the new contents (starting at the
/// index stored in the `WireIndex`) can be used to create a new Reader. That reader can then
/// continue to extract data from the buffer.
pub struct WireIndex {
    /// The index of which buffer in the set of vectored buffers the reader or writer was at.
    ///
    /// If the given `WireIndex` was created from a [`WireReader`] or [`WireWriter`] and not a
    /// [`VectoredReader`] or [`VectoredWriter`], this value will always be set to 0.
    pub vectored_idx: usize,
    /// The index within the buffer that the reader or writer was at.
    pub slice_idx: usize,
}

impl convert::From<WireReader<'_>> for WireIndex {
    fn from(reader: WireReader<'_>) -> Self {
        WireIndex {
            vectored_idx: 0,
            slice_idx: _internal_wirereader_consumed(&reader),
        }
    }
}

impl convert::From<VectoredReader<'_>> for WireIndex {
    fn from(reader: VectoredReader<'_>) -> Self {
        WireIndex {
            vectored_idx: _internal_vectoredreader_vec_index(&reader),
            slice_idx: _internal_vectoredreader_slice_index(&reader),
        }
    }
}

impl convert::From<WireWriter<'_>> for WireIndex {
    fn from(writer: WireWriter<'_>) -> Self {
        WireIndex {
            vectored_idx: 0,
            slice_idx: _internal_wirewriter_consumed(&writer),
        }
    }
}

impl convert::From<VectoredWriter<'_>> for WireIndex {
    fn from(writer: VectoredWriter<'_>) -> Self {
        WireIndex {
            vectored_idx: _internal_vectoredwriter_vec_index(&writer),
            slice_idx: _internal_vectoredwriter_slice_index(&writer),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    const BUF1_LEN: usize = 16;
    const BUF1: [u8; BUF1_LEN] = [
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f,
    ];

    #[cfg(not(feature = "ioslice"))]
    #[test]
    fn vectored_final_index() {
        let iovec1: [&[u8]; 3] = [&BUF1[BUF1_LEN..], &BUF1[..11], &[]];

        let mut r1 = VectoredReader::new(&iovec1);
        assert!(r1.read() == Ok(0x0001020304050607u64));
        assert!(r1.read() == Ok(0x0809i16));
        assert!(r1.read() == Ok(0x0au8));
        let i1 = WireIndex::from(r1);
        assert!(i1.vectored_idx == 1);
        assert!(i1.slice_idx == 11);

        let mut r1 = VectoredReader::new(&iovec1);
        assert!(r1.read_remaining() == Ok(&BUF1[..11]));
        let i1 = WireIndex::from(r1);
        assert!(i1.vectored_idx == 1);
        assert!(i1.slice_idx == 11);
    }

    #[cfg(not(feature = "ioslice"))]
    #[test]
    fn vectored_empty_index() {
        let iovec1: [&[u8]; 6] = [&[], &[], &BUF1[..4], &[], &BUF1[4..8], &[]];
        let mut r1 = VectoredReader::new(&iovec1);
        let i1 = WireIndex::from(r1);
        assert!(i1.vectored_idx == 0);
        assert!(i1.slice_idx == 0);
        assert!(r1.read::<i128>().is_err());
        let i2 = WireIndex::from(r1);
        assert!(i2.vectored_idx == 0);
        assert!(i2.slice_idx == 0);
        assert!(r1.read::<i32>() == Ok(0x00010203i32));
        let i3 = WireIndex::from(r1);
        assert!(i3.vectored_idx == 2);
        assert!(i3.slice_idx == 4);

        assert!(r1.read::<i32>() == Ok(0x04050607i32));
        assert!(r1.finalize().is_ok());
        let i4 = WireIndex::from(r1);

        assert!(i4.vectored_idx == 4);
        assert!(i4.slice_idx == 4);
    }

    #[cfg(not(feature = "ioslice"))]
    #[test]
    fn vectored_wraparound_empty() {
        let iovec1: [&[u8]; 2] = [&BUF1[BUF1_LEN..], &BUF1[..11]];

        let mut r1 = VectoredReader::new(&iovec1);
        assert!(r1.read::<u128>().is_err());
        let i1 = WireIndex::from(r1);
        assert!(i1.vectored_idx == 0);
        assert!(i1.slice_idx == 0);

        let mut r1 = VectoredReader::new(&iovec1);
        assert!(r1.read::<u8>().is_ok());
        let i1 = WireIndex::from(r1);
        assert!(i1.vectored_idx == 1);
        assert!(i1.slice_idx == 1);

        let iovec2: [&[u8]; 2] = [&BUF1[BUF1_LEN - 4..], &BUF1[..7]];

        let mut r2 = VectoredReader::new(&iovec2);
        assert!(r2.read::<u128>().is_err());
        let i2 = WireIndex::from(r2);
        assert!(i2.vectored_idx == 0);
        assert!(i2.slice_idx == 0);

        let mut r2 = VectoredReader::new(&iovec2);
        assert!(r2.read::<u32>().is_ok());
        let i2 = WireIndex::from(r2);
        assert!(i2.vectored_idx == 0);
        assert!(i2.slice_idx == 4);

        let mut r2 = VectoredReader::new(&iovec2);
        assert!(r2.read::<u8>().is_ok());
        assert!(r2.read::<u32>().is_ok());
        let i2 = WireIndex::from(r2);
        assert!(i2.vectored_idx == 1);
        assert!(i2.slice_idx == 1);
    }

    #[test]
    fn simple_read_finalize() {
        let bytes = [0x12, 0x34, 0x56, 0x78];
        let mut r1: WireReader = WireReader::new(&bytes);

        let val1 = r1.read();
        let val2 = r1.read();
        let val3 = WireReader::finalize_after(r1.read(), &r1);
        //        let i1 = WireIndex::from(r1);

        assert!(val1 == Ok(0x12u8));
        assert!(val2 == Ok(0x34u8));
        assert!(val3 == Ok(0x5678u16));
    }

    #[test]
    fn read_finalize_insufficient_bytes() {
        let bytes = [0x12, 0x34, 0x56, 0x78];
        let mut r1 = WireReader::<true>::new(&bytes);

        let val1 = r1.read();
        let val2 = r1.read();
        let val3: Result<u32, WireError> = WireReader::finalize_after(r1.read(), &r1);

        assert!(val1 == Ok(0x12u8));
        assert!(val2 == Ok(0x34u8));
        assert!(val3 == Err(WireError::InsufficientBytes));
    }

    #[test]
    fn read_str() {
        let bytes = [0x12, 0x34, 0x56, 0x78];
        let mut r1 = WireReader::<true>::new(&bytes);
        let str1 = r1.read_ref(4);

        assert!(str1 == Ok("\x12\x34\x56\x78"));
        assert!(r1.finalize() == Ok(()));
    }

    #[test]
    fn read_nonutf8_str_fail() {
        let bytes = [0x9a, 0xbc, 0xde, 0xf0];
        let mut r1 = WireReader::<true>::new(&bytes);
        let str1 = r1.read_ref::<str>(4);

        assert!(str1.is_err());
        assert!(match str1 {
            Err(WireError::InvalidData(_)) => true,
            _ => false,
        });
    }

    struct CustomWireReadable<'a> {
        a: u8,
        b: &'a str,
    }

    impl<'a> WireReadComp<'a> for CustomWireReadable<'a> {
        fn read_wire_comp<const E: bool>(curs: &mut WireCursor<'a>) -> Result<Self, WireError> {
            // curs needs some stronger functionality

            let a = curs.get_readable::<u8, E>()?;
            let str_len = curs.get_readable::<u16, E>()?;

            Ok(CustomWireReadable {
                a: a,
                b: curs.get_readable_ref::<str, E>(str_len as usize)?,
            })
        }
    }

    #[test]
    fn custom_wire_readable() {
        let bytes = [0x9a, 0x00, 0x05, 0x65, 0x66, 0x67, 0x68, 0x69];
        let c1: CustomWireReadable;

        // c1's lifetime must be bound to `bytes`, not `r1`, so this should be able to compile
        {
            let mut r1 = WireReader::<true>::new(&bytes);
            c1 = r1.read_comp().unwrap_or(CustomWireReadable { a: 0, b: "" });

            assert!(r1.is_empty())
        }

        assert!(c1.a == 0x9a);
        assert!(c1.b == "\x65\x66\x67\x68\x69")
    }
}