use serde::{Serialize, de::DeserializeOwned};
#[derive(Debug)]
pub struct JsonError {
message: String,
}
impl std::fmt::Display for JsonError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for JsonError {}
impl From<serde_json::Error> for JsonError {
fn from(err: serde_json::Error) -> Self {
JsonError {
message: err.to_string(),
}
}
}
#[cfg(feature = "simd-json")]
impl From<simd_json::Error> for JsonError {
fn from(err: simd_json::Error) -> Self {
JsonError {
message: err.to_string(),
}
}
}
pub type Result<T> = std::result::Result<T, JsonError>;
#[inline]
pub fn to_vec<T: Serialize>(value: &T) -> Result<Vec<u8>> {
#[cfg(feature = "simd-json")]
{
simd_json::to_vec(value).map_err(Into::into)
}
#[cfg(not(feature = "simd-json"))]
{
serde_json::to_vec(value).map_err(Into::into)
}
}
#[inline]
pub fn to_vec_with_capacity<T: Serialize>(value: &T, capacity: usize) -> Result<Vec<u8>> {
let mut buf = Vec::with_capacity(capacity);
#[cfg(feature = "simd-json")]
{
simd_json::to_writer(&mut buf, value)?;
}
#[cfg(not(feature = "simd-json"))]
{
serde_json::to_writer(&mut buf, value)?;
}
Ok(buf)
}
#[inline]
pub fn to_string<T: Serialize>(value: &T) -> Result<String> {
#[cfg(feature = "simd-json")]
{
simd_json::to_string(value).map_err(Into::into)
}
#[cfg(not(feature = "simd-json"))]
{
serde_json::to_string(value).map_err(Into::into)
}
}
#[inline]
pub fn to_string_pretty<T: Serialize>(value: &T) -> Result<String> {
serde_json::to_string_pretty(value).map_err(Into::into)
}
#[inline]
pub fn to_writer<W: std::io::Write, T: Serialize>(writer: W, value: &T) -> Result<()> {
#[cfg(feature = "simd-json")]
{
simd_json::to_writer(writer, value).map_err(Into::into)
}
#[cfg(not(feature = "simd-json"))]
{
serde_json::to_writer(writer, value).map_err(Into::into)
}
}
#[inline]
pub fn from_slice<T: DeserializeOwned>(slice: &[u8]) -> Result<T> {
#[cfg(feature = "simd-json")]
{
let mut buf = slice.to_vec();
simd_json::from_slice(&mut buf).map_err(Into::into)
}
#[cfg(not(feature = "simd-json"))]
{
serde_json::from_slice(slice).map_err(Into::into)
}
}
#[inline]
pub fn from_owned<T: DeserializeOwned>(buf: Vec<u8>) -> Result<T> {
#[cfg(feature = "simd-json")]
{
let mut buf = buf;
simd_json::from_slice(&mut buf).map_err(Into::into)
}
#[cfg(not(feature = "simd-json"))]
{
serde_json::from_slice(&buf).map_err(Into::into)
}
}
#[inline]
pub fn from_slice_mut<T: DeserializeOwned>(slice: &mut [u8]) -> Result<T> {
#[cfg(feature = "simd-json")]
{
simd_json::from_slice(slice).map_err(Into::into)
}
#[cfg(not(feature = "simd-json"))]
{
serde_json::from_slice(slice).map_err(Into::into)
}
}
#[inline]
pub fn from_str<T: DeserializeOwned>(s: &str) -> Result<T> {
#[cfg(feature = "simd-json")]
{
let mut buf = s.as_bytes().to_vec();
simd_json::from_slice(&mut buf).map_err(Into::into)
}
#[cfg(not(feature = "simd-json"))]
{
serde_json::from_str(s).map_err(Into::into)
}
}
#[inline]
pub fn from_reader<R: std::io::Read, T: DeserializeOwned>(reader: R) -> Result<T> {
serde_json::from_reader(reader).map_err(Into::into)
}
#[cfg(feature = "simd-json")]
pub use simd_json::OwnedValue as Value;
#[cfg(not(feature = "simd-json"))]
pub use serde_json::Value;
#[inline]
pub fn to_value<T: Serialize>(value: &T) -> Result<serde_json::Value> {
serde_json::to_value(value).map_err(Into::into)
}
#[inline]
pub fn from_value<T: DeserializeOwned>(value: serde_json::Value) -> Result<T> {
serde_json::from_value(value).map_err(Into::into)
}
#[inline]
pub const fn is_simd_enabled() -> bool {
cfg!(feature = "simd-json")
}
#[inline]
pub const fn library_name() -> &'static str {
if cfg!(feature = "simd-json") {
"simd-json"
} else {
"serde_json"
}
}
#[macro_export]
macro_rules! json {
($($json:tt)+) => {
serde_json::json!($($json)+)
};
}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
struct TestUser {
name: String,
age: u32,
email: String,
}
#[test]
fn test_serialize_deserialize_roundtrip() {
let user = TestUser {
name: "John Doe".to_string(),
age: 30,
email: "john@example.com".to_string(),
};
let bytes = to_vec(&user).unwrap();
let parsed: TestUser = from_slice(&bytes).unwrap();
assert_eq!(user, parsed);
}
#[test]
fn test_to_string() {
let user = TestUser {
name: "John".to_string(),
age: 25,
email: "john@test.com".to_string(),
};
let json_str = to_string(&user).unwrap();
assert!(json_str.contains("John"));
assert!(json_str.contains("25"));
}
#[test]
fn test_to_string_pretty() {
let user = TestUser {
name: "John".to_string(),
age: 25,
email: "john@test.com".to_string(),
};
let json_str = to_string_pretty(&user).unwrap();
assert!(json_str.contains('\n')); }
#[test]
fn test_from_str() {
let json_str = r#"{"name":"Alice","age":28,"email":"alice@example.com"}"#;
let user: TestUser = from_str(json_str).unwrap();
assert_eq!(user.name, "Alice");
assert_eq!(user.age, 28);
}
#[test]
fn test_from_owned() {
let bytes = br#"{"name":"Dana","age":22,"email":"dana@test.com"}"#.to_vec();
let user: TestUser = from_owned(bytes).unwrap();
assert_eq!(user.name, "Dana");
assert_eq!(user.age, 22);
assert_eq!(user.email, "dana@test.com");
}
#[test]
fn test_from_owned_roundtrip_with_to_vec() {
let user = TestUser {
name: "Eve".to_string(),
age: 33,
email: "eve@example.com".to_string(),
};
let bytes = to_vec(&user).unwrap();
let parsed: TestUser = from_owned(bytes).unwrap();
assert_eq!(user, parsed);
}
#[test]
fn test_from_owned_error() {
let bad = b"{ not json }".to_vec();
let result: Result<TestUser> = from_owned(bad);
assert!(result.is_err());
}
#[test]
fn test_from_slice_mut() {
let mut bytes = br#"{"name":"Bob","age":35,"email":"bob@test.com"}"#.to_vec();
let user: TestUser = from_slice_mut(&mut bytes).unwrap();
assert_eq!(user.name, "Bob");
assert_eq!(user.age, 35);
}
#[test]
fn test_to_vec_with_capacity() {
let user = TestUser {
name: "Charlie".to_string(),
age: 40,
email: "charlie@example.com".to_string(),
};
let bytes = to_vec_with_capacity(&user, 256).unwrap();
let parsed: TestUser = from_slice(&bytes).unwrap();
assert_eq!(user, parsed);
}
#[test]
fn test_library_info() {
let name = library_name();
let simd = is_simd_enabled();
if simd {
assert_eq!(name, "simd-json");
} else {
assert_eq!(name, "serde_json");
}
}
#[test]
fn test_json_macro() {
let value = serde_json::json!({
"key": "value",
"number": 42
});
assert_eq!(value["key"], "value");
assert_eq!(value["number"], 42);
}
#[test]
fn test_error_handling() {
let bad_json = b"{ invalid json }";
let result: Result<TestUser> = from_slice(bad_json);
assert!(result.is_err());
}
}