Structured Data
Recipe | Crates | Categories |
---|---|---|
Serialize and deserialize unstructured JSON | ||
Deserialize a TOML configuration file | ||
Read and write integers in little-endian byte order |
Serialize and deserialize unstructured JSON
The serde_json
⮳ crate provides a serde_json::from_str
⮳ function to parse a &str
of JSON.
Unstructured JSON can be parsed into a universal serde_json::Value
⮳ type that is able to represent any valid JSON data.
The example below shows a &str
of JSON being parsed. The expected value is declared using the serde_json::json
⮳ macro.
use serde_json::Error; use serde_json::Value; use serde_json::json; fn main() -> Result<(), Error> { let j: &str = r#"{ "userid": 103609, "verified": true, "access_privileges": [ "user", "admin" ] }"#; let parsed: Value = serde_json::from_str(j)?; let expected: Value = json!({ "userid": 103609, "verified": true, "access_privileges": [ "user", "admin" ] }); println!("{}", expected); assert_eq!(parsed, expected); Ok(()) }
Deserialize a TOML configuration file
TOML is a simple, ergonomic, and readable configuration format that is often used by Rust's tooling - for example cargo
⮳.
The following parses some TOML into a universal toml::Value
⮳ that is able to represent any valid TOML data.
use toml::Value; /* Representation of a TOML value e.g. String, * Integer, Float, Array, Table... */ use toml::de::Error; // TOML is a minimal configuration file format. // It is designed to map unambiguously to a hash table. fn main() -> Result<(), Error> { // Sample TOML. // Note the use of a Rust raw string, // so that there is no need to escape the inner double quotes let toml_content = r#" This is a TOML comment key = "value" "quoted key" = "possible but rare" A table a.k.a. hash tables or dictionaries: [table] key = 123 [strings] str1 = "basic string with \"escaping\" \n" str2 = 'literal string. No escaping is performed' str3 = """multi-line \ basic string""" str4 = '''multi-line literal strings allow a single quote ' inside''' [numbers] int1 = 42 hex1 = 0xdeadbeef # Or octal or binary float1 = 6.626e-34 [dates] dt1 = 2025-02-09T00:00:00-09:00 Dates, times, and datetimes with and without offsets are possible [arrays] basic = ["a", "b"] nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ] numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ] # Mixed-type arrays are allowed Dotted key notation table2.key = 3.14 Equivalent to #[table2] key = 3.14 [a.b] c = "1.0" Equivalent to a.b.c = "1.0" inline_table = { x = 1, y = 2 } [[array-of-tables]] name = "John" [[array-of-tables]] # Empty table within the array [[arrays-of-tables]] name = "Blake" "#; let toml: Value = toml::from_str(toml_content)?; assert_eq!(toml["table"]["key"].as_integer(), Some(123)); println!("{}", toml["strings"]["str1"].as_str().unwrap()); Ok(()) }
Parse TOML into your own structs using serde
⮳.
use std::collections::HashMap; use serde::Deserialize; use toml::de::Error; #[derive(Deserialize, Debug)] struct Config { package: Package, dependencies: HashMap<String, String>, } #[derive(Deserialize, Debug)] struct Package { name: String, version: String, authors: Vec<String>, } fn main() -> Result<(), Error> { let toml_content = r#" [package] name = "your_package" version = "0.1.0" authors = ["You! <you@example.org>"] [dependencies] serde = "1.0" "#; let package_info: Config = toml::from_str(toml_content)?; println!("{:?}", package_info); assert_eq!(package_info.package.name, "your_package"); assert_eq!(package_info.package.version, "0.1.0"); assert_eq!(package_info.package.authors, vec!["You! <you@example.org>"]); assert_eq!(package_info.dependencies["serde"], "1.0"); Ok(()) }
Read and write integers in little-endian byte order
byteorder
⮳ is a library for reading/writing numbers in big-endian and little-endian. It can reverse the significant bytes of structured data. This may be necessary when receiving information over the network, when bytes received are from another system.
use std::io::Error; use byteorder::LittleEndian; use byteorder::ReadBytesExt; use byteorder::WriteBytesExt; #[derive(Default, PartialEq, Debug)] struct Payload { kind: u8, value: u16, } fn encode(payload: &Payload) -> Result<Vec<u8>, Error> { let mut bytes = vec![]; bytes.write_u8(payload.kind)?; bytes.write_u16::<LittleEndian>(payload.value)?; Ok(bytes) } fn decode(mut bytes: &[u8]) -> Result<Payload, Error> { let payload = Payload { kind: bytes.read_u8()?, value: bytes.read_u16::<LittleEndian>()?, }; Ok(payload) } fn main() -> Result<(), Error> { let original_payload = Payload::default(); let encoded_bytes = encode(&original_payload)?; println!("{:?}", encoded_bytes); let decoded_payload = decode(&encoded_bytes)?; assert_eq!(original_payload, decoded_payload); println!("{:?}", decoded_payload); Ok(()) }