• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Protobuf "text format" implementation.
2 //!
3 //! Text format message look like this:
4 //!
5 //! ```text,ignore
6 //! size: 17
7 //! color: "red"
8 //! children {
9 //!     size: 18
10 //!     color: "blue"
11 //! }
12 //! children {
13 //!     size: 19
14 //!     color: "green"
15 //! }
16 //! ```
17 //!
18 //! This format is not specified, but it is implemented by all official
19 //! protobuf implementations, including `protoc` command which can decode
20 //! and encode messages using text format.
21 
22 use std;
23 use std::fmt;
24 use std::fmt::Write;
25 
26 use crate::message::Message;
27 use crate::reflect::ReflectFieldRef;
28 use crate::reflect::ReflectValueRef;
29 
30 mod print;
31 
32 // Used by text format parser and by pure-rust codegen parsed
33 // this it is public but hidden module.
34 // https://github.com/rust-lang/rust/issues/44663
35 #[doc(hidden)]
36 pub mod lexer;
37 
38 use self::print::print_str_to;
39 #[doc(hidden)]
40 pub use self::print::quote_bytes_to;
41 #[doc(hidden)]
42 pub use self::print::quote_escape_bytes;
43 use crate::text_format::print::quote_escape_bytes_to;
44 
45 #[doc(hidden)]
unescape_string(string: &str) -> Vec<u8>46 pub fn unescape_string(string: &str) -> Vec<u8> {
47     fn parse_if_digit(chars: &mut std::str::Chars) -> u8 {
48         let mut copy = chars.clone();
49         let f = match copy.next() {
50             None => return 0,
51             Some(f) => f,
52         };
53         let d = match f {
54             '0'..='9' => (f as u8 - b'0'),
55             _ => return 0,
56         };
57         *chars = copy;
58         d
59     }
60 
61     fn parse_hex_digit(chars: &mut std::str::Chars) -> u8 {
62         match chars.next().unwrap() {
63             c @ '0'..='9' => (c as u8) - b'0',
64             c @ 'a'..='f' => (c as u8) - b'a' + 10,
65             c @ 'A'..='F' => (c as u8) - b'A' + 10,
66             _ => panic!("incorrect hex escape"),
67         }
68     }
69 
70     fn parse_escape_rem(chars: &mut std::str::Chars) -> u8 {
71         let n = chars.next().unwrap();
72         match n {
73             'a' => return b'\x07',
74             'b' => return b'\x08',
75             'f' => return b'\x0c',
76             'n' => return b'\n',
77             'r' => return b'\r',
78             't' => return b'\t',
79             'v' => return b'\x0b',
80             '"' => return b'"',
81             '\'' => return b'\'',
82             '0'..='9' => {
83                 let d1 = n as u8 - b'0';
84                 let d2 = parse_if_digit(chars);
85                 let d3 = parse_if_digit(chars);
86                 return (d1 * 64 + d2 * 8 + d3) as u8;
87             }
88             'x' => {
89                 let d1 = parse_hex_digit(chars);
90                 let d2 = parse_hex_digit(chars);
91                 return d1 * 16 + d2;
92             }
93             c => return c as u8, // TODO: validate ASCII
94         };
95     }
96 
97     let mut chars = string.chars();
98     let mut r = Vec::new();
99 
100     loop {
101         let f = match chars.next() {
102             None => return r,
103             Some(f) => f,
104         };
105 
106         if f == '\\' {
107             r.push(parse_escape_rem(&mut chars));
108         } else {
109             r.push(f as u8); // TODO: escape UTF-8
110         }
111     }
112 }
113 
do_indent(buf: &mut String, pretty: bool, indent: usize)114 fn do_indent(buf: &mut String, pretty: bool, indent: usize) {
115     if pretty && indent > 0 {
116         for _ in 0..indent {
117             buf.push_str("  ");
118         }
119     }
120 }
121 
print_start_field( buf: &mut String, pretty: bool, indent: usize, first: &mut bool, field_name: &str, )122 fn print_start_field(
123     buf: &mut String,
124     pretty: bool,
125     indent: usize,
126     first: &mut bool,
127     field_name: &str,
128 ) {
129     if !*first && !pretty {
130         buf.push_str(" ");
131     }
132     do_indent(buf, pretty, indent);
133     *first = false;
134     buf.push_str(field_name);
135 }
136 
print_end_field(buf: &mut String, pretty: bool)137 fn print_end_field(buf: &mut String, pretty: bool) {
138     if pretty {
139         buf.push_str("\n");
140     }
141 }
142 
print_field( buf: &mut String, pretty: bool, indent: usize, first: &mut bool, field_name: &str, value: ReflectValueRef, )143 fn print_field(
144     buf: &mut String,
145     pretty: bool,
146     indent: usize,
147     first: &mut bool,
148     field_name: &str,
149     value: ReflectValueRef,
150 ) {
151     print_start_field(buf, pretty, indent, first, field_name);
152 
153     match value {
154         ReflectValueRef::Message(m) => {
155             buf.push_str(" {");
156             if pretty {
157                 buf.push_str("\n");
158             }
159             print_to_internal(m, buf, pretty, indent + 1);
160             do_indent(buf, pretty, indent);
161             buf.push_str("}");
162         }
163         ReflectValueRef::Enum(e) => {
164             buf.push_str(": ");
165             buf.push_str(e.name());
166         }
167         ReflectValueRef::String(s) => {
168             buf.push_str(": ");
169             print_str_to(s, buf);
170         }
171         ReflectValueRef::Bytes(b) => {
172             buf.push_str(": ");
173             quote_escape_bytes_to(b, buf);
174         }
175         ReflectValueRef::I32(v) => {
176             write!(buf, ": {}", v).unwrap();
177         }
178         ReflectValueRef::I64(v) => {
179             write!(buf, ": {}", v).unwrap();
180         }
181         ReflectValueRef::U32(v) => {
182             write!(buf, ": {}", v).unwrap();
183         }
184         ReflectValueRef::U64(v) => {
185             write!(buf, ": {}", v).unwrap();
186         }
187         ReflectValueRef::Bool(v) => {
188             write!(buf, ": {}", v).unwrap();
189         }
190         ReflectValueRef::F32(v) => {
191             write!(buf, ": {}", v).unwrap();
192         }
193         ReflectValueRef::F64(v) => {
194             write!(buf, ": {}", v).unwrap();
195         }
196     }
197 
198     print_end_field(buf, pretty);
199 }
200 
print_to_internal(m: &dyn Message, buf: &mut String, pretty: bool, indent: usize)201 fn print_to_internal(m: &dyn Message, buf: &mut String, pretty: bool, indent: usize) {
202     let d = m.descriptor();
203     let mut first = true;
204     for f in d.fields() {
205         match f.get_reflect(m) {
206             ReflectFieldRef::Map(map) => {
207                 for (k, v) in map {
208                     print_start_field(buf, pretty, indent, &mut first, f.name());
209                     buf.push_str(" {");
210                     if pretty {
211                         buf.push_str("\n");
212                     }
213 
214                     let mut entry_first = true;
215 
216                     print_field(buf, pretty, indent + 1, &mut entry_first, "key", k.as_ref());
217                     print_field(
218                         buf,
219                         pretty,
220                         indent + 1,
221                         &mut entry_first,
222                         "value",
223                         v.as_ref(),
224                     );
225                     do_indent(buf, pretty, indent);
226                     buf.push_str("}");
227                     print_end_field(buf, pretty);
228                 }
229             }
230             ReflectFieldRef::Repeated(repeated) => {
231                 // TODO: do not print zeros for v3
232                 for v in repeated {
233                     print_field(buf, pretty, indent, &mut first, f.name(), v.as_ref());
234                 }
235             }
236             ReflectFieldRef::Optional(optional) => {
237                 if let Some(v) = optional {
238                     print_field(buf, pretty, indent, &mut first, f.name(), v);
239                 }
240             }
241         }
242     }
243 
244     // TODO: unknown fields
245 }
246 
247 /// Text-format
print_to(m: &dyn Message, buf: &mut String)248 pub fn print_to(m: &dyn Message, buf: &mut String) {
249     print_to_internal(m, buf, false, 0)
250 }
251 
print_to_string_internal(m: &dyn Message, pretty: bool) -> String252 fn print_to_string_internal(m: &dyn Message, pretty: bool) -> String {
253     let mut r = String::new();
254     print_to_internal(m, &mut r, pretty, 0);
255     r.to_string()
256 }
257 
258 /// Text-format
print_to_string(m: &dyn Message) -> String259 pub fn print_to_string(m: &dyn Message) -> String {
260     print_to_string_internal(m, false)
261 }
262 
263 /// Text-format to `fmt::Formatter`.
fmt(m: &dyn Message, f: &mut fmt::Formatter) -> fmt::Result264 pub fn fmt(m: &dyn Message, f: &mut fmt::Formatter) -> fmt::Result {
265     let pretty = f.alternate();
266     f.write_str(&print_to_string_internal(m, pretty))
267 }
268 
269 #[cfg(test)]
270 mod test {
271 
escape(data: &[u8]) -> String272     fn escape(data: &[u8]) -> String {
273         let mut s = String::with_capacity(data.len() * 4);
274         super::quote_bytes_to(data, &mut s);
275         s
276     }
277 
test_escape_unescape(text: &str, escaped: &str)278     fn test_escape_unescape(text: &str, escaped: &str) {
279         assert_eq!(text.as_bytes(), &super::unescape_string(escaped)[..]);
280         assert_eq!(escaped, &escape(text.as_bytes())[..]);
281     }
282 
283     #[test]
test_print_to_bytes()284     fn test_print_to_bytes() {
285         assert_eq!("ab", escape(b"ab"));
286         assert_eq!("a\\\\023", escape(b"a\\023"));
287         assert_eq!("a\\r\\n\\t \\'\\\"\\\\", escape(b"a\r\n\t '\"\\"));
288         assert_eq!("\\344\\275\\240\\345\\245\\275", escape("你好".as_bytes()));
289     }
290 
291     #[test]
292     fn test_unescape_string() {
293         test_escape_unescape("", "");
294         test_escape_unescape("aa", "aa");
295         test_escape_unescape("\n", "\\n");
296         test_escape_unescape("\r", "\\r");
297         test_escape_unescape("\t", "\\t");
298         test_escape_unescape("你好", "\\344\\275\\240\\345\\245\\275");
299         // hex
300         assert_eq!(b"aaa\x01bbb", &super::unescape_string("aaa\\x01bbb")[..]);
301         assert_eq!(b"aaa\xcdbbb", &super::unescape_string("aaa\\xCDbbb")[..]);
302         assert_eq!(b"aaa\xcdbbb", &super::unescape_string("aaa\\xCDbbb")[..]);
303         // quotes
304         assert_eq!(b"aaa\"bbb", &super::unescape_string("aaa\\\"bbb")[..]);
305         assert_eq!(b"aaa\'bbb", &super::unescape_string("aaa\\\'bbb")[..]);
306     }
307 }
308