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
// Copyright (c) 2021 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
// Use of this source is governed by Apache-2.0 License that can be found
// in the LICENSE file.
use byteorder::{BigEndian, ByteOrder};
use super::utils;
#[allow(clippy::module_name_repetitions)]
#[derive(Debug)]
pub enum ByteArrayError {
OutOfRangeError,
InvalidString(utils::StringError),
}
impl From<utils::StringError> for ByteArrayError {
fn from(e: utils::StringError) -> Self {
Self::InvalidString(e)
}
}
pub struct ByteArray<'a> {
offset: usize,
data: &'a [u8],
}
impl<'a> ByteArray<'a> {
/// Create a new `ByteArray` object based on byte slice.
#[must_use]
pub const fn new(data: &'a [u8]) -> Self {
ByteArray { offset: 0, data }
}
/// Get length of inner byte slice.
#[must_use]
pub const fn len(&self) -> usize {
self.data.len()
}
/// Returns true if byte array is empty.
#[must_use]
pub const fn is_empty(&self) -> bool {
self.data.is_empty()
}
/// Get remaining length of bytes available to read.
///
/// # Panics
///
/// Runs into panic if lenght of inner byte slice is invalid.
#[must_use]
pub const fn remaining_bytes(&self) -> usize {
assert!(self.offset <= self.data.len());
self.data.len() - self.offset
}
/// Read one byte from slice.
///
/// # Errors
///
/// Returns error if the array has no length bytes.
pub fn read_byte(&mut self) -> Result<u8, ByteArrayError> {
let offset = self.offset + 1;
if self.offset > self.data.len() {
Err(ByteArrayError::OutOfRangeError)
} else {
self.offset = offset;
Ok(self.data[self.offset - 1])
}
}
/// Read a u16 value from slice.
///
/// # Errors
///
/// Returns error if the array has no length bytes.
pub fn read_u16(&mut self) -> Result<u16, ByteArrayError> {
Ok(BigEndian::read_u16(self.read_bytes(2)?))
}
/// Read a u32 value from slice.
///
/// # Errors
///
/// Returns error if the array has no length bytes.
pub fn read_u32(&mut self) -> Result<u32, ByteArrayError> {
Ok(BigEndian::read_u32(self.read_bytes(4)?))
}
/// Read an UTF-8 string with `len` from slice.
///
/// # Errors
///
/// Returns error if the array has no length bytes or bytes are not valid utf8 string.
pub fn read_string(&mut self, len: usize) -> Result<String, ByteArrayError> {
let bytes = self.read_bytes(len)?;
utils::to_utf8_string(bytes).map_err(ByteArrayError::from)
}
/// Read a byte array with `len` from slice.
/// # Errors
///
/// Returns error if the array has no length bytes.
pub fn read_bytes(&mut self, len: usize) -> Result<&[u8], ByteArrayError> {
let offset = self.offset + len;
if offset > self.data.len() {
log::error!(
"read_bytes() reading {} bytes, current offset: {}, data len: {}",
len,
self.offset,
self.data.len()
);
Err(ByteArrayError::OutOfRangeError)
} else {
self.offset = offset;
Ok(&self.data[self.offset - len..self.offset])
}
}
/// Reset offset value to 0.
pub fn reset_offset(&mut self) {
self.offset = 0;
}
/// Get current offset.
#[must_use]
pub const fn offset(&self) -> usize {
self.offset
}
}