use regex::Regex; use serde::ser::Serialize; use serde_json::ser::{CharEscape, Formatter}; use std::io::Write; use std::string::FromUtf8Error as Utf8Error; use thiserror::Error;
/// Implements the [serde_json::ser::Formatter] trait for serializing [serde_json::Value] objects into their /// canonical string representation. /// /// # Example /// /// ``` /// use serde::Serialize; /// use serde_json::json; /// use canonical_json::JsonFormatter; /// /// let input = json!(vec!["one", "two", "three"]); /// let mut bytes = vec![]; /// let mut serializer = serde_json::Serializer::with_formatter(&mut bytes, JsonFormatter); /// input.serialize(&mut serializer).unwrap(); /// /// assert_eq!(String::from_utf8(bytes).unwrap(), r#"["one","two","three"]"#); /// ``` pubstruct JsonFormatter;
#[derive(Debug, Error)] pubenum CanonicalJSONError { #[error("UTF-8 related error: {0}")]
Utf8Error(#[from] Utf8Error), #[error("JSON related error: {0}")]
JSONError(#[from] serde_json::error::Error),
}
if string_iter.peek() == Some(&'{') { // consume at most 4 characters till '}' is found letmut characters = String::new();
string_iter.next(); // skip the '{' for now letmut index = 0;
while index < 6 && string_iter.peek() != Some(&'}') && string_iter.peek() != None { match string_iter.peek() {
Some(character) => characters.push(*character),
None => break,
};
string_iter.next();
index += 1;
}
if string_iter.peek() == None { // could not find '}' bracket so must include '{' and following characters
writer.write_all("{".as_bytes())?;
writer.write_all(&characters.into_bytes())?;
} elseif string_iter.peek() == Some(&'}') { // found '}' - remove '{' and '}' but must pad zeros if characters.is_empty() {
writer.write_all("{}".as_bytes())?;
} else { if characters.len() > 4 { // Surrogates pairs. match hex::decode(format!("{:0>6}", characters)) {
Ok(v) => { let codepoint = (v[2] as u32)
+ ((v[1] as u32) << 8)
+ ((v[0] as u32) << 16); let high = ((codepoint - 0x10000) / 0x400) + 0xD800; let low = ((codepoint - 0x10000) % 0x400) + 0xDC00;
writer.write_all(format!("{:x}", high).as_bytes())?;
writer.write_all(format!("\\u{:x}", low).as_bytes())?;
}
Err(_) => {
writer.write_all(&characters.into_bytes())?;
}
};
} else {
writer.write_all(&"0".repeat(4 - characters.len()).into_bytes())?;
writer.write_all(&characters.into_bytes())?;
}
string_iter.next(); // skip '}'
}
}
}
// serialize does not alter certain strings (newline, tab, carriagereturn, forwardslashes)
test_canonical_json!("This is a sentence.\n", r#""This is a sentence.\n""#);
test_canonical_json!("This is a \t tab.", r#""This is a \t tab.""#);
test_canonical_json!( "This is a \r carriage return char.",
r#""This is a \r carriage return char.""#
);
test_canonical_json!("image/jpeg", r#""image/jpeg""#);
test_canonical_json!("image//jpeg", r#""image//jpeg""#); // serialize preserves scientific notation number within string
test_canonical_json!("frequency at 10.0e+04", r#""frequency at 10.0e+04""#); // serialize preserves invalid unicode escape sequence
test_canonical_json!("I \\u{} testing", r#""I \\u{} testing""#); // serialize preserves opening curly brackets when invalid unicode escape sequence
test_canonical_json!("I \\u{1234 testing", r#""I \\u{1234 testing""#);
test_canonical_json!("I \\u{{12345}} testing", r#""I \\u{{12345}} testing""#);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.