pub trait EncodeSink {
// Required methods
fn remaining_capacity(&self) -> Option<usize>;
fn write(&mut self, bytes: &[u8]) -> Result<(), SinkFull>;
// Provided method
fn write_parts(&mut self, parts: &[&[u8]]) -> Result<(), SinkFull> { ... }
}Expand description
Storage that accepts a complete byte slice or leaves its output unchanged.
A write appends after earlier output. On failure, neither the output bytes nor the output position may change. Implementers must uphold that contract; it is not a partial-I/O interface.
The tag-header, bounded scalar, timestamp and reference encoders check
advertised capacity, then write their complete output once. A
variable-length value, such as a string with its header, is written with
write_parts, which is atomic for the whole value.
Neither promises rollback across several encoder calls: a custom sink can
refuse a later write even after a total-capacity check, leaving earlier
writes in place.
Implemented for &mut [u8], and heapless::Vec<u8, N> with the heapless
feature, and with alloc for alloc::vec::Vec<u8> and bytes::BytesMut.
Growable adapters may allocate and retain their ordinary
allocation-failure behavior.
use bacnet_encoding::sink::EncodeSink;
let mut storage = [0xA5; 4];
let mut tail = &mut storage[..];
tail.write(&[1, 2])?;
assert_eq!(tail.remaining_capacity(), Some(2));
assert_eq!(tail.write(&[3, 4, 5]).unwrap_err().available, 2);
tail.write(&[3, 4])?;
assert!(tail.is_empty());
assert_eq!(storage, [1, 2, 3, 4]);Required Methods§
Sourcefn remaining_capacity(&self) -> Option<usize>
fn remaining_capacity(&self) -> Option<usize>
Remaining append space, or None when no fixed bound is advertised.
Growable containers return None, not their current allocation’s spare
capacity. A sink may still reject a write; the encoder passes through
its SinkFull without changing the error.
Provided Methods§
Sourcefn write_parts(&mut self, parts: &[&[u8]]) -> Result<(), SinkFull>
fn write_parts(&mut self, parts: &[&[u8]]) -> Result<(), SinkFull>
Append every slice of parts, in order, as one value, or fail without
changing output bytes or position.
The provided method adds up the parts’ lengths, refuses a total that
overflows usize (with needed set to usize::MAX) or exceeds
remaining_capacity, and only then calls
write once per part. That is atomic for a sink whose
write never refuses an append its advertised capacity covers, and
whose capacity, when it advertises none, is unbounded. Every adapter
this crate ships is such a sink.
A sink that can refuse despite advertising enough room, such as one with a quota it doesn’t advertise or one backed by fallible storage, must override this method, and either stage the parts or undo the ones it wrote. Otherwise a refused later part leaves the earlier ones written.
use bacnet_encoding::sink::EncodeSink;
let mut storage = [0; 4];
let mut tail = &mut storage[..];
// Five octets don't fit: nothing is written.
let refused = tail.write_parts(&[&[1, 2], &[3, 4, 5]]).unwrap_err();
assert_eq!((refused.needed, refused.available), (5, 4));
assert_eq!(tail.len(), 4);
tail.write_parts(&[&[1], &[], &[2, 3]])?;
assert_eq!(storage, [1, 2, 3, 0]);Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementations on Foreign Types§
Source§impl EncodeSink for &mut [u8]
Writes at the front and advances the slice to its unused tail.
A failed write leaves both the slice and its backing bytes unchanged.
impl EncodeSink for &mut [u8]
Writes at the front and advances the slice to its unused tail. A failed write leaves both the slice and its backing bytes unchanged.
Source§impl EncodeSink for BytesMut
Available on crate feature alloc only.
impl EncodeSink for BytesMut
alloc only.Source§impl EncodeSink for Vec<u8>
Available on crate feature alloc only.
impl EncodeSink for Vec<u8>
alloc only.