8 releases (stable)
1.1.3 | Jan 1, 2024 |
---|---|
1.1.2 | Dec 30, 2023 |
0.1.0 | Dec 8, 2023 |
#428 in Encoding
115 downloads per month
Used in 5 crates
53KB
1K
SLoC
WJP - Wizards JSON Parser
A library to parse raw Strings into workable types and vice versa.
Documentation:
Basic Usage:
Import the library into your Cargo.toml
[dependencies]
wjp = "1.1.3"
// Example Struct to show how this library works
#[derive(Debug)]
struct Example {
code: f32,
messages: Vec<String>,
opt: Option<bool>,
}
// Implementing the Serialize Trait allows you to call the .json() method on your struct
impl Serialize for Example {
fn serialize(&self) -> Values {
// The map!() macro is a helper to create a hashmap from the given values
Values::Struct(map!(
// Many Data Structures and Types already have Serialize implemented
("code", self.code.serialize()),
("messages", self.messages.serialize()),
("opt", self.opt.serialize())
))
}
}
// Implementing the TryFrom<Values> Trait allows you to deserialize a JSON String into your struct
impl TryFrom<Values> for Example {
// We advise on using the ParseError because many helper methods build on this error
type Error = ParseError;
fn try_from(value: Values) -> Result<Self, Self::Error> {
// Now you just need to get your struct / array and get the keys with their appropriate values
let mut struc = value.get_struct().ok_or(ParseError::new())?;
let code = struc.map_val("code", f32::try_from)?;
// Many Data Structures and Types already have TryFrom<Values> implemented
let messages = struc.map_val("messages", Vec::try_from)?;
// This is sadly not the case for Option<T> where your need to find out what the type of T is and parse that
let opt = struc.map_opt_val("opt", |val| val.get_bool())?;
Ok(Self {
opt,
messages,
code,
})
}
}
pub fn main() {
let example = Example {
code: 123.0,
messages: vec!["Important".to_string(), "Message".to_string()],
opt: None,
};
// After implementing these two traits you can call the .json() method to serialize your struct
let json = example.json();
println!("{}", json);
// And the <Your Type>::deserialize(&str/String) to deserialize it
let back = Example::deserialize(json);
println!("{:?}", back);
}
Output of the Example above:
{"opt":null,"code":123,"messages":["Important","Message"]}
Ok(Example { code: 123.0, messages: ["Important", "Message"], opt: None })
Explanation:
JSON is a lightweight, text-based, language-independent syntax for defining data interchange formats. Despite being language independent. It is not really optimised for the Rust language.
Example Json:
{
"type": "error",
"message": "A really bad Error occurred",
"code": 444
}
Key Value Pairs can have different positions every time:
{
"code": 444,
"message": "A really bad Error occurred",
"type": "error"
}
This is currently also the case for this library because the Struct implementation uses a HashMap that allocates Key-Value Pairs every time at a new place and delivers them at different positions
Key Value pairs can just not exist, have the value null or be a different type:
{
"code": null,
"type": 123.23
}
This is supported, but it makes the parsing part more difficult and is the Reason why
the User of this library needs to implement From<Values>
and Serialize
for each of
their Structs they want to parse
JSON supports the IEEE 754 Standard for storing numbers:
{
"plus": 1,
"minus": -1,
"minus-zero": -0,
"exponent": 10E10,
"minus-exponent": 10e-10,
"decimal-point": 1.2,
"decimal-point-exponent": 1.23E-10
}
This is supported, but just uses the f64::from_str()
underneath which should support all these cases
JSON also supports the UTF-8 Encoding
{
"text": "\u1234",
"info": " ^ This is not supported "
}
This library doesn't support \u escaped characters and doesn't advise on using escaped chars at all
JSON also supports different types inside of Arrays
[
true,
false,
null,
1.23,
false
]
This is supported, but the User needs to find out what to do with
the Vec<Values>
that can contain different types