rust-cookbook/src/encoding.md
2017-05-19 15:10:29 +02:00

8.9 KiB

Encoding

Recipe Crates Categories
Serialize and deserialize unstructured JSON serde-json-badge cat-encoding-badge
Deserialize a TOML configuration file toml-badge cat-encoding-badge
Percent-encode a string url-badge cat-encoding-badge
Encode and decode hex data-encoding-badge cat-encoding-badge
Encode and decode base64 base64-badge cat-encoding-badge

Serialize and deserialize unstructured JSON

serde-json-badge cat-encoding-badge

The serde_json crate provides a from_str function to parse a &str of JSON into a type of the caller's choice.

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 and then compared to what we expect the parsed value to be. The expected value is declared using the json! macro.

#[macro_use]
extern crate serde_json;

#[macro_use]
extern crate error_chain;

use serde_json::Value;

error_chain! {
    foreign_links {
        Json(serde_json::Error);
    }
}

fn run() -> Result<()> {
    let j = r#"{
                 "userid": 103609,
                 "verified": true,
                 "access_privileges": [
                   "user",
                   "admin"
                 ]
               }"#;

    let parsed: Value = serde_json::from_str(j)?;

    let expected = json!({
        "userid": 103609,
        "verified": true,
        "access_privileges": [
            "user",
            "admin"
        ]
    });

    assert_eq!(parsed, expected);

    Ok(())
}

quick_main!(run);

Deserialize a TOML configuration file

toml-badge cat-encoding-badge

Parse some TOML into a universal toml::Value that is able to represent any valid TOML data.

extern crate toml;

#[macro_use]
extern crate error_chain;

use toml::Value;

error_chain! {
    foreign_links {
        Toml(toml::de::Error);
    }
}

fn run() -> Result<()> {
    let toml_content = r#"
          [package]
          name = "your_package"
          version = "0.1.0"
          authors = ["You! <you@example.org>"]

          [dependencies]
          serde = "1.0"
          "#;

    let package_info: Value = toml::from_str(toml_content)?;

    assert_eq!(package_info["dependencies"]["serde"].as_str(), Some("1.0"));
    assert_eq!(package_info["package"]["name"].as_str(), Some("your_package"));

    Ok(())
}

quick_main!(run);

Parse TOML into your own structs using Serde:

serde-json-badge toml-badge cat-encoding-badge

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate toml;

#[macro_use]
extern crate error_chain;

use std::collections::HashMap;

#[derive(Deserialize)]
struct Config {
    package: Package,
    dependencies: HashMap<String, String>,
}

#[derive(Deserialize)]
struct Package {
    name: String,
    version: String,
    authors: Vec<String>,
}

error_chain! {
    foreign_links {
        Toml(toml::de::Error);
    }
}

fn run() -> Result<()> {
    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)?;

    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(())
}

quick_main!(run);

Percent-encode a string

url-badge cat-encoding-badge

Encode an input string with percent-encoding using the utf8_percent_encode function from the url crate. Then decode using the percent_decode function.

extern crate url;

#[macro_use]
extern crate error_chain;

use url::percent_encoding::{utf8_percent_encode, percent_decode, DEFAULT_ENCODE_SET};

error_chain! {
    foreign_links {
        Utf8(std::str::Utf8Error);
    }
}

fn run() -> Result<()> {
    let input = "confident, productive systems programming";

    let iter = utf8_percent_encode(input, DEFAULT_ENCODE_SET);
    let encoded: String = iter.collect();
    assert_eq!(encoded, "confident,%20productive%20systems%20programming");

    let iter = percent_decode(encoded.as_bytes());
    let decoded = iter.decode_utf8()?;
    assert_eq!(decoded, "confident, productive systems programming");

    Ok(())
}

quick_main!(run);

The encode set defines which bytes (in addition to non-ASCII and controls) need to be percent-encoded. The choice of this set depends on context. For example, ? needs to be encoded in a URL path but not in a query string.

The return value of encoding is an iterator of &str slices which can be collected into a String.

Encode and decode hex

data-encoding-badge cat-encoding-badge

The data_encoding crate provides a HEXUPPER::encode method which takes a &[u8] and returns a String containing the hexadecimal representation of the data.

Similarly, a HEXUPPER::decode method is provided which takes a &[u8] and returns a Vec<u8> if the input data is successfully decoded.

The example below shows a &[u8] of data being converted to its hexadecimal representation and then being compared to its expected value. The returned hex String is then converted back to its original representation and is compared to the original value provided.

extern crate data_encoding;

#[macro_use]
extern crate error_chain;

use data_encoding::{HEXUPPER, DecodeError};

error_chain! {
    foreign_links {
        Decode(DecodeError);
    }
}

fn run() -> Result<()> {
    let original = b"The quick brown fox jumps over the lazy dog.";
    let expected = "54686520717569636B2062726F776E20666F78206A756D7073206F76\
        657220746865206C617A7920646F672E";
    
    let encoded = HEXUPPER.encode(original);
    assert_eq!(encoded, expected);

    let decoded = HEXUPPER.decode(&encoded.into_bytes())?;
    assert_eq!(&decoded[..], &original[..]);

    Ok(())
}

quick_main!(run);

Encode and decode base64

base64-badge cat-encoding-badge

Byte slice is encoded into base64 String with help of encode and subsequently decoded with decode.

#[macro_use]
extern crate error_chain;
extern crate base64;

use std::str;
use base64::{encode, decode};

error_chain! {
    foreign_links {
        Base64(base64::DecodeError);
        Utf8Error(str::Utf8Error);
    }
}

fn run() -> Result<()> {
    let hello = b"hello rustaceans";
    let encoded = encode(hello);
    let decoded = decode(&encoded)?;

    println!("origin: {}", str::from_utf8(hello)?);
    println!("base64 encoded: {}", encoded);
    println!("back to origin: {}", str::from_utf8(&decoded)?);

    Ok(())
}

quick_main!(run);