pub trait JsonlValueDeserialize {
// Required method
fn deserialize_values(self) -> impl Stream<Item = Result<Value>>;
}
Expand description
Extension trait specifically for deserializing JSONL to serde_json::Value
objects.
This trait provides a convenient method to deserialize JSON lines into generic
serde_json::Value
objects when you don’t know the exact structure of the JSON
data ahead of time or when working with heterogeneous JSON objects.
§Examples
§Basic Usage with Dynamic JSON
ⓘ
use async_jsonl::{Jsonl, JsonlValueDeserialize};
use futures::StreamExt;
use std::io::Cursor;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let data = r#"{"user_id": 123, "action": "login", "timestamp": "2024-01-01T10:00:00Z"}
{"user_id": 456, "action": "logout", "timestamp": "2024-01-01T11:00:00Z"}
{"user_id": 789, "action": "purchase", "item": "widget", "price": 29.99}"#;
let reader = Jsonl::new(Cursor::new(data.as_bytes()));
let mut value_stream = reader.deserialize_values();
while let Some(result) = value_stream.next().await {
match result {
Ok(value) => {
println!("Event: {}", value["action"]);
if let Some(price) = value.get("price") {
println!(" Purchase amount: {}", price);
}
}
Err(e) => eprintln!("Failed to parse JSON: {}", e),
}
}
Ok(())
}
§Processing Mixed JSON Structures
ⓘ
use async_jsonl::{Jsonl, JsonlValueDeserialize};
use futures::StreamExt;
use serde_json::Value;
use std::io::Cursor;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mixed_data = r#"{"type": "user", "name": "Alice", "age": 30}
{"type": "product", "name": "Widget", "price": 19.99, "categories": ["tools", "hardware"]}
{"type": "event", "name": "click", "target": "button", "metadata": {"page": "/home"}}"#;
let reader = Jsonl::new(Cursor::new(mixed_data.as_bytes()));
let values: Vec<Value> = reader
.deserialize_values()
.collect::<Vec<_>>()
.await
.into_iter()
.collect::<Result<Vec<_>, _>>()?;
for value in values {
match value["type"].as_str() {
Some("user") => println!("User: {} (age {})", value["name"], value["age"]),
Some("product") => println!("Product: {} - ${}", value["name"], value["price"]),
Some("event") => println!("Event: {} on {}", value["name"], value["target"]),
_ => println!("Unknown type: {:?}", value),
}
}
Ok(())
}
§Error Handling with Invalid JSON
ⓘ
use async_jsonl::{Jsonl, JsonlValueDeserialize};
use futures::StreamExt;
use std::io::Cursor;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let data_with_errors = r#"{"valid": "json"}
{invalid json line
{"another": "valid line"}"#;
let reader = Jsonl::new(Cursor::new(data_with_errors.as_bytes()));
let mut value_stream = reader.deserialize_values();
let mut valid_count = 0;
let mut error_count = 0;
while let Some(result) = value_stream.next().await {
match result {
Ok(_) => valid_count += 1,
Err(_) => error_count += 1,
}
}
println!("Valid JSON lines: {}, Errors: {}", valid_count, error_count);
Ok(())
}
Required Methods§
Sourcefn deserialize_values(self) -> impl Stream<Item = Result<Value>>
fn deserialize_values(self) -> impl Stream<Item = Result<Value>>
Deserialize JSON lines into serde_json::Value
objects.
This method transforms each line of a JSONL stream into serde_json::Value
objects,
which can represent any valid JSON structure. This is useful when:
- You don’t know the exact structure of the JSON data ahead of time
- You’re working with heterogeneous JSON objects in the same file
- You want to inspect or transform JSON data dynamically
- You need to handle mixed or evolving JSON schemas
§Returns
Returns a Stream
of anyhow::Result<Value>
where:
Ok(Value)
represents a successfully parsed JSON valueErr(anyhow::Error)
represents parsing errors for invalid JSON lines
§Examples
ⓘ
use async_jsonl::{Jsonl, JsonlValueDeserialize};
use futures::StreamExt;
use std::io::Cursor;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let data = r#"{"id": 1, "data": {"nested": [1, 2, 3]}}
{"id": 2, "data": {"different": "structure"}}"#;
let reader = Jsonl::new(Cursor::new(data.as_bytes()));
let values: Vec<_> = reader
.deserialize_values()
.collect()
.await;
for (i, result) in values.iter().enumerate() {
match result {
Ok(value) => println!("Object {}: ID = {}", i + 1, value["id"]),
Err(e) => eprintln!("Error parsing object {}: {}", i + 1, e),
}
}
Ok(())
}
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.