Serialize JSON in a recursive struct - json

I have this JSON:
{
"argument0": {
"argument1": "test",
"argument2": {
"argument3": "test3"
}
}
}
I need to use some kind of recursive struct with methods like the HashMap<String, _> in Rust. The key should always be a String but the value can be a String or the same Argument struct.
#[derive(Clone, RustcDecodable, RustcEncodable)]
struct Argument {
key: String
value: String Or Argument
}
How can I achieve this?

You have a few distinct problems here.
First, you want to be able to define a data type that can be either one type or another type, but not both. This is what Rust's enum data type is intended for.
enum Value {
String(String),
Argument(Argument),
}
This Value type can contain either a String or an Argument, but not both.
Now, we need to define the Argument type. In your example, an argument can contain arbitrary field names, so we can't just define a struct. Instead, we can use a map collection from the standard library to map Strings to Values, such as BTreeMap. We'll also define a type alias so that we can use the name Argument instead of BTreeMap<String, Argument> elsewhere in the program.
use std::collections::BTreeMap;
type Argument = BTreeMap<String, Argument>;
Now that we've successfully defined the type, let's define its serialization behavior using the serde library. Serde can automatically serialize types from the Rust standard library, and user structs can implement or derive the Serialize and Deserialize traits to add the functionality to their own types.
For most structs, we can just add a #[derive(Serialize)] and/or #[derive(Deserialize)] to implement the necessary traits for serialization. In this case, we want to customize the deserialization of our enum to be untagged, so it just emits the value of the enum, not an object with "String" or "Argument" as the key. Instead, we just want the JSON to contain the value. We do this by adding a special attribute to the struct, #[serde(untagged)].
Here's a short Rust program that demonstrates the above concepts. This program will read your JSON example, and print the Debug representation of a Rust type that represents the data.
#[macro_use]
extern crate serde_derive; // 1.0.78
extern crate serde; // 1.0.78
extern crate serde_json; // 1.0.27
use std::collections::BTreeMap;
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
enum Value {
String(String),
Argument(Argument),
}
type Argument = BTreeMap<String, Value>;
fn main() {
let argument: Argument = serde_json::from_str(
r#"{
"argument0": {
"argument1": "test",
"argument2": {
"argument3": "test3"
}
}
}"#,
).unwrap();
println!("{:?}", argument);
}

Related

Functions as the struct fields or as struct methods

Could anybody help me to clarify in which situations is better to use functions as the struct fields and when as the methods of struct?
A field of function type is not a method, so it's not part of the method set of the struct type. A "true" method declared with the struct type as the receiver will be part of the method set.
That being said, if you want to implement an interface, you have no choice but to define "true" methods.
Methods are "attached" to concrete types and cannot be changed at runtime. A field of function type may be used to "mimic" virtual methods, but as said above, this is not a method. A field of function type may be reassigned at runtime.
Like in this example:
type Foo struct {
Bar func()
}
func main() {
f := Foo{
Bar: func() { fmt.Println("initial") },
}
f.Bar()
f.Bar = func() { fmt.Println("changed") }
f.Bar()
}
Which outputs (try it on the Go Playground):
initial
changed
Fields of function type are often used to store callback functions. Examples from the standard lib are http.Server and http.Transport.

How to use an arbitrary type as a function argument?

I am trying to write a generic function to pick up a random element in a vector of any kind. How can I specify an arbitrary vector type?
For example:
let list1: Vec<u32> = vec![1, 2, 3];
let list2: Vec<&str> = vec!["foo", "bar"];
fn print_a_random_element(a_list: Vec<?????>) {
// do some stuff
}
print_a_random_element(list1); // get error
print_a_random_element(list2); // get error
Generic types specific to a function are declared using the <> syntax on the function definition:
fn print_a_random_element<T>(a_list: Vec<T>) {
// do some stuff
}
See also:
Generic Types, Traits, and Lifetimes in The Rust Programming Language
Generic function to take struct as parameter in rust
How to restrict generic implementation of a trait in Rust?
Is there any way to restrict a generic type to one of several types?

How to write a function that takes a slice of functions?

I am trying to write a function that takes a slice of functions. Consider the following simple illustration:
fn g<P: Fn(&str) -> usize>(ps: &[P]) { }
fn f1() -> impl Fn(&str) -> usize { |s: &str| s.len() }
fn f2() -> impl Fn(&str) -> usize { |s: &str| s.len() }
fn main() {
g(&[f1(), f2()][..]);
}
It fails to compile:
error[E0308]: mismatched types
--> src/main.rs:6:15
|
6 | g(&[f1(), f2()][..]);
| ^^^^ expected opaque type, found a different opaque type
|
= note: expected type `impl for<'r> std::ops::Fn<(&'r str,)>` (opaque type)
found type `impl for<'r> std::ops::Fn<(&'r str,)>` (opaque type)
Is there any way to do this?
Your problem is that every element of the array must be of the same type, but the return of a function declared as returning impl Trait is an opaque type, that is an unspecified, unnamed type, that you can only use by means of the given trait.
You have two functions that return the same impl Trait but that does not mean that they return the same type. In fact, as your compiler shows, they are different opaque types, so they cannot be part of the same array. If you were to write an array of values of the same type, such as:
g(&[f1(), f1(), f1()]);
then it would work. But with different functions, there will be different types and the array is impossible to build.
Does that mean there is no solution for your problem? Of course not! You just have to invoke dynamic dispatch. That is you have to make your slice of type &[&dyn Fn(&str) -> usize]. For that you need to do two things:
Add a level of indirection: dynamic dispatching is always done via references or pointers (&dyn Trait or Box<dyn Trait> instead of Trait).
Do an explicit cast to the &dyn Trait to avoid ambiguities in the conversion.
There are many ways to do the cast: you can cast the first element of the array, or you can declare the temporary variables, or give the slice a type. I prefer the latter, because it is more symmetric. Something like this:
fn main() {
let fns: &[&dyn Fn(&str) -> usize] =
&[&f1(), &f2()];
g(fns);
}
Link to a playground with this solution.

Rust scoping rules for struct-owned functions

I am trying to understand what exactly the scope is for functions defined within an impl block but which don't accept &self as a parameter. For example, why doesn't the following chunk of code compile? I get the error "cannot find function generate_a_result in this scope".
pub struct Blob {
num: u32,
}
impl Blob {
pub fn new() -> Blob {
generate_a_result()
}
fn generate_a_result() -> Blob {
let result = Blob {
num: 0
};
result
}
}
These functions are called associated functions. And they live in the namespace of the type. They always have to be called like Type::function(). In your case, that's Blob::generate_a_result(). But for referring to your own type, there is the special keyword Self. So the best solution is:
Self::generate_a_result()

Rust Json serialization overlapping responsibilities

I'm learning Json serialization in Rust, in particular, how to serialize Rust objects to Json.
Currently I see 3 methods of converting an instance of a struct to Json:
Deriving Encodable trait
Manual implementation of ToJson trait
Manual implementation of Encodable trait
Below code illustrates all 3 approaches:
extern crate serialize;
use serialize::{Encoder, Encodable, json};
use serialize::json::{Json, ToJson};
use std::collections::TreeMap;
fn main() {
let document = Document::new();
let word_document = WordDocument::new();
println!("1. Deriving `Encodable`: {}", json::encode(&document));
println!("2. Manually implementing `ToJson` trait: {}", document.to_json());
println!("3. Manually implementing `Encodable` trait: {}", json::encode(&word_document));
}
#[deriving(Encodable)]
struct Document<'a> {
metadata: Vec<(&'a str, &'a str)>
}
impl<'a> Document<'a> {
fn new() -> Document<'a> {
let metadata = vec!(("Title", "Untitled Document 1"));
Document {metadata: metadata}
}
}
impl<'a> ToJson for Document<'a> {
fn to_json(&self) -> Json {
let mut tm = TreeMap::new();
for &(ref mk, ref mv) in self.metadata.iter() {
tm.insert(mk.to_string(), mv.to_string().to_json());
}
json::Object(tm)
}
}
struct WordDocument<'a> {
metadata: Vec<(&'a str, &'a str)>
}
impl<'a> WordDocument<'a> {
fn new() -> WordDocument<'a> {
let metadata = vec!(("Title", "Untitled Word Document 1"));
WordDocument {metadata: metadata}
}
}
impl<'a, E, S: Encoder<E>> Encodable<S, E> for WordDocument<'a> {
fn encode(&self, s: &mut S) -> Result<(), E> {
s.emit_map(self.metadata.len(), |e| {
let mut i = 0;
for &(ref key, ref val) in self.metadata.iter() {
try!(e.emit_map_elt_key(i, |e| key.encode(e)));
try!(e.emit_map_elt_val(i, |e| val.encode(e)));
i += 1;
}
Ok(())
})
}
}
Rust playpen: http://is.gd/r7cYmE
Results:
1. Deriving `Encodable`: {"metadata":[["Title","Untitled Document 1"]]}
2. Manually implementing `ToJson` trait: {"Title":"Untitled Document 1"}
3. Manually implementing `Encodable` trait: {"Title":"Untitled Word Document 1"}
First method is fully automatic, but does not provide sufficient flexibility.
Second and third achieve same level of flexibility by specifying the serialization process manually. In my case I want document metadata to be serialized as an object, not as an array (which is what deriving implementation gives me).
Questions:
Why do methods 2 and 3 exist at all? I don't understand the reason for the overlap between them. I would expect there to exist only one automatic (deriving) method of serialization and one manual.
If I want manual serialization, which method should I choose and why?
Am I right in assuming that method 2 will build a Json enum in memory (besides the struct itself) and is a worse fit for huge documents (multi megabytes), while method 3 is streaming and safer for huge documents?
Why does rust stdlib use method 3 even for primitives, while not using method 2 internally?
Why do methods 2 and 3 exist at all? I don't understand the reason for the overlap between them. I would expect there to exist only one automatic (deriving) method of serialization and one manual.
Method 2 (the ToJson trait) is specific to encoding JSON. It returns JSON objects, instead of writing to a stream. One example of use is for mapping to custom representations - see this example in the documentation.
Method 3 (implementing Encodable) has to exist for method 1 to work.
Am I right in assuming that method 2 will build a Json enum in memory (besides the struct itself) and is a worse fit for huge documents (multi megabytes), while method 3 is streaming and safer for huge documents?
Yes. ToJson creates a nested Json enum of the whole object, while Encodable streams to a Writer.
If I want manual serialization, which method should I choose and why?
Why does rust stdlib use method 3 even for primitives, while not using method 2 internally?
You should use Encodable. It is not specific to the JSON format, does not use an intermediate representation (so can be streamed instead of stored in memory) and should continue to work with new formats added to the library.