1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
//! Contains the definition of the error type used by the encoding functions in the crate.
use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq)]
/// The error returned by [`zalgo_encode`](crate::zalgo_encode), [`ZalgoString::new`](crate::ZalgoString::new), and [`zalgo_wrap_python`](crate::zalgo_wrap_python)
/// if they encounter a byte they can not encode.
///
/// Only implements the [`Error`](std::error::Error) trait if the `std` feature is enabled.
pub enum Error {
/// Represents a valid ASCII character that is outside of the encodable set.
/// The first `u8` in the variant is the byte value of the character, the first `usize`
/// is the 1-indexed line number where the character occured, the second `usize` is
/// the 1-indexed column in which the character occured and the `&str` is a description
/// of the character.
UnencodableAscii(u8, usize, usize, &'static str),
/// Represents some other character.
/// The two `usize`s represent the same thing as in the `UnencodableAscii` variant,
/// but the `u8` is only the first byte of the character.
NotAscii(u8, usize, usize),
}
impl Error {
/// Returns the 1-indexed line number of the line on which the unencodable byte occured.
///
/// # Examples
///
/// ```
/// # use zalgo_codec_common::{Error, zalgo_encode};
/// assert_eq!(zalgo_encode("❤️").err().map(|e| e.line()), Some(1));
/// assert_eq!(zalgo_encode("a\nb\nc\r\n").err().map(|e| e.line()), Some(3));
/// ```
#[must_use = "the method returns a new valus and does not modify `self`"]
pub const fn line(&self) -> usize {
match self {
Self::UnencodableAscii(_, line, _, _) | Self::NotAscii(_, line, _) => *line,
}
}
/// Returns the 1-indexed column where the unencodable byte occured.
/// Columns are counted from left to right and the count resets for each new line.
///
/// # Example
///
/// ```
/// # use zalgo_codec_common::{Error, zalgo_encode};
/// assert_eq!(zalgo_encode("I ❤️ 🎂").err().map(|e| e.column()), Some(3));
/// assert_eq!(zalgo_encode("I\n❤️\n🎂").err().map(|e|e.column()), Some(1));
/// ```
#[must_use = "the method returns a new valus and does not modify `self`"]
pub const fn column(&self) -> usize {
match self {
Self::UnencodableAscii(_, _, column, _) | Self::NotAscii(_, _, column) => *column,
}
}
/// Returns the value of the first byte of the unencodable character.
///
/// # Examples
///
/// ```
/// # use zalgo_codec_common::{Error, zalgo_encode};
/// assert_eq!(zalgo_encode("\r").err().map(|e| e.byte()), Some(13));
/// ```
/// Note that this might not be the complete representation of
/// the character in unicode, just the first byte of it.
/// ```
/// # use zalgo_codec_common::{Error, zalgo_encode};
/// assert_eq!(zalgo_encode("❤️").err().map(|e| e.byte()), Some(226));
/// // Even though
/// assert_eq!("❤️".as_bytes(), &[226, 157, 164, 239, 184, 143])
/// ```
#[must_use = "the method returns a new value and does not modify `self`"]
pub const fn byte(&self) -> u8 {
match self {
Self::UnencodableAscii(byte, _, _, _) | Self::NotAscii(byte, _, _) => *byte,
}
}
/// Return a representation of the unencodable byte.
/// This exists if the character is an unencodable ASCII character.
/// If it is some other unicode character we only know its first byte, so we can not
/// accurately represent it.
///
/// # Examples
///
/// ```
/// # use zalgo_codec_common::zalgo_encode;
/// assert_eq!(zalgo_encode("\r").err().map(|e| e.representation()).flatten(), Some("Carriage Return"));
/// assert_eq!(zalgo_encode("❤️").err().map(|e| e.representation()).flatten(), None);
/// ```
#[must_use = "the method returns a new value and does not modify `self`"]
pub const fn representation(&self) -> Option<&'static str> {
match self {
Self::UnencodableAscii(_, _, _, repr) => Some(*repr),
Self::NotAscii(_, _, _) => None,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::UnencodableAscii(byte, line, column, repr) => write!(
f,
"line {line} at column {column}: can not encode ASCII \"{repr}\" character with byte value {byte}"
),
Self::NotAscii(byte, line, column) => write!(
f,
"line {line} at column {column}: byte value {byte} does not correspond to an ASCII character"
),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
#[cfg(test)]
mod test {
use super::Error;
#[test]
fn test_error() {
let err = Error::NotAscii(195, 1, 7);
assert_eq!(err.byte(), 195);
assert_eq!(err.line(), 1);
assert_eq!(err.column(), 7);
assert_eq!(err.representation(), None);
let err = Error::UnencodableAscii(13, 1, 2, "Carriage Return");
assert_eq!(err.byte(), 13);
assert_eq!(err.line(), 1);
assert_eq!(err.column(), 2);
assert_eq!(err.representation(), Some("Carriage Return"));
}
}