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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
//! Contains the definition of the error type used by the encoding functions in the crate.
use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// 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 struct Error {
unencodable_character: char,
line: usize,
column: usize,
index: usize,
}
impl Error {
/// Creates a new `Error`.
///
/// # Note
///
/// This associated method does not check the validity of its inputs,
/// and just constructs a new `Error` instance.
#[inline]
#[must_use = "this associated method does not modify its inputs and just returns a new value"]
pub(crate) const fn new(
unencodable_character: char,
line: usize,
column: usize,
index: usize,
) -> Self {
Self {
unencodable_character,
line,
column,
index,
}
}
/// 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("❤️").map_err(|e| e.line()), Err(1));
/// assert_eq!(zalgo_encode("a\nb\nc\r\n").map_err(|e| e.line()), Err(3));
/// ```
#[inline]
#[must_use = "the method returns a new value and does not modify `self`"]
pub const fn line(&self) -> usize {
self.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 ❤️ 🎂").map_err(|e| e.column()), Err(3));
/// assert_eq!(zalgo_encode("I\n❤️\n🎂").map_err(|e|e.column()), Err(1));
/// ```
#[inline]
#[must_use = "the method returns a new value and does not modify `self`"]
pub const fn column(&self) -> usize {
self.column
}
/// Returns the unencodable character that caused the error.
///
/// This may not match with what you see when you look at the unencoded string in a text editor since
/// some grapheme clusters consist of many unicode characters.
///
/// # Examples
///
/// ```
/// # use zalgo_codec_common::zalgo_encode;
/// assert_eq!(zalgo_encode("CRLF\r\n").map_err(|e| e.char()), Err('\r'));
///
/// ```
/// The ❤️ emoji consists of two characters, the heart `U+2764` and the color variant selector `U+FE0F`
/// Since the heart is not encodable, that is the place where the error is generated:
/// ```
/// # use zalgo_codec_common::zalgo_encode;
/// assert_eq!(zalgo_encode("❤️").map_err(|e| e.char()), Err('❤'));
/// ```
/// The grapheme cluster `á` consists of a normal `a` and a combining acute accent, `U+301`.
/// The `a` can be encoded and the combining acute accent can not, so the error points only to the accent:
/// ```
/// # use zalgo_codec_common::zalgo_encode;
/// assert_eq!(zalgo_encode("á").map_err(|e| e.char()), Err('\u{301}'))
/// ```
#[inline]
#[must_use = "the method returns a new value and does not modify `self`"]
pub const fn char(&self) -> char {
self.unencodable_character
}
/// Returns the index of the string where the unencodable character occured.
///
/// # Example
///
/// ```
/// # use zalgo_codec_common::zalgo_encode;
/// assert_eq!(zalgo_encode("ab\ncdë").map_err(|e| e.index()), Err(5));
/// ```
#[inline]
#[must_use = "the method returns a new value and does not modify `self`"]
pub const fn index(&self) -> usize {
self.index
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"can not encode {:?} character at string index {}, on line {} at column {}: ",
self.char(),
self.index(),
self.line(),
self.column(),
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
#[cfg(test)]
mod test {
use super::Error;
#[test]
fn test_error() {
let err = Error {
line: 1,
column: 7,
unencodable_character: 'å',
index: 6,
};
assert_eq!(err.char(), 'å');
assert_eq!(err.line(), 1);
assert_eq!(err.column(), 7);
assert_eq!(err.index(), 6);
let err2 = Error {
line: 1,
column: 2,
unencodable_character: '\r',
index: 1,
};
assert_eq!(err2.char(), '\r');
assert_eq!(err2.line(), 1);
assert_eq!(err2.column(), 2);
assert_eq!(err2.index(), 1);
assert_ne!(err, err2);
let err3 = err;
assert_eq!(err, err3);
}
}