serde_json
Serialization Library
serde_json
Overview
serde_json is a fast and flexible JSON serialization and deserialization library for Rust. Integrated with the Serde framework, it provides type-safe conversion between Rust data structures and JSON. It offers comprehensive JSON processing features including streaming API, pretty printing, and dynamic JSON manipulation.
Details
serde_json is the JSON implementation for the Serde framework, efficiently converting strongly-typed Rust data structures to and from JSON. It achieves performance comparable to or better than the fastest C/C++ JSON libraries.
Key Features:
- High Performance: 500-1000 MB/s deserialization, 600-900 MB/s serialization speeds
- Streaming API: Efficient processing of large JSON data
- Pretty Printing: Support for readable formatted output
- Dynamic JSON Manipulation: Flexible JSON operations via
serde_json::Valuetype - Macro Support: Intuitive JSON construction with
json!macro
Main Functions:
to_string: Serialization to JSONto_string_pretty: Serialization to formatted JSONto_writer: Direct writing to files or network streamsfrom_str: Deserialization from JSONStreamDeserializer: Sequential processing of multiple JSON values
Technical Details:
- Zero-copy deserialization support
- Indent control via custom PrettyFormatter
- no-std environment support (with "alloc" feature)
- Arbitrary precision number support
Pros and Cons
Pros
- Industry-leading performance
- Complete integration with Serde ecosystem
- Rich feature set (streaming, pretty printing, etc.)
- Excellent error messages and debugging experience
- Active maintenance and community support
- Compliance with standard JSON specification
Cons
- Initial learning cost due to Serde dependency
- JSON limitations (e.g., no comments, no key order guarantee)
- Complex custom serialization implementation
- Impact on compile time (when using derive)
References
- GitHub Repository: https://github.com/serde-rs/json
- Documentation: https://docs.rs/serde_json/
- Serde Official Site: https://serde.rs/
Code Examples
Basic Usage
use serde::{Serialize, Deserialize};
use serde_json;
#[derive(Serialize, Deserialize, Debug)]
struct Person {
name: String,
age: u32,
email: String,
}
fn main() -> Result<(), serde_json::Error> {
let person = Person {
name: "John Doe".to_string(),
age: 30,
email: "[email protected]".to_string(),
};
// Serialize to JSON
let json = serde_json::to_string(&person)?;
println!("JSON: {}", json);
// Serialize to pretty JSON
let pretty_json = serde_json::to_string_pretty(&person)?;
println!("Pretty JSON:\n{}", pretty_json);
// Deserialize
let deserialized: Person = serde_json::from_str(&json)?;
println!("Deserialized: {:?}", deserialized);
Ok(())
}
Using json! Macro
use serde_json::{json, Value};
fn main() {
// Dynamically construct JSON with json! macro
let data = json!({
"name": "Project Config",
"version": "1.0.0",
"dependencies": {
"serde": "1.0",
"tokio": "1.0"
},
"features": ["async", "json", "yaml"],
"active": true,
"count": 42
});
println!("{}", serde_json::to_string_pretty(&data).unwrap());
// Access values
println!("Name: {}", data["name"]);
println!("Version: {}", data["version"]);
// Dynamic value modification
let mut value = data;
value["count"] = json!(100);
value["features"].as_array_mut().unwrap().push(json!("new_feature"));
}
Streaming API
use serde::{Serialize, Deserialize};
use serde_json::Deserializer;
#[derive(Serialize, Deserialize, Debug)]
struct LogEntry {
timestamp: String,
level: String,
message: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// String containing multiple JSON values
let json_stream = r#"
{"timestamp": "2024-01-01T10:00:00Z", "level": "INFO", "message": "Server started"}
{"timestamp": "2024-01-01T10:00:01Z", "level": "DEBUG", "message": "Connection established"}
{"timestamp": "2024-01-01T10:00:02Z", "level": "ERROR", "message": "Failed to process request"}
"#;
// Create streaming deserializer
let stream = Deserializer::from_str(json_stream).into_iter::<LogEntry>();
for item in stream {
match item {
Ok(entry) => println!("{:?}", entry),
Err(e) => eprintln!("Error: {}", e),
}
}
Ok(())
}
File I/O
use serde::{Serialize, Deserialize};
use std::fs::File;
use std::io::{BufReader, BufWriter};
#[derive(Serialize, Deserialize, Debug)]
struct Config {
database_url: String,
port: u16,
workers: usize,
features: Vec<String>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = Config {
database_url: "postgres://localhost/mydb".to_string(),
port: 8080,
workers: 4,
features: vec!["auth".to_string(), "api".to_string()],
};
// Write to file
let file = File::create("config.json")?;
let writer = BufWriter::new(file);
serde_json::to_writer_pretty(writer, &config)?;
// Read from file
let file = File::open("config.json")?;
let reader = BufReader::new(file);
let loaded_config: Config = serde_json::from_reader(reader)?;
println!("Loaded config: {:?}", loaded_config);
Ok(())
}
Custom Pretty Printing
use serde_json::{to_string_pretty, Value};
use serde_json::ser::PrettyFormatter;
fn main() -> Result<(), serde_json::Error> {
let data = serde_json::json!({
"users": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
],
"settings": {
"theme": "dark",
"language": "en"
}
});
// Default formatting (2 spaces)
let pretty = to_string_pretty(&data)?;
println!("Default formatting:\n{}", pretty);
// Custom formatter (4 spaces)
let buf = Vec::new();
let formatter = PrettyFormatter::with_indent(b" ");
let mut ser = serde_json::Serializer::with_formatter(buf, formatter);
data.serialize(&mut ser)?;
let result = String::from_utf8(ser.into_inner()).unwrap();
println!("\nCustom formatting (4 spaces):\n{}", result);
Ok(())
}
Error Handling
use serde::{Serialize, Deserialize};
use serde_json::{Error, Result};
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: u64,
name: String,
age: Option<u32>,
}
fn parse_user(json: &str) -> Result<User> {
serde_json::from_str(json)
}
fn main() {
// Valid JSON
let valid_json = r#"{"id": 1, "name": "Alice", "age": 30}"#;
match parse_user(valid_json) {
Ok(user) => println!("Parsed user: {:?}", user),
Err(e) => eprintln!("Error: {}", e),
}
// Invalid JSON (type mismatch)
let invalid_json = r#"{"id": "not_a_number", "name": "Bob"}"#;
match parse_user(invalid_json) {
Ok(user) => println!("Parsed user: {:?}", user),
Err(e) => {
eprintln!("Error: {}", e);
eprintln!("Line: {}, Column: {}", e.line(), e.column());
}
}
// Incomplete JSON
let incomplete_json = r#"{"id": 1, "name": "Charlie""#;
if let Err(e) = parse_user(incomplete_json) {
eprintln!("Parse error: {}", e);
// Determine error type
use serde_json::error::Category;
match e.classify() {
Category::Io => eprintln!("IO error"),
Category::Syntax => eprintln!("Syntax error"),
Category::Data => eprintln!("Data error"),
Category::Eof => eprintln!("Unexpected end of input"),
}
}
}