use std::fmt::Display;
#[derive(Clone)]
pub struct JsonString {
string: Vec<u8>,
string_with_quotes: Vec<u8>,
}
impl std::fmt::Debug for JsonString {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
r#"{}"#,
std::str::from_utf8(&self.string_with_quotes).unwrap_or("[invalid utf8]")
)
}
}
impl JsonString {
#[must_use]
#[inline]
pub fn new(string: &str) -> Self {
let bytes = string.as_bytes();
let without_quotes = Vec::from(bytes);
let mut with_quotes = Vec::with_capacity(bytes.len() + 2);
with_quotes.push(b'"');
with_quotes.extend(bytes);
with_quotes.push(b'"');
Self {
string: without_quotes,
string_with_quotes: with_quotes,
}
}
#[must_use]
#[inline(always)]
pub fn bytes(&self) -> &[u8] {
&self.string
}
#[must_use]
#[inline(always)]
pub fn bytes_with_quotes(&self) -> &[u8] {
&self.string_with_quotes
}
#[must_use]
#[inline(always)]
pub fn display(&self) -> impl Display + '_ {
std::str::from_utf8(&self.string).unwrap_or("[invalid utf8]")
}
}
impl PartialEq<Self> for JsonString {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.string == other.string
}
}
impl Eq for JsonString {}
impl PartialEq<JsonString> for [u8] {
#[inline(always)]
fn eq(&self, other: &JsonString) -> bool {
self == other.string
}
}
impl PartialEq<JsonString> for &[u8] {
#[inline(always)]
fn eq(&self, other: &JsonString) -> bool {
*self == other.string
}
}
impl PartialEq<[u8]> for JsonString {
#[inline(always)]
fn eq(&self, other: &[u8]) -> bool {
self.string == other
}
}
impl PartialEq<&[u8]> for JsonString {
#[inline(always)]
fn eq(&self, other: &&[u8]) -> bool {
self.string == *other
}
}
impl std::hash::Hash for JsonString {
#[inline(always)]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let slice: &[u8] = &self.string;
slice.hash(state);
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::{assert_eq, assert_ne};
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};
use test_case::test_case;
#[test_case("dog", "dog"; "dog")]
#[test_case("", ""; "empty")]
fn equal_json_strings_are_equal(s1: &str, s2: &str) {
let string1 = JsonString::new(s1);
let string2 = JsonString::new(s2);
assert_eq!(string1, string2);
}
#[test]
fn different_json_strings_are_not_equal() {
let string1 = JsonString::new("dog");
let string2 = JsonString::new("doc");
assert_ne!(string1, string2);
}
#[test_case("dog", "dog"; "dog")]
#[test_case("", ""; "empty")]
fn equal_json_strings_have_equal_hashes(s1: &str, s2: &str) {
let string1 = JsonString::new(s1);
let string2 = JsonString::new(s2);
let mut hasher1 = DefaultHasher::new();
string1.hash(&mut hasher1);
let hash1 = hasher1.finish();
let mut hasher2 = DefaultHasher::new();
string2.hash(&mut hasher2);
let hash2 = hasher2.finish();
assert_eq!(hash1, hash2);
}
}