|
14 | 14 | #[forbid(non_camel_case_types)];
|
15 | 15 | #[allow(missing_doc)];
|
16 | 16 |
|
17 |
| -//! json parsing and serialization |
| 17 | +/*! |
| 18 | +JSON parsing and serialization |
| 19 | +
|
| 20 | +# What is JSON? |
| 21 | +
|
| 22 | +JSON (JavaScript Object Notation) is a way to write data in Javascript. |
| 23 | +Like XML it allows one to encode structured data in a text format that can be read by humans easily. |
| 24 | +Its native compatibility with JavaScript and its simple syntax make it used widely. |
| 25 | +
|
| 26 | +Json data are encoded in a form of "key":"value". |
| 27 | +Data types that can be encoded are JavaScript types : |
| 28 | +boolean (`true` or `false`), number (`f64`), string, array, object, null. |
| 29 | +An object is a series of string keys mapping to values, in `"key": value` format. |
| 30 | +Arrays are enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }). |
| 31 | +A simple JSON document encoding a person, his/her age, address and phone numbers could look like: |
| 32 | +
|
| 33 | +``` |
| 34 | +{ |
| 35 | + "FirstName": "John", |
| 36 | + "LastName": "Doe", |
| 37 | + "Age": 43, |
| 38 | + "Address": { |
| 39 | + "Street": "Downing Street 10", |
| 40 | + "City": "London", |
| 41 | + "Country": "Great Britain" |
| 42 | + }, |
| 43 | + "PhoneNumbers": [ |
| 44 | + "+44 1234567", |
| 45 | + "+44 2345678" |
| 46 | + ] |
| 47 | +} |
| 48 | +``` |
| 49 | +
|
| 50 | +# Rust Type-based Encoding and Decoding |
| 51 | +
|
| 52 | +Rust provides a mechanism for low boilerplate encoding & decoding |
| 53 | +of values to and from JSON via the serialization API. |
| 54 | +To be able to encode a piece of data, it must implement the `extra::serialize::Encodable` trait. |
| 55 | +To be able to decode a piece of data, it must implement the `extra::serialize::Decodable` trait. |
| 56 | +The Rust compiler provides an annotation to automatically generate |
| 57 | +the code for these traits: `#[deriving(Decodable, Encodable)]` |
| 58 | +
|
| 59 | +To encode using Encodable : |
| 60 | +
|
| 61 | +```rust |
| 62 | +use extra::json; |
| 63 | +use std::io; |
| 64 | +use extra::serialize::Encodable; |
| 65 | +
|
| 66 | + #[deriving(Encodable)] |
| 67 | + pub struct TestStruct { |
| 68 | + data_str: ~str, |
| 69 | + } |
| 70 | +
|
| 71 | +fn main() { |
| 72 | + let to_encode_object = TestStruct{data_str:~"example of string to encode"}; |
| 73 | + let mut m = io::MemWriter::new(); |
| 74 | + { |
| 75 | + let mut encoder = json::Encoder::new(&mut m as &mut std::io::Writer); |
| 76 | + to_encode_object.encode(&mut encoder); |
| 77 | + } |
| 78 | +} |
| 79 | +``` |
| 80 | +
|
| 81 | +Two wrapper functions are provided to encode a Encodable object |
| 82 | +into a string (~str) or buffer (~[u8]): `str_encode(&m)` and `buffer_encode(&m)`. |
| 83 | +
|
| 84 | +```rust |
| 85 | +use extra::json; |
| 86 | +let to_encode_object = ~"example of string to encode"; |
| 87 | +let encoded_str: ~str = json::Encoder::str_encode(&to_encode_object); |
| 88 | +``` |
| 89 | +
|
| 90 | +JSON API provide an enum `json::Json` and a trait `ToJson` to encode object. |
| 91 | +The trait `ToJson` encode object into a container `json::Json` and the API provide writer |
| 92 | +to encode them into a stream or a string ... |
| 93 | +
|
| 94 | +When using `ToJson` the `Encodable` trait implementation is not mandatory. |
| 95 | +
|
| 96 | +A basic `ToJson` example using a TreeMap of attribute name / attribute value: |
| 97 | +
|
| 98 | +
|
| 99 | +```rust |
| 100 | +use extra::json; |
| 101 | +use extra::json::ToJson; |
| 102 | +use extra::treemap::TreeMap; |
| 103 | +
|
| 104 | +pub struct MyStruct { |
| 105 | + attr1: u8, |
| 106 | + attr2: ~str, |
| 107 | +} |
| 108 | +
|
| 109 | +impl ToJson for MyStruct { |
| 110 | + fn to_json( &self ) -> json::Json { |
| 111 | + let mut d = ~TreeMap::new(); |
| 112 | + d.insert(~"attr1", self.attr1.to_json()); |
| 113 | + d.insert(~"attr2", self.attr2.to_json()); |
| 114 | + json::Object(d) |
| 115 | + } |
| 116 | +} |
| 117 | +
|
| 118 | +fn main() { |
| 119 | + let test2: MyStruct = MyStruct {attr1: 1, attr2:~"test"}; |
| 120 | + let tjson: json::Json = test2.to_json(); |
| 121 | + let json_str: ~str = tjson.to_str(); |
| 122 | +} |
| 123 | +``` |
| 124 | +
|
| 125 | +To decode a json string using `Decodable` trait : |
| 126 | +
|
| 127 | +```rust |
| 128 | +use extra::serialize::Decodable; |
| 129 | +
|
| 130 | +#[deriving(Decodable)] |
| 131 | +pub struct MyStruct { |
| 132 | + attr1: u8, |
| 133 | + attr2: ~str, |
| 134 | +} |
| 135 | +
|
| 136 | +fn main() { |
| 137 | + let json_str_to_decode: ~str = |
| 138 | + ~"{\"attr1\":1,\"attr2\":\"toto\"}"; |
| 139 | + let json_object = extra::json::from_str(json_str_to_decode); |
| 140 | + let mut decoder = extra::json::Decoder::new(json_object.unwrap()); |
| 141 | + let decoded_object: MyStruct = Decodable::decode(&mut decoder); // create the final object |
| 142 | +} |
| 143 | +``` |
| 144 | +
|
| 145 | +# Examples of use |
| 146 | +
|
| 147 | +## Using Autoserialization |
| 148 | +
|
| 149 | +Create a struct called TestStruct1 and serialize and deserialize it to and from JSON |
| 150 | +using the serialization API, using the derived serialization code. |
| 151 | +
|
| 152 | +```rust |
| 153 | +use extra::json; |
| 154 | +use extra::serialize::{Encodable, Decodable}; |
| 155 | +
|
| 156 | + #[deriving(Decodable, Encodable)] //generate Decodable, Encodable impl. |
| 157 | + pub struct TestStruct1 { |
| 158 | + data_int: u8, |
| 159 | + data_str: ~str, |
| 160 | + data_vector: ~[u8], |
| 161 | + } |
| 162 | +
|
| 163 | +// To serialize use the `json::str_encode` to encode an object in a string. |
| 164 | +// It calls the generated `Encodable` impl. |
| 165 | +fn main() { |
| 166 | + let to_encode_object = TestStruct1 |
| 167 | + {data_int: 1, data_str:~"toto", data_vector:~[2,3,4,5]}; |
| 168 | + let encoded_str: ~str = json::Encoder::str_encode(&to_encode_object); |
| 169 | +
|
| 170 | + // To unserialize use the `extra::json::from_str` and `extra::json::Decoder` |
| 171 | +
|
| 172 | + let json_object = extra::json::from_str(encoded_str); |
| 173 | + let mut decoder = json::Decoder::new(json_object.unwrap()); |
| 174 | + let decoded1: TestStruct1 = Decodable::decode(&mut decoder); // create the final object |
| 175 | +} |
| 176 | +``` |
| 177 | +
|
| 178 | +## Using `ToJson` |
| 179 | +
|
| 180 | +This example use the ToJson impl to unserialize the json string. |
| 181 | +Example of `ToJson` trait implementation for TestStruct1. |
| 182 | +
|
| 183 | +```rust |
| 184 | +use extra::json; |
| 185 | +use extra::json::ToJson; |
| 186 | +use extra::serialize::{Encodable, Decodable}; |
| 187 | +use extra::treemap::TreeMap; |
| 188 | +
|
| 189 | +#[deriving(Decodable, Encodable)] // generate Decodable, Encodable impl. |
| 190 | +pub struct TestStruct1 { |
| 191 | + data_int: u8, |
| 192 | + data_str: ~str, |
| 193 | + data_vector: ~[u8], |
| 194 | +} |
| 195 | +
|
| 196 | +impl ToJson for TestStruct1 { |
| 197 | + fn to_json( &self ) -> json::Json { |
| 198 | + let mut d = ~TreeMap::new(); |
| 199 | + d.insert(~"data_int", self.data_int.to_json()); |
| 200 | + d.insert(~"data_str", self.data_str.to_json()); |
| 201 | + d.insert(~"data_vector", self.data_vector.to_json()); |
| 202 | + json::Object(d) |
| 203 | + } |
| 204 | +} |
| 205 | +
|
| 206 | +fn main() { |
| 207 | + // Seralization using our impl of to_json |
| 208 | +
|
| 209 | + let test2: TestStruct1 = TestStruct1 {data_int: 1, data_str:~"toto", data_vector:~[2,3,4,5]}; |
| 210 | + let tjson: json::Json = test2.to_json(); |
| 211 | + let json_str: ~str = tjson.to_str(); |
| 212 | +
|
| 213 | + // Unserialize like before. |
| 214 | +
|
| 215 | + let mut decoder = json::Decoder::new(json::from_str(json_str).unwrap()); |
| 216 | + // create the final object |
| 217 | + let decoded2: TestStruct1 = Decodable::decode(&mut decoder); |
| 218 | +} |
| 219 | +``` |
| 220 | +
|
| 221 | +*/ |
18 | 222 |
|
19 | 223 | use std::char;
|
20 | 224 | use std::cast::transmute;
|
@@ -93,6 +297,23 @@ impl<'a> Encoder<'a> {
|
93 | 297 | pub fn new<'a>(wr: &'a mut io::Writer) -> Encoder<'a> {
|
94 | 298 | Encoder { wr: wr }
|
95 | 299 | }
|
| 300 | + |
| 301 | + /// Encode the specified struct into a json [u8] |
| 302 | + pub fn buffer_encode<T:Encodable<Encoder<'a>>>(to_encode_object: &T) -> ~[u8] { |
| 303 | + //Serialize the object in a string using a writer |
| 304 | + let mut m = MemWriter::new(); |
| 305 | + { |
| 306 | + let mut encoder = Encoder::new(&mut m as &mut io::Writer); |
| 307 | + to_encode_object.encode(&mut encoder); |
| 308 | + } |
| 309 | + m.unwrap() |
| 310 | + } |
| 311 | + |
| 312 | + /// Encode the specified struct into a json str |
| 313 | + pub fn str_encode<T:Encodable<Encoder<'a>>>(to_encode_object: &T) -> ~str { |
| 314 | + let buff:~[u8] = Encoder::buffer_encode(to_encode_object); |
| 315 | + str::from_utf8_owned(buff) |
| 316 | + } |
96 | 317 | }
|
97 | 318 |
|
98 | 319 | impl<'a> serialize::Encoder for Encoder<'a> {
|
|
0 commit comments