Crates.io | nojson |
lib.rs | nojson |
version | 0.3.4 |
created_at | 2025-04-06 08:16:51.047912+00 |
updated_at | 2025-08-17 08:17:16.973821+00 |
description | A flexible JSON library with no dependencies and no macros |
homepage | https://github.com/sile/nojson |
repository | https://github.com/sile/nojson |
max_upload_size | |
id | 1622711 |
size | 149,277 |
A flexible Rust JSON library with no dependencies and no macros.
nojson
is a flexible and ergonomic JSON library for Rust that offers a balance between the type-safety of Rust and the dynamic nature of JSON.
Unlike serde
, which typically requires one-to-one mapping between Rust types and JSON structures (or other serialization formats),
nojson
provides a toolbox approach that allows you to leverage both type-level programming and imperative code flexibility.
The Json<T>
wrapper allows parsing JSON text into Rust types that implement TryFrom<RawJsonValue<'_, '_>>
:
use nojson::Json;
fn main() -> Result<(), nojson::JsonParseError> {
// Parse a JSON array into a typed Rust array
let text = "[1, null, 2]";
let value: Json<[Option<u32>; 3]> = text.parse()?;
assert_eq!(value.0, [Some(1), None, Some(2)]);
Ok(())
}
The DisplayJson
trait allows converting Rust types to JSON:
use nojson::Json;
// Generate a JSON array from a Rust array
let value = [Some(1), None, Some(2)];
assert_eq!(Json(value).to_string(), "[1,null,2]");
The json()
function provides a convenient way to generate JSON with custom formatting:
use nojson::json;
// Compact JSON
let compact = json(|f| f.value([1, 2, 3]));
assert_eq!(compact.to_string(), "[1,2,3]");
// Pretty-printed JSON with custom indentation
let pretty = json(|f| {
f.set_indent_size(2);
f.set_spacing(true);
f.array(|f| {
f.element(1)?;
f.element(2)?;
f.element(3)
})
});
assert_eq!(
format!("\n{}", pretty),
r#"
[
1,
2,
3
]"#
);
Implementing DisplayJson
and TryFrom<RawJsonValue<'_, '_>>
for your own types:
use nojson::{DisplayJson, Json, JsonFormatter, JsonParseError, RawJsonValue};
struct Person {
name: String,
age: u32,
}
impl DisplayJson for Person {
fn fmt(&self, f: &mut JsonFormatter<'_, '_>) -> std::fmt::Result {
f.object(|f| {
f.member("name", &self.name)?;
f.member("age", self.age)
})
}
}
impl<'text, 'raw> TryFrom<RawJsonValue<'text, 'raw>> for Person {
type Error = JsonParseError;
fn try_from(value: RawJsonValue<'text, 'raw>) -> Result<Self, Self::Error> {
let name = value.to_member("name")?.required()?;
let age = value.to_member("age")?.required()?;
Ok(Person {
name: name.try_into()?,
age: age.try_into()?,
})
}
}
fn main() -> Result<(), JsonParseError> {
// Parse JSON to Person
let json_text = r#"{"name":"Alice","age":30}"#;
let person: Json<Person> = json_text.parse()?;
// Generate JSON from Person
assert_eq!(Json(&person.0).to_string(), json_text);
Ok(())
}
You can add custom validations using RawJsonValue::invalid()
:
use nojson::{JsonParseError, RawJson, RawJsonValue};
fn parse_positive_number(text: &str) -> Result<u32, JsonParseError> {
let json = RawJson::parse(text)?;
let raw_value = json.value();
let num: u32 = raw_value.as_number_str()?
.parse()
.map_err(|e| raw_value.invalid(e))?;
if num == 0 {
return Err(raw_value.invalid("Expected a positive number, got 0"));
}
Ok(num)
}
Rich error information helps with debugging:
use nojson::{JsonParseError, RawJson};
let text = r#"{"invalid": 123e++}"#;
let result = RawJson::parse(text);
if let Err(error) = result {
println!("Error: {}", error);
// Get line and column information
if let Some((line, column)) = error.get_line_and_column_numbers(text) {
println!("At line {}, column {}", line, column);
}
// Get the full line with the error
if let Some(line_text) = error.get_line(text) {
println!("Line content: {}", line_text);
}
}