]> git.proxmox.com Git - rustc.git/blob - src/vendor/toml-0.1.30/src/encoder/mod.rs
New upstream version 1.20.0+dfsg1
[rustc.git] / src / vendor / toml-0.1.30 / src / encoder / mod.rs
1 use std::collections::BTreeMap;
2 use std::error;
3 use std::fmt;
4 use std::mem;
5
6 use {Value, Table};
7
8 #[cfg(feature = "rustc-serialize")] mod rustc_serialize;
9 #[cfg(feature = "serde")] mod serde;
10
11 /// A structure to transform Rust values into TOML values.
12 ///
13 /// This encoder implements the serialization `Encoder` interface, allowing
14 /// `Encodable` rust types to be fed into the encoder. The output of this
15 /// encoder is a TOML `Table` structure. The resulting TOML can be stringified
16 /// if necessary.
17 ///
18 /// # Example
19 ///
20 /// ```
21 /// extern crate rustc_serialize;
22 /// extern crate toml;
23 ///
24 /// # fn main() {
25 /// use toml::{Encoder, Value};
26 /// use rustc_serialize::Encodable;
27 ///
28 /// #[derive(RustcEncodable)]
29 /// struct MyStruct { foo: isize, bar: String }
30 /// let my_struct = MyStruct { foo: 4, bar: "hello!".to_string() };
31 ///
32 /// let mut e = Encoder::new();
33 /// my_struct.encode(&mut e).unwrap();
34 ///
35 /// assert_eq!(e.toml.get(&"foo".to_string()), Some(&Value::Integer(4)))
36 /// # }
37 /// ```
38 pub struct Encoder {
39 /// Output TOML that is emitted. The current version of this encoder forces
40 /// the top-level representation of a structure to be a table.
41 ///
42 /// This field can be used to extract the return value after feeding a value
43 /// into this `Encoder`.
44 pub toml: Table,
45 state: State,
46 }
47
48 /// Enumeration of errors which can occur while encoding a rust value into a
49 /// TOML value.
50 #[allow(missing_copy_implementations)]
51 #[derive(Debug)]
52 pub enum Error {
53 /// Indication that a key was needed when a value was emitted, but no key
54 /// was previously emitted.
55 NeedsKey,
56 /// Indication that a key was emitted, but not value was emitted.
57 NoValue,
58 /// Indicates that a map key was attempted to be emitted at an invalid
59 /// location.
60 InvalidMapKeyLocation,
61 /// Indicates that a type other than a string was attempted to be used as a
62 /// map key type.
63 InvalidMapKeyType,
64 /// A custom error type was generated
65 Custom(String),
66 }
67
68 #[derive(PartialEq)]
69 enum State {
70 Start,
71 NextKey(String),
72 NextArray(Vec<Value>),
73 NextMapKey,
74 }
75
76 impl Encoder {
77 /// Constructs a new encoder which will emit to the given output stream.
78 pub fn new() -> Encoder {
79 Encoder { state: State::Start, toml: BTreeMap::new() }
80 }
81
82 fn emit_value(&mut self, v: Value) -> Result<(), Error> {
83 match mem::replace(&mut self.state, State::Start) {
84 State::NextKey(key) => { self.toml.insert(key, v); Ok(()) }
85 State::NextArray(mut vec) => {
86 // TODO: validate types
87 vec.push(v);
88 self.state = State::NextArray(vec);
89 Ok(())
90 }
91 State::NextMapKey => {
92 match v {
93 Value::String(s) => { self.state = State::NextKey(s); Ok(()) }
94 _ => Err(Error::InvalidMapKeyType)
95 }
96 }
97 _ => Err(Error::NeedsKey)
98 }
99 }
100
101 fn emit_none(&mut self) -> Result<(), Error> {
102 match mem::replace(&mut self.state, State::Start) {
103 State::Start => unreachable!(),
104 State::NextKey(_) => Ok(()),
105 State::NextArray(..) => panic!("how to encode None in an array?"),
106 State::NextMapKey => Err(Error::InvalidMapKeyLocation),
107 }
108 }
109
110 fn seq<F>(&mut self, f: F) -> Result<(), Error>
111 where F: FnOnce(&mut Encoder) -> Result<(), Error>
112 {
113 let old = mem::replace(&mut self.state, State::NextArray(Vec::new()));
114 try!(f(self));
115 match mem::replace(&mut self.state, old) {
116 State::NextArray(v) => self.emit_value(Value::Array(v)),
117 _ => unreachable!(),
118 }
119 }
120
121 fn table<F>(&mut self, f: F) -> Result<(), Error>
122 where F: FnOnce(&mut Encoder) -> Result<(), Error>
123 {
124 match mem::replace(&mut self.state, State::Start) {
125 State::NextKey(key) => {
126 let mut nested = Encoder::new();
127 try!(f(&mut nested));
128 self.toml.insert(key, Value::Table(nested.toml));
129 Ok(())
130 }
131 State::NextArray(mut arr) => {
132 let mut nested = Encoder::new();
133 try!(f(&mut nested));
134 arr.push(Value::Table(nested.toml));
135 self.state = State::NextArray(arr);
136 Ok(())
137 }
138 State::Start => f(self),
139 State::NextMapKey => Err(Error::InvalidMapKeyLocation),
140 }
141 }
142
143 fn table_key<F>(&mut self, f: F) -> Result<(), Error>
144 where F: FnOnce(&mut Encoder) -> Result<(), Error>
145 {
146 match mem::replace(&mut self.state, State::NextMapKey) {
147 State::Start => {}
148 _ => return Err(Error::InvalidMapKeyLocation),
149 }
150 try!(f(self));
151 match self.state {
152 State::NextKey(_) => Ok(()),
153 _ => Err(Error::InvalidMapKeyLocation),
154 }
155 }
156 }
157
158 /// Encodes an encodable value into a TOML value.
159 ///
160 /// This function expects the type given to represent a TOML table in some form.
161 /// If encoding encounters an error, then this function will fail the task.
162 #[cfg(feature = "rustc-serialize")]
163 pub fn encode<T: ::rustc_serialize::Encodable>(t: &T) -> Value {
164 let mut e = Encoder::new();
165 t.encode(&mut e).unwrap();
166 Value::Table(e.toml)
167 }
168
169 /// Encodes an encodable value into a TOML value.
170 ///
171 /// This function expects the type given to represent a TOML table in some form.
172 /// If encoding encounters an error, then this function will fail the task.
173 #[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))]
174 pub fn encode<T: ::serde::Serialize>(t: &T) -> Value {
175 let mut e = Encoder::new();
176 t.serialize(&mut e).unwrap();
177 Value::Table(e.toml)
178 }
179
180 /// Encodes an encodable value into a TOML string.
181 ///
182 /// This function expects the type given to represent a TOML table in some form.
183 /// If encoding encounters an error, then this function will fail the task.
184 #[cfg(feature = "rustc-serialize")]
185 pub fn encode_str<T: ::rustc_serialize::Encodable>(t: &T) -> String {
186 encode(t).to_string()
187 }
188
189 /// Encodes an encodable value into a TOML string.
190 ///
191 /// This function expects the type given to represent a TOML table in some form.
192 /// If encoding encounters an error, then this function will fail the task.
193 #[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))]
194 pub fn encode_str<T: ::serde::Serialize>(t: &T) -> String {
195 encode(t).to_string()
196 }
197
198 impl fmt::Display for Error {
199 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200 match *self {
201 Error::NeedsKey => write!(f, "need a key to encode"),
202 Error::NoValue => write!(f, "no value to emit for a previous key"),
203 Error::InvalidMapKeyLocation => write!(f, "a map cannot be emitted \
204 at this location"),
205 Error::InvalidMapKeyType => write!(f, "only strings can be used as \
206 key types"),
207 Error::Custom(ref s) => write!(f, "custom error: {}", s),
208 }
209 }
210 }
211
212 impl error::Error for Error {
213 fn description(&self) -> &str { "TOML encoding error" }
214 }