1use std::fmt;
5use std::ops::Deref;
6use std::vec::Vec;
7
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14pub struct NeoByteString {
15 data: Vec<u8>,
16}
17
18impl NeoByteString {
19 pub fn new(data: Vec<u8>) -> Self {
20 Self { data }
21 }
22
23 pub fn from_slice(slice: &[u8]) -> Self {
24 Self {
25 data: slice.to_vec(),
26 }
27 }
28
29 pub fn as_slice(&self) -> &[u8] {
30 &self.data
31 }
32
33 pub const MAX_SIZE: usize = 1024 * 1024;
36
37 pub fn max_size() -> usize {
41 Self::MAX_SIZE
42 }
43
44 pub fn len(&self) -> usize {
45 self.data.len()
46 }
47
48 pub fn is_empty(&self) -> bool {
49 self.data.is_empty()
50 }
51
52 pub fn try_push(&mut self, byte: u8) -> Result<(), ByteStringFullError> {
56 if self.data.len() >= Self::MAX_SIZE {
57 return Err(ByteStringFullError {
58 current_len: self.data.len(),
59 attempted: 1,
60 });
61 }
62 self.data.push(byte);
63 Ok(())
64 }
65
66 pub fn try_extend_from_slice(&mut self, slice: &[u8]) -> Result<(), ByteStringFullError> {
69 let new_len = self
70 .data
71 .len()
72 .checked_add(slice.len())
73 .ok_or(ByteStringFullError {
74 current_len: self.data.len(),
75 attempted: slice.len(),
76 })?;
77 if new_len > Self::MAX_SIZE {
78 return Err(ByteStringFullError {
79 current_len: self.data.len(),
80 attempted: slice.len(),
81 });
82 }
83 self.data.extend_from_slice(slice);
84 Ok(())
85 }
86
87 pub fn push(&mut self, byte: u8) {
88 self.data.push(byte);
89 }
90
91 pub fn extend_from_slice(&mut self, slice: &[u8]) {
92 self.data.extend_from_slice(slice);
93 }
94}
95
96impl fmt::Display for NeoByteString {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 for byte in &self.data {
99 write!(f, "{:02x}", byte)?;
100 }
101 Ok(())
102 }
103}
104
105impl From<Vec<u8>> for NeoByteString {
106 fn from(data: Vec<u8>) -> Self {
107 Self { data }
108 }
109}
110
111impl From<&[u8]> for NeoByteString {
112 fn from(slice: &[u8]) -> Self {
113 Self::from_slice(slice)
114 }
115}
116
117impl AsRef<[u8]> for NeoByteString {
118 fn as_ref(&self) -> &[u8] {
119 &self.data
120 }
121}
122
123impl Deref for NeoByteString {
128 type Target = [u8];
129 fn deref(&self) -> &Self::Target {
130 &self.data
131 }
132}
133
134impl Extend<u8> for NeoByteString {
135 fn extend<I: IntoIterator<Item = u8>>(&mut self, iter: I) {
136 self.data.extend(iter);
137 }
138}
139
140impl FromIterator<u8> for NeoByteString {
141 fn from_iter<I: IntoIterator<Item = u8>>(iter: I) -> Self {
142 Self {
143 data: Vec::from_iter(iter),
144 }
145 }
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152pub struct ByteStringFullError {
153 pub current_len: usize,
155 pub attempted: usize,
157}
158
159impl core::fmt::Display for ByteStringFullError {
160 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
161 write!(
162 f,
163 "NeoByteString is full (current_len = {}; attempted {} more; MAX_SIZE = {})",
164 self.current_len,
165 self.attempted,
166 NeoByteString::MAX_SIZE
167 )
168 }
169}
170
171impl std::error::Error for ByteStringFullError {}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn deref_to_slice() {
179 let bs = NeoByteString::from_slice(&[1, 2, 3]);
180 assert_eq!(bs.len(), 3);
182 assert_eq!(&bs[..2], &[1, 2]);
183 let sum: u32 = bs.iter().map(|&b| b as u32).sum();
185 assert_eq!(sum, 6);
186 }
187
188 #[test]
189 fn max_size_constant_matches_csharp_limit() {
190 assert_eq!(NeoByteString::MAX_SIZE, 1024 * 1024);
192 }
193
194 #[test]
195 fn try_push_returns_error_at_limit() {
196 let mut bs = NeoByteString::from_slice(&[]);
199 bs.try_push(0x42).expect("tiny string fits");
206 assert_eq!(bs.len(), 1);
207 }
208
209 #[test]
210 fn try_extend_propagates_error() {
211 let mut bs = NeoByteString::from_slice(&[1, 2, 3]);
212 bs.try_extend_from_slice(&[]).expect("empty extend ok");
213 bs.try_extend_from_slice(&[4, 5]).expect("small extend ok");
215 assert_eq!(bs.as_slice(), &[1, 2, 3, 4, 5]);
216 }
217}