repl_lang/error.rs
1//! Why a session refused a line.
2
3use core::fmt;
4
5/// The reason a [`Session`](crate::Session) could not accept a line.
6///
7/// Both variants mean the pending entry was too large to keep, so the session
8/// discards it before returning the error: the next line starts a fresh entry
9/// and the session stays usable. Nothing already committed is affected. The
10/// pipeline is never called with input that triggered an error.
11///
12/// The enum is `#[non_exhaustive]`; match it with a wildcard arm.
13///
14/// # Examples
15///
16/// ```
17/// use repl_lang::{Session, SessionError, Status};
18///
19/// let mut session = Session::with_limit(8);
20/// let err = session.feed("a line that is far too long", |_| Status::Complete(())).unwrap_err();
21/// assert!(matches!(err, SessionError::TooLong { limit: 8, .. }));
22/// assert!(!session.is_pending()); // the oversized entry was dropped
23/// ```
24#[derive(Clone, Debug, PartialEq, Eq)]
25#[non_exhaustive]
26pub enum SessionError {
27 /// The entry, with this line added, would exceed the session's size limit.
28 ///
29 /// The limit bounds how much text one entry can accumulate — and so how
30 /// much the pipeline re-reads on every continuation line — guarding
31 /// against a runaway paste or a pipeline that never declares input
32 /// complete. Report it to the user; raise the limit with
33 /// [`Session::with_limit`](crate::Session::with_limit) if legitimate
34 /// entries hit it.
35 TooLong {
36 /// Byte length the entry would have reached, including line terminators.
37 len: usize,
38 /// The session's limit, in bytes.
39 limit: usize,
40 },
41
42 /// The session's source map has no room left for the entry.
43 ///
44 /// Committed entries share one 32-bit position space, so a session can hold
45 /// about 4 GiB of entries in total. A shorter entry may still fit, but the
46 /// session is effectively full: start a fresh [`Session`](crate::Session).
47 SpaceExhausted {
48 /// Byte length of the entry that did not fit.
49 needed: u64,
50 /// Bytes of position space that remained.
51 available: u64,
52 },
53}
54
55impl fmt::Display for SessionError {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 match self {
58 Self::TooLong { len, limit } => write!(
59 f,
60 "entry too long: {len} bytes exceeds the session limit of {limit} bytes"
61 ),
62 Self::SpaceExhausted { needed, available } => write!(
63 f,
64 "session source space exhausted: entry needs {needed} bytes, \
65 {available} remain"
66 ),
67 }
68 }
69}
70
71impl core::error::Error for SessionError {}
72
73#[cfg(test)]
74mod tests {
75 use alloc::string::ToString;
76
77 use super::*;
78
79 #[test]
80 fn test_display_too_long_names_both_sizes() {
81 let text = SessionError::TooLong { len: 12, limit: 8 }.to_string();
82 assert_eq!(
83 text,
84 "entry too long: 12 bytes exceeds the session limit of 8 bytes"
85 );
86 }
87
88 #[test]
89 fn test_display_space_exhausted_names_both_sizes() {
90 let text = SessionError::SpaceExhausted {
91 needed: 9,
92 available: 2,
93 }
94 .to_string();
95 assert_eq!(
96 text,
97 "session source space exhausted: entry needs 9 bytes, 2 remain"
98 );
99 }
100
101 #[test]
102 fn test_error_trait_is_implemented() {
103 fn assert_error<E: core::error::Error + Send + Sync + 'static>() {}
104 assert_error::<SessionError>();
105 }
106}