1#[cfg(feature = "varing")]
2#[cfg_attr(docsrs, doc(cfg(feature = "varing")))]
3pub use varing::{DecodeError as ReadVarintError, EncodeError as WriteVarintError};
4
5use core::num::NonZeroUsize;
6
7macro_rules! try_op_error {
8 (
9 #[doc = $doc:literal]
10 #[error($msg:literal)]
11 $op:ident
12 ) => {
13 paste::paste! {
14 #[doc = $doc]
15 #[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
16 #[error($msg)]
17 pub struct [< Try $op:camel Error >] {
18 requested: NonZeroUsize,
19 available: usize,
20 }
21
22 impl [< Try $op:camel Error >] {
23 #[doc = "Creates a new `Try" $op:camel "Error` with the requested and available bytes."]
24 #[inline]
30 pub const fn new(requested: usize, available: usize) -> Self {
31 debug_assert!(requested > available, concat!(stringify!([< Try $op:camel Error >]), ": requested must be greater than available"));
32
33 Self {
34 requested: NonZeroUsize::new(requested).expect(
35 concat!(stringify!([< Try $op:camel Error >]), ": requested must be non-zero")
36 ),
37 available,
38 }
39 }
40
41 #[inline]
45 pub const fn requested(&self) -> usize {
46 self.requested.get()
47 }
48
49 #[inline]
53 pub const fn available(&self) -> usize {
54 self.available
55 }
56
57 #[inline]
61 pub const fn shortage(&self) -> usize {
62 self.requested() - self.available()
63 }
64 }
65 }
66 };
67}
68
69try_op_error!(
70 #[doc = "An error that occurs when trying to advance the buffer cursor beyond available data.
71
72This error indicates that an attempt was made to move the buffer's read position forward
73by more bytes than are currently available. This is a recoverable error - the buffer
74position remains unchanged and the operation can be retried with a smaller advance amount."]
75 #[error(
76 "not enough bytes available to advance (requested {requested} but only {available} available)"
77 )]
78 advance
79);
80
81#[cfg(feature = "std")]
82impl From<TryAdvanceError> for std::io::Error {
83 fn from(e: TryAdvanceError) -> Self {
84 std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e)
85 }
86}
87
88try_op_error!(
89 #[doc = "An error that occurs when trying to read data from a buffer with insufficient bytes.
90
91This error indicates that a read operation failed because the buffer does not contain
92enough bytes to satisfy the request. Failed read operations do not consume any bytes - the buffer position remains unchanged."]
93 #[error(
94 "not enough bytes available to read value (requested {requested} but only {available} available)"
95 )]
96 read
97);
98
99#[cfg(feature = "std")]
100impl From<TryReadError> for std::io::Error {
101 fn from(e: TryReadError) -> Self {
102 std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e)
103 }
104}
105
106try_op_error!(
107 #[doc = "An error that occurs when trying to peek at data beyond the buffer's available bytes.
108
109This error indicates that a peek operation failed because the buffer does not contain
110enough bytes at the current position. Peek operations never modify the buffer position,
111so this error leaves the buffer in its original state."]
112 #[error(
113 "not enough bytes available to peek value (requested {requested} but only {available} available)"
114 )]
115 peek
116);
117
118#[cfg(feature = "std")]
119impl From<TryPeekError> for std::io::Error {
120 fn from(e: TryPeekError) -> Self {
121 std::io::Error::new(std::io::ErrorKind::UnexpectedEof, e)
122 }
123}
124
125impl From<TryPeekError> for TryReadError {
126 #[inline]
127 fn from(e: TryPeekError) -> Self {
128 TryReadError {
129 requested: e.requested,
130 available: e.available,
131 }
132 }
133}
134
135try_op_error!(
136 #[doc = "An error that occurs when trying to write data to a buffer with insufficient space.
137
138This error indicates that a write operation failed because the buffer does not have
139enough remaining capacity to hold the data.
140
141This error is particularly useful for Sans-I/O designs as it provides exact information
142about space requirements, allowing the caller to allocate a larger buffer and retry:
143
144```rust
145# use bufkit::BufMut;
146let mut small_buf = [0u8; 4];
147let mut writer = &mut small_buf[..];
148
149match writer.try_put_u64_le(0x123456789ABCDEF0) {
150 Err(e) => {
151 // Caller knows exactly how much space is needed
152 assert_eq!(e.requested(), 8);
153 assert_eq!(e.available(), 4);
154 println!(\"Need {} more bytes\", e.shortage());
155 }
156 _ => panic!(\"Expected error\"),
157}
158```"]
159 #[error(
160 "not enough space available to write value (requested {requested} but only {available} available)"
161 )]
162 write
163);
164
165#[cfg(feature = "std")]
166impl From<TryWriteError> for std::io::Error {
167 fn from(e: TryWriteError) -> Self {
168 std::io::Error::new(std::io::ErrorKind::WriteZero, e)
169 }
170}
171
172#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
198#[error("invalid segment range {start}..{end} for buffer with {available} bytes")]
199pub struct TrySegmentError {
200 start: usize,
201 end: usize,
202 available: usize,
203}
204
205impl TrySegmentError {
206 #[inline]
212 pub const fn new(start: usize, end: usize, available: usize) -> Self {
213 debug_assert!(
214 start > end || end > available,
215 "TrySegmentError: invalid error - range is valid"
216 );
217
218 Self {
219 start,
220 end,
221 available,
222 }
223 }
224
225 #[inline]
227 pub const fn start(&self) -> usize {
228 self.start
229 }
230
231 #[inline]
233 pub const fn end(&self) -> usize {
234 self.end
235 }
236
237 #[inline]
239 pub const fn available(&self) -> usize {
240 self.available
241 }
242
243 #[inline]
247 pub const fn requested(&self) -> usize {
248 self.end.saturating_sub(self.start)
249 }
250
251 #[inline]
253 pub const fn is_inverted(&self) -> bool {
254 self.start > self.end
255 }
256
257 #[inline]
262 pub const fn overflow(&self) -> usize {
263 self.end.saturating_sub(self.available)
264 }
265}
266
267#[cfg(feature = "std")]
268impl From<TrySegmentError> for std::io::Error {
269 fn from(e: TrySegmentError) -> Self {
270 std::io::Error::new(std::io::ErrorKind::InvalidInput, e)
271 }
272}
273
274#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
295#[error("offset {offset} is out of bounds for buffer length {length}")]
296pub struct OutOfBounds {
297 offset: usize,
298 length: usize,
299}
300
301impl OutOfBounds {
302 #[inline]
308 pub const fn new(offset: usize, length: usize) -> Self {
309 debug_assert!(offset >= length, "OutOfBounds: offset must be >= length");
310
311 Self { offset, length }
312 }
313
314 #[inline]
316 pub const fn offset(&self) -> usize {
317 self.offset
318 }
319
320 #[inline]
322 pub const fn length(&self) -> usize {
323 self.length
324 }
325
326 #[inline]
330 pub const fn excess(&self) -> usize {
331 self.offset() - self.length() + 1
332 }
333}
334
335#[cfg(feature = "std")]
336impl From<OutOfBounds> for std::io::Error {
337 fn from(e: OutOfBounds) -> Self {
338 std::io::Error::new(std::io::ErrorKind::InvalidInput, e)
339 }
340}
341
342#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
347#[error(
348 "not enough bytes available at {offset} (requested {requested} but only {available} available)"
349)]
350pub struct InsufficientSpaceAt {
351 requested: NonZeroUsize,
353 available: usize,
355 offset: usize,
357}
358
359impl InsufficientSpaceAt {
360 #[inline]
367 pub const fn new(requested: usize, available: usize, offset: usize) -> Self {
368 debug_assert!(
369 requested > available,
370 "InsufficientSpaceAt: requested must be greater than available"
371 );
372
373 Self {
374 requested: NonZeroUsize::new(requested)
375 .expect("InsufficientSpaceAt: requested must be non-zero"),
376 available,
377 offset,
378 }
379 }
380
381 #[inline]
383 pub const fn requested(&self) -> usize {
384 self.requested.get()
385 }
386
387 #[inline]
389 pub const fn available(&self) -> usize {
390 self.available
391 }
392
393 #[inline]
395 pub const fn offset(&self) -> usize {
396 self.offset
397 }
398
399 #[inline]
403 pub const fn shortage(&self) -> usize {
404 self.requested() - self.available()
405 }
406}
407
408#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
412#[non_exhaustive]
413pub enum TryWriteAtError {
414 #[error(transparent)]
416 OutOfBounds(#[from] OutOfBounds),
417 #[error(transparent)]
419 InsufficientSpace(#[from] InsufficientSpaceAt),
420}
421
422impl TryWriteAtError {
423 #[inline]
425 pub const fn out_of_bounds(offset: usize, length: usize) -> Self {
426 Self::OutOfBounds(OutOfBounds::new(offset, length))
427 }
428
429 #[inline]
436 pub const fn insufficient_space(requested: usize, available: usize, offset: usize) -> Self {
437 Self::InsufficientSpace(InsufficientSpaceAt::new(requested, available, offset))
438 }
439}
440
441#[cfg(feature = "std")]
442impl From<TryWriteAtError> for std::io::Error {
443 fn from(e: TryWriteAtError) -> Self {
444 match e {
445 TryWriteAtError::OutOfBounds(e) => std::io::Error::new(std::io::ErrorKind::InvalidInput, e),
446 TryWriteAtError::InsufficientSpace(e) => {
447 if e.offset() >= e.available() {
448 std::io::Error::new(std::io::ErrorKind::InvalidInput, e)
449 } else {
450 std::io::Error::new(std::io::ErrorKind::WriteZero, e)
451 }
452 }
453 }
454 }
455}
456
457#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
459#[non_exhaustive]
460#[cfg(feature = "varing")]
461#[cfg_attr(docsrs, doc(cfg(feature = "varing")))]
462pub enum WriteVarintAtError {
463 #[error(transparent)]
465 OutOfBounds(#[from] OutOfBounds),
466 #[error(transparent)]
468 InsufficientSpace(#[from] InsufficientSpaceAt),
469 #[error("{0}")]
471 #[cfg(not(any(feature = "std", feature = "alloc")))]
472 Other(&'static str),
473
474 #[error("{0}")]
476 #[cfg(any(feature = "std", feature = "alloc"))]
477 Other(std::borrow::Cow<'static, str>),
478}
479
480#[cfg(feature = "varing")]
481impl WriteVarintAtError {
482 #[inline]
484 pub const fn out_of_bounds(offset: usize, length: usize) -> Self {
485 Self::OutOfBounds(OutOfBounds::new(offset, length))
486 }
487
488 #[inline]
495 pub const fn insufficient_space(requested: usize, available: usize, offset: usize) -> Self {
496 Self::InsufficientSpace(InsufficientSpaceAt::new(requested, available, offset))
497 }
498
499 #[inline]
501 pub const fn from_write_varint_error(err: WriteVarintError, offset: usize) -> Self {
502 match err {
503 WriteVarintError::InsufficientSpace(e) => {
504 Self::insufficient_space(e.requested(), e.available(), offset)
505 }
506 #[cfg(any(feature = "std", feature = "alloc"))]
507 WriteVarintError::Other(msg) => Self::Other(std::borrow::Cow::Borrowed(msg)),
508 #[cfg(not(any(feature = "std", feature = "alloc")))]
509 WriteVarintError::Other(msg) => Self::other(msg),
510 #[cfg(any(feature = "std", feature = "alloc"))]
511 _ => Self::Other(std::borrow::Cow::Borrowed("unknown error")),
512 #[cfg(not(any(feature = "std", feature = "alloc")))]
513 _ => Self::Other("unknown error"),
514 }
515 }
516
517 #[cfg(not(any(feature = "std", feature = "alloc")))]
519 #[inline]
520 pub const fn other(msg: &'static str) -> Self {
521 Self::Other(msg)
522 }
523
524 #[cfg(any(feature = "std", feature = "alloc"))]
526 #[inline]
527 pub fn other(msg: impl Into<std::borrow::Cow<'static, str>>) -> Self {
528 Self::Other(msg.into())
529 }
530}
531
532#[cfg(all(feature = "varing", feature = "std"))]
533impl From<WriteVarintAtError> for std::io::Error {
534 fn from(e: WriteVarintAtError) -> Self {
535 match e {
536 WriteVarintAtError::OutOfBounds(e) => {
537 std::io::Error::new(std::io::ErrorKind::InvalidInput, e)
538 }
539 WriteVarintAtError::InsufficientSpace(e) => {
540 if e.offset() >= e.available() {
541 std::io::Error::new(std::io::ErrorKind::InvalidInput, e)
542 } else {
543 std::io::Error::new(std::io::ErrorKind::WriteZero, e)
544 }
545 }
546 WriteVarintAtError::Other(msg) => std::io::Error::other(msg),
547 }
548 }
549}
550
551#[cfg(feature = "bytes_1")]
552const _: () = {
553 use bytes_1::TryGetError;
554
555 impl From<TryGetError> for TryAdvanceError {
556 fn from(e: TryGetError) -> Self {
557 TryAdvanceError::new(e.requested, e.available)
558 }
559 }
560
561 impl From<TryGetError> for TryReadError {
562 fn from(e: TryGetError) -> Self {
563 TryReadError::new(e.requested, e.available)
564 }
565 }
566};