wire_rs/writer.rs
1// Copyright (c) 2022 Nathaniel Bennett
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use crate::WireError;
10use core::{cmp, mem, str};
11
12#[cfg(feature = "ioslice")]
13use std::io;
14
15#[cfg(feature = "ioslice")]
16pub type VectoredBufMut<'a> = &'a mut [io::IoSliceMut<'a>];
17#[cfg(not(feature = "ioslice"))]
18pub type VectoredBufMut<'a> = &'a mut [&'a mut [u8]];
19
20/// Serialization from a data type to the wire.
21///
22/// A type that implements this trait guarantees that it can be serialized into a
23/// number of bytes that will be written to the provided [`WireCursorMut`]. If the
24/// bytes cannot be written to the wire, an error will be returned.
25pub trait WireWrite {
26 /// Serializes the data type into a number of bytes on the wire, or returns a [`WireError`] on failure.
27 ///
28 /// The generic boolean `E` designates the intended endianness of the data being written. If `E` is set to
29 /// `true`, then the data will be serialized in big endian format; if `false`, it will be serialized
30 /// in little endian.
31 ///
32 /// ## Errors
33 ///
34 /// [`WireError::InsufficientBytes`] - not enough bytes remained on the cursor to write the type to the wire.
35 ///
36 /// [`WireError::Internal`] - an internal error occurred in the `wire-rs` library
37 fn write_wire<const E: bool>(&self, curs: &mut WireCursorMut<'_>) -> Result<(), WireError>;
38}
39
40/// Serialization from a data type to a portion of the wire smaller than the full size of the data type.
41///
42/// A type that implements this trait guarantees that at least a subset of its values can be serialized
43/// into a specified number of bytes (greater than zero but less than the size of the type). The serialized
44/// bytes are written to the supplied [`WireCursorMut`]. For values that cannot be serialized into the number
45/// of bytes specified, the [`WireError::InvalidData`] error should be returned.
46///
47/// This trait is most useful for writing integer values to the wire that can be represented in fewer bytes
48/// than what the data type is capable of storing, such as writing out a `u32` to 3 bytes. The caller must ensure
49/// that the value stored in the data type can fit in the number of bytes specified for the operation to succeed.
50///
51/// Types implementing this trait should also implement [`WireWrite`] for the case where the specified number of bytes
52/// is equal to the size of the type.
53pub trait WireWritePart: Sized {
54 /// Serializes the data type into exactly `L` bytes on the wire. If the data's value exceeds the bounds of
55 /// what can be stored in `L` bytes, this function will return a [`WireError::InvalidData`] error.
56 ///
57 /// As an example, the following function would return an error because the value contained in the
58 /// `u16` can't be represented by a single byte:
59 ///
60 /// ```rust
61 /// use wire_rs::{WireError, WireWriter};
62 ///
63 /// fn decode_partial_out_of_range() -> Result<(), WireError> {
64 /// let mut buf = [0u8; 4];
65 /// let out_of_range = 0x0100u16;
66 /// let mut writer: WireWriter = WireWriter::new(buf.as_mut_slice());
67 /// writer.write_part::<u16, 1>(&out_of_range) // Returns Err(WireError::InvalidData)
68 /// }
69 /// ```
70 ///
71 /// If the `u16` were a value less than or equal to 0xFF, the above function would return an Ok() result.
72 ///
73 /// The generic boolean `E` designates the intended endianness of the data being written. If `E` is set to
74 /// `true`, then the data will be serialized in big endian format; if `false`, it will be serialized in little endian.
75 fn write_wire_part<const L: usize, const E: bool>(
76 &self,
77 curs: &mut WireCursorMut<'_>,
78 ) -> Result<(), WireError>;
79}
80
81/// Serialization from a data type to the vectored wire.
82///
83/// A type that implements this trait guarantees that it can be serialized into a
84/// number of bytes that will be written to the provided [`VectoredCursorMut`]. If the
85/// bytes cannot be written to the vectored wire, an error will be returned.
86pub trait VectoredWrite {
87 /// Serializes the data type into a number of bytes on the vectored wire, or returns a [`WireError`] on failure.
88 ///
89 /// The generic boolean `E` designates the intended endianness of the data being written. If `E` is set to
90 /// `true`, then the data will be serialized in big endian format; if `false`, it will be serialized
91 /// in little endian.
92 ///
93 /// ## Errors
94 ///
95 /// [`WireError::InsufficientBytes`] - not enough bytes remained on the cursor to write the type to the wire.
96 ///
97 /// [`WireError::Internal`] - an internal error occurred in the `wire-rs` library
98 fn write_vectored<const E: bool>(
99 &self,
100 curs: &mut VectoredCursorMut<'_>,
101 ) -> Result<(), WireError>;
102}
103
104/// Serialization from an owned data type to a portion of the vectored wire smaller than what the data type would
105/// normally produce.
106///
107/// This trait is most useful for writing integer values to the vectored wire that can be represented in fewer bytes
108/// than what the data type is capable of storing, such as writing out a `u32` to 3 bytes. The caller must ensure
109/// that the value stored in the data type can fit in the number of bytes specified.
110///
111/// A type implementing this trait must guarantee that any length `L` passed in that is greater than 0 and smaller
112/// than the size of the type can be converted into the type. Types implementing this trait should also implement
113/// [`WireWrite`] for the case where `L` is equal to the size of the type.
114pub trait VectoredWritePart: Sized {
115 /// Serializes the data type into `L` bytes on the vectored wire. If the data's value exceeds the bounds of
116 /// what can be stored in `L` bytes, this function will return a WireError::InvalidData error.
117 ///
118 /// As an example, the following function would return an error because the value contained in the
119 /// `u16` can't be represented by a single byte:
120 ///
121 /// ```rust
122 /// use wire_rs::{WireWriter, WireError};
123 ///
124 /// fn decode_partial_out_of_range() -> Result<(), WireError> {
125 /// let mut buf = [0u8; 4];
126 /// let out_of_range = 0x0100u16;
127 /// let mut writer: WireWriter = WireWriter::new(buf.as_mut_slice());
128 /// writer.write_part::<u16, 1>(&out_of_range) // Returns Err(WireError::InvalidData)
129 /// }
130 /// ```
131 ///
132 /// If the value were <= 0xFF instead, the above function would return an Ok() result.
133 ///
134 /// The generic boolean `E` designates the intended endianness of the data being written. If `E` is set to
135 /// `true`, then the data will be serialized in big endian format; if `false`, it will be serialized in little endian.
136 fn write_vectored_part<const L: usize, const E: bool>(
137 &self,
138 curs: &mut VectoredCursorMut<'_>,
139 ) -> Result<(), WireError>;
140}
141
142/// A cursor that acts as an index over a mutable slice and provides operations to sequentially
143/// write data to it.
144///
145/// When implementing the [`WireWrite`] trait or one of its variants, this cursor provides an
146/// interface for writing data to the wire. When an error is returned by the cursor, it
147/// should be returned by the trait method being implemented. This can be easily accomplished
148/// using the `?` operator.
149///
150/// NOTE: this is an internal structure, and is NOT meant to be used to write data from a wire
151/// in the same manner as a [`WireWriter`]. A `WireWriter` is guaranteed to maintain the index
152/// of its last succesful write if any of its methods return an error, while this cursor may move its
153/// internal index forward by some unspecified amount when an error is encountered.
154pub struct WireCursorMut<'a> {
155 wire: &'a mut [u8],
156 idx: usize,
157}
158
159impl<'a> WireCursorMut<'a> {
160 /// Create a `WireCursorMut` that writes to the given slice `wire`.
161 fn new(wire: &'a mut [u8]) -> Self {
162 WireCursorMut { wire, idx: 0 }
163 }
164
165 /// Advance the cursor's index by the given amount, returning an error if
166 /// there are insufficient bytes on the wire.
167 pub fn advance(&mut self, amount: usize) -> Result<(), WireError> {
168 self.idx = match self.idx.checked_add(amount) {
169 Some(new_idx) if new_idx > self.wire.len() => return Err(WireError::InsufficientBytes),
170 Some(new_idx) => new_idx,
171 None => return Err(WireError::InsufficientBytes),
172 };
173
174 Ok(())
175 }
176
177 /// Advance the cursor's index by the given amount, or to the end of the wire if
178 /// the amount exceeds the number of remaining bytes.
179 pub fn advance_up_to(&mut self, amount: usize) {
180 self.idx = match self.idx.checked_add(amount) {
181 Some(new_idx) => cmp::min(new_idx, self.wire.len()),
182 None => self.wire.len(),
183 };
184 }
185
186 /// Check whether the vectored wire has any remaining bytes that can be written
187 /// to by the cursor.
188 pub fn is_empty(&self) -> bool {
189 self.wire.is_empty()
190 }
191
192 /// Write a slice of bytes to the wire.
193 pub fn put_slice(&mut self, slice: &[u8]) -> Result<(), WireError> {
194 let tmp_slice = match self.wire.get_mut(self.idx..) {
195 Some(s) => s,
196 None => return Err(WireError::Internal), // Invariant: the index should never exceed the bound of the slice
197 };
198
199 if tmp_slice.len() < slice.len() {
200 return Err(WireError::InsufficientBytes);
201 }
202
203 for (a, b) in tmp_slice.iter_mut().zip(slice.iter()) {
204 *a = *b;
205 }
206
207 self.idx += slice.len(); // tmp_slice.len() >= slice.len, so self.idx + slice.len() <= self.wire.len()
208 Ok(())
209 }
210
211 /// Serialize a given type `T` that implements the [`WireWrite`] trait to the wire.
212 ///
213 /// The generic boolean `E` designates the intended endianness of the data being written. If `E` is set to
214 /// `true`, then the data will be serialized in big endian format; if `false`, it will be serialized
215 /// in little endian.
216 pub fn put_writable<T, const E: bool>(&mut self, writable: &T) -> Result<(), WireError>
217 where
218 T: WireWrite + ?Sized,
219 {
220 writable.write_wire::<E>(self)
221 }
222
223 /// Serialize `L` bytes to the wire from a given type `T` that implements the
224 /// [`WireWritePart`] trait.
225 ///
226 /// The generic boolean `E` designates the intended endianness of the data being written. If `E` is set to
227 /// `true`, then the data will be serialized in big endian format; if `false`, it will be serialized
228 /// in little endian.
229 pub fn put_writable_part<T, const L: usize, const E: bool>(
230 &mut self,
231 writable: &T,
232 ) -> Result<(), WireError>
233 where
234 T: WireWritePart,
235 {
236 writable.write_wire_part::<L, E>(self)
237 }
238
239 /// Get the number of bytes remaining on the wire for the given cursor.
240 pub fn remaining(&self) -> usize {
241 self.wire.len().saturating_sub(self.idx)
242 }
243}
244
245/// A cursor that acts as an index over a set of vectored mutable slices and provides
246/// operations to sequentially write data to the slices.
247///
248/// When implementing the [`VectoredWrite`] trait or one of its variants, this cursor provides an
249/// interface for writing data to the vectored wire. When an error is returned by the cursor, it
250/// should be returned by the trait method being implemented. This can be easily accomplished
251/// using the `?` operator.
252///
253/// NOTE: this is an internal structure, and is NOT meant to be used to write data from a wire
254/// in the same manner as a [`WireWriter`]. A `WireWriter` is guaranteed to maintain the index
255/// of its last succesful write if any of its methods return an error, while this cursor may move its
256/// internal index forward by some unspecified amount when an error is encountered.
257pub struct VectoredCursorMut<'a> {
258 wire: VectoredBufMut<'a>,
259 arr_idx: usize,
260 idx: usize,
261}
262
263impl<'a> VectoredCursorMut<'a> {
264 /// Create a `VectoredCursorMut` that writes to the given set of vectored slices `wire`.
265 fn new(wire: VectoredBufMut<'a>) -> Self {
266 VectoredCursorMut {
267 wire,
268 arr_idx: 0,
269 idx: 0,
270 }
271 }
272
273 /// Advance the cursor's index by the given amount, returning an error if there are insufficient bytes
274 /// on the vectored wire.
275 pub fn advance(&mut self, mut amount: usize) -> Result<(), WireError> {
276 while let Some(curr_slice) = self.wire.get(self.arr_idx) {
277 let remaining_slice_len = match curr_slice.len().checked_sub(self.idx) {
278 None => return Err(WireError::Internal), // Invariant: the index should never exceed the bound of the slice
279 Some(0) => {
280 if self.wire.get(self.arr_idx + 1).is_none() {
281 return Err(WireError::InsufficientBytes);
282 }
283
284 self.arr_idx += 1; // Checked above to ensure that self.wire[self.arr_idx + 1] exists
285 self.idx = 0;
286 continue;
287 }
288 Some(l) => l,
289 };
290
291 match amount.checked_sub(remaining_slice_len) {
292 None | Some(0) => {
293 // Invariant: cannot overflow (as you cannot have a slice greater than `usize::MAX`)
294 self.idx += amount; // amount <= curr_slice.len() - self.idx -> self.idx + amount <= curr_slice.len()
295 return Ok(());
296 }
297 Some(new_amount) => {
298 self.arr_idx += 1;
299 self.idx = 0;
300 amount = new_amount;
301 }
302 }
303 }
304
305 Err(WireError::InsufficientBytes)
306 }
307
308 /// Advance the cursor's index by the given amount, or to the end of the vectored wire if the amount
309 /// exceeds the number of remaining bytes.
310 pub fn advance_up_to(&mut self, mut amount: usize) {
311 while let Some(curr_slice) = self.wire.get(self.arr_idx) {
312 let remaining_slice_len = match curr_slice.len().checked_sub(self.idx) {
313 None | Some(0) => {
314 // Invariant: None should never occur, as the index should never exceed the bound of the first slice
315 if self.wire.get(self.arr_idx + 1).is_none() {
316 return;
317 }
318 self.arr_idx += 1; // Checked above to ensure that self.wire[self.arr_idx + 1] exists
319 self.idx = 0;
320 continue;
321 }
322 Some(l) => l,
323 };
324
325 match amount.checked_sub(remaining_slice_len) {
326 Some(0) | None => {
327 // Invariant: cannot overflow (as you cannot have a slice greater than `usize::MAX`)
328 self.idx += amount; // amount < curr_slice.len() - self.idx -> self.idx + amount <= curr_slice.len()
329 return;
330 }
331 Some(new_amount) => {
332 if self.wire.get(self.arr_idx + 1).is_none() {
333 self.idx = curr_slice.len();
334 return;
335 }
336 self.arr_idx += 1; // Checked above to ensure that self.wire[self.arr_idx + 1] exists
337 self.idx = 0;
338 amount = new_amount;
339 }
340 }
341 }
342 }
343
344 /// Check whether the vectored wire has any remaining bytes that can be written to by the cursor.
345 pub fn is_empty(&self) -> bool {
346 let mut tmp_arr_idx = self.arr_idx;
347 let mut tmp_idx = self.idx;
348 while let Some(tmp_slice) = self.wire.get(tmp_arr_idx) {
349 if tmp_idx < tmp_slice.len() {
350 return false;
351 } else if self.wire.get(tmp_arr_idx).is_none() {
352 // tmp_idx == first.len() and we're at the last slice
353 return true;
354 } else {
355 tmp_idx = 0;
356 tmp_arr_idx += 1;
357 }
358 }
359
360 true
361 }
362
363 /// Write a slice of bytes to the wire.
364 pub fn put_slice(&mut self, mut slice: &[u8]) -> Result<(), WireError> {
365 while let Some(curr_slice) = self.wire.get_mut(self.arr_idx) {
366 let wire_remaining = match curr_slice.get_mut(self.idx..) {
367 Some(s) => s,
368 None => return Err(WireError::Internal), // Invariant: the index can never exceed the bound of the slice
369 };
370
371 for (a, b) in wire_remaining.iter_mut().zip(slice.iter()) {
372 *a = *b;
373 }
374
375 let num_read = cmp::min(wire_remaining.len(), slice.len());
376 match slice.get(num_read..) {
377 Some(&[]) => {
378 self.idx += num_read;
379 return Ok(());
380 }
381 Some(s) => {
382 if self.wire.get(self.arr_idx + 1).is_none() {
383 return Err(WireError::InsufficientBytes);
384 }
385 slice = s;
386 self.arr_idx += 1; // Checked above to ensure that self.wire[self.arr_idx + 1] exists
387 self.idx = 0;
388 }
389 None => return Err(WireError::Internal), // Invariant: num_read cannot exceed slice.len()
390 }
391 }
392
393 Err(WireError::InsufficientBytes)
394 }
395
396 /// Serialize a given type `T` that implements the [`WireWrite`] trait to the wire.
397 ///
398 /// The generic boolean `E` designates the intended endianness of the data being written. If `E` is set to
399 /// `true`, then the data will be serialized in big endian format; if `false`, it will be serialized
400 /// in little endian.
401 pub fn put_writable<T, const E: bool>(&mut self, writable: &T) -> Result<(), WireError>
402 where
403 T: VectoredWrite + ?Sized,
404 {
405 writable.write_vectored::<E>(self)
406 }
407
408 /// Serialize `L` bytes to the wire from a given type `T` that implements the [`WireWritePart`]
409 /// trait.
410 ///
411 /// The generic boolean `E` designates the intended endianness of the data being written. If `E` is set to
412 /// `true`, then the data will be serialized in big endian format; if `false`, it will be serialized
413 /// in little endian.
414 pub fn put_writable_part<T, const L: usize, const E: bool>(
415 &mut self,
416 writable: &T,
417 ) -> Result<(), WireError>
418 where
419 T: VectoredWritePart,
420 {
421 writable.write_vectored_part::<L, E>(self)
422 }
423
424 /// Get the number of bytes remaining on the wire for the given cursor.
425 pub fn remaining(&self) -> usize {
426 self.wire
427 .iter()
428 .map(|s| s.len())
429 .sum::<usize>()
430 .saturating_sub(self.idx)
431 }
432}
433
434pub struct WireWriter<'a, const E: bool = true> {
435 curs: WireCursorMut<'a>,
436 initial_len: usize,
437}
438
439impl<'a, const E: bool> WireWriter<'a, E> {
440 /// Create a `WireWriter` that can write data types sequentially to the `bytes` slice.
441 pub fn new(bytes: &'a mut [u8]) -> Self {
442 let initial_len = bytes.len();
443 WireWriter {
444 curs: WireCursorMut::new(bytes),
445 initial_len,
446 }
447 }
448
449 /// Advance the writer's index forward by the given amount of bytes, returning an error if there are insufficient
450 /// bytes on the wire to do so.
451 pub fn advance(&mut self, amount: usize) -> Result<(), WireError> {
452 let prev_idx = self.curs.idx;
453 let res = self.curs.advance(amount);
454 if res.is_err() {
455 self.curs.idx = prev_idx;
456 }
457 res
458 }
459
460 /// Advance the writer's index forward by the given number of bytes, or to the end of the wire if the amount
461 /// exceeds the number of remaining bytes.
462 pub fn advance_up_to(&mut self, amount: usize) {
463 self.curs.advance_up_to(amount);
464 }
465
466 /// Check if the writer has no more bytes left on the wire that can be written to. If any
467 /// bytes remain, return [`WireError::ExtraBytes`]; otherwise, return Ok().
468 pub fn finalize(&self) -> Result<(), WireError> {
469 if !self.is_empty() {
470 Err(WireError::ExtraBytes)
471 } else {
472 Ok(())
473 }
474 }
475
476 /// Check if the writer has no more bytes left on the wire that can be written to after
477 /// the given action. If any bytes remain, return [`WireError::ExtraBytes`]; otherwise,
478 /// return Ok().
479 pub fn finalize_after<T>(
480 action: Result<(), WireError>,
481 reader: &Self,
482 ) -> Result<(), WireError> {
483 if action.is_ok() {
484 reader.finalize()?;
485 }
486 action
487 }
488
489 /// Check whether the writer has any remaining bytes that can be written to.
490 pub fn is_empty(&self) -> bool {
491 self.curs.is_empty()
492 }
493
494 /// Write the given data type `writable` to the wire.
495 pub fn write<T>(&mut self, writable: &T) -> Result<(), WireError>
496 where
497 T: WireWrite + ?Sized,
498 {
499 let temp_idx = self.curs.idx;
500 let res = writable.write_wire::<E>(&mut self.curs);
501 if res.is_err() {
502 self.curs.idx = temp_idx;
503 }
504 res
505 }
506
507 /// Write the given data type `writable` to `L` bytes on the wire.
508 pub fn write_part<T, const L: usize>(&mut self, writable: &T) -> Result<(), WireError>
509 where
510 T: WireWritePart,
511 {
512 let temp_idx = self.curs.idx;
513 let res = writable.write_wire_part::<L, E>(&mut self.curs);
514 if res.is_err() {
515 self.curs.idx = temp_idx;
516 }
517 res
518 }
519}
520
521pub fn _internal_wirewriter_consumed(writer: &WireWriter<'_>) -> usize {
522 writer.initial_len - writer.curs.remaining()
523}
524
525pub struct VectoredWriter<'a, const E: bool = true> {
526 curs: VectoredCursorMut<'a>,
527}
528
529impl<'a, const E: bool> VectoredWriter<'a, E> {
530 /// Create a `VectoredWriter` that can write data types sequentially to the vectored `bytes` slice.
531 pub fn new(bytes: VectoredBufMut<'a>) -> Self {
532 VectoredWriter {
533 curs: VectoredCursorMut::new(bytes),
534 }
535 }
536
537 /// Advance the writer's index forward by the given amount of bytes, returning an error if there are insufficient
538 /// bytes on the wire to do so.
539 pub fn advance(&mut self, amount: usize) -> Result<(), WireError> {
540 let temp_arr_idx = self.curs.arr_idx;
541 let temp_idx = self.curs.idx;
542 let res = self.curs.advance(amount);
543 if res.is_err() {
544 self.curs.arr_idx = temp_arr_idx;
545 self.curs.idx = temp_idx;
546 }
547 res
548 }
549
550 /// Advance the writer's index forward by the given number of bytes, or to the end of the vectored
551 /// wire if the amount exceeds the number of remaining bytes.
552 pub fn advance_up_to(&mut self, index: usize) {
553 self.curs.advance_up_to(index);
554 }
555
556 /// Check if the writer has no more bytes left on the vectored wire that can be written
557 /// to. If any bytes remain, return [`WireError::ExtraBytes`]; otherwise, return Ok().
558 pub fn finalize(&self) -> Result<(), WireError> {
559 if self.is_empty() {
560 Ok(())
561 } else {
562 Err(WireError::ExtraBytes)
563 }
564 }
565
566 /// Check if the writer has no more bytes left on the vectored wire that can be written
567 /// to after the given action. If any bytes remain, return [`WireError::ExtraBytes`];
568 /// otherwise, return Ok().
569 pub fn finalize_after<T>(
570 action: Result<(), WireError>,
571 reader: &Self,
572 ) -> Result<(), WireError> {
573 if action.is_ok() {
574 reader.finalize()?;
575 }
576 action
577 }
578
579 /// Check whether the writer has any remaining bytes that can be written to.
580 pub fn is_empty(&self) -> bool {
581 self.curs.is_empty()
582 }
583
584 /// Write the given data type `writable` to the vectored wire.
585 pub fn write<T>(&mut self, writable: &T) -> Result<(), WireError>
586 where
587 T: VectoredWrite + ?Sized,
588 {
589 let temp_arr_idx = self.curs.arr_idx;
590 let temp_idx = self.curs.idx;
591 let res = writable.write_vectored::<E>(&mut self.curs);
592 if res.is_err() {
593 self.curs.arr_idx = temp_arr_idx;
594 self.curs.idx = temp_idx;
595 }
596 res
597 }
598
599 /// Write the given data type `writable` to `L` bytes on the vectored wire.
600 pub fn write_part<T, const L: usize>(&mut self, writable: &T) -> Result<(), WireError>
601 where
602 T: VectoredWritePart,
603 {
604 let temp_arr_idx = self.curs.arr_idx;
605 let temp_idx = self.curs.idx;
606 let res = writable.write_vectored_part::<L, E>(&mut self.curs);
607 if res.is_err() {
608 self.curs.arr_idx = temp_arr_idx;
609 self.curs.idx = temp_idx;
610 }
611 res
612 }
613}
614
615pub fn _internal_vectoredwriter_vec_index(writer: &VectoredWriter) -> usize {
616 writer.curs.wire.len().saturating_sub(writer.curs.arr_idx)
617}
618
619pub fn _internal_vectoredwriter_slice_index(writer: &VectoredWriter) -> usize {
620 writer.curs.idx
621}
622
623impl WireWrite for str {
624 fn write_wire<'a, const E: bool>(&self, curs: &mut WireCursorMut<'a>) -> Result<(), WireError> {
625 curs.put_slice(self.as_bytes())
626 }
627}
628
629impl VectoredWrite for str {
630 fn write_vectored<'a, const E: bool>(
631 &self,
632 curs: &mut VectoredCursorMut<'a>,
633 ) -> Result<(), WireError> {
634 curs.put_slice(self.as_bytes())
635 }
636}
637
638impl WireWrite for [u8] {
639 fn write_wire<'a, const E: bool>(&self, curs: &mut WireCursorMut<'a>) -> Result<(), WireError> {
640 curs.put_slice(self)
641 }
642}
643
644impl VectoredWrite for [u8] {
645 fn write_vectored<'a, const E: bool>(
646 &self,
647 curs: &mut VectoredCursorMut<'a>,
648 ) -> Result<(), WireError> {
649 curs.put_slice(self)
650 }
651}
652
653macro_rules! derive_wire_writable {
654 ($int:ty)=> {
655 impl WireWrite for $int {
656 fn write_wire<const E: bool>(&self, curs: &mut WireCursorMut<'_>) -> Result<(), WireError> {
657 if E {
658 curs.put_slice(self.to_be_bytes().as_slice())
659 } else {
660 curs.put_slice(self.to_le_bytes().as_slice())
661 }
662 }
663 }
664 };
665
666 ($i1:ty, $($i2:ty),+) => {
667 derive_wire_writable! { $i1 }
668 derive_wire_writable! { $($i2),+ }
669 };
670}
671
672macro_rules! derive_wire_partwritable {
673 ($int:ty)=> {
674 impl WireWritePart for $int {
675 fn write_wire_part<const L: usize, const E: bool>(&self, curs: &mut WireCursorMut<'_>) -> Result<(), WireError> {
676 assert!(L < mem::size_of::<$int>()); // TODO: once more powerful const generic expressions are in rust, use them
677 if E {
678 curs.put_slice(&self.to_be_bytes().get(..L).unwrap_or(&[])) // TODO: downcast larger array to smaller one here for safety guarantees
679 } else {
680 curs.put_slice(&self.to_le_bytes().get(..L).unwrap_or(&[]))
681 }
682 }
683 }
684 };
685
686 ($i1:ty, $($i2:ty),+) => {
687 derive_wire_partwritable! { $i1 }
688 derive_wire_partwritable! { $($i2),+ }
689 };
690}
691
692macro_rules! derive_vectored_writable {
693 ($int:ty)=> {
694 impl VectoredWrite for $int {
695 fn write_vectored<const E: bool>(&self, curs: &mut VectoredCursorMut<'_>) -> Result<(), WireError> {
696 if E {
697 curs.put_slice(self.to_be_bytes().as_slice())
698 } else {
699 curs.put_slice(self.to_le_bytes().as_slice())
700 }
701 }
702 }
703 };
704
705 ($i1:ty, $($i2:ty),+) => {
706 derive_vectored_writable! { $i1 }
707 derive_vectored_writable! { $($i2),+ }
708 };
709}
710
711macro_rules! derive_vectored_partwritable {
712 ($int:ty)=> {
713 impl VectoredWritePart for $int {
714 fn write_vectored_part<const L: usize, const E: bool>(&self, curs: &mut VectoredCursorMut<'_>) -> Result<(), WireError> {
715 assert!(L < mem::size_of::<$int>()); // TODO: once more powerful const generic expressions are in rust, use them
716 if E {
717 curs.put_slice(&self.to_be_bytes().get(..L).unwrap_or(&[])) // TODO: downcast larger array to smaller one here for safety guarantees
718 } else {
719 curs.put_slice(&self.to_le_bytes().get(..L).unwrap_or(&[]))
720 }
721 }
722 }
723 };
724
725 ($i1:ty, $($i2:ty),+) => {
726 derive_vectored_partwritable! { $i1 }
727 derive_vectored_partwritable! { $($i2),+ }
728 };
729}
730
731derive_wire_writable!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, f32, f64, isize, usize);
732derive_vectored_writable!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, f32, f64, isize, usize);
733
734// No floats or signed integers--their implementations aren't conducive to chopping off bytes at will
735derive_wire_partwritable!(u16, u32, u64, u128, usize);
736derive_vectored_partwritable!(u16, u32, u64, u128, usize);