protobuf_json/
lib.rs

1extern crate protobuf;
2extern crate serde_json;
3
4use protobuf::Message;
5use protobuf::descriptor::FieldDescriptorProto_Type;
6use protobuf::reflect::FieldDescriptor;
7
8#[cfg(test)]
9mod tests;
10
11pub fn proto_to_json(message: &Message) -> serde_json::Value {
12    let mut map = serde_json::Map::new();
13
14    for field in message.descriptor().fields() {
15        match field_to_json(message, field) {
16            Some(x) => {
17                map.insert(field.name().to_string(), x)
18            },
19            None => continue
20        };
21    }
22    serde_json::Value::Object(map)
23}
24
25fn field_to_json(m: &Message, fd: &FieldDescriptor) -> Option<serde_json::Value> {
26    if fd.is_repeated() {
27        match fd.len_field(m) {
28            0 => None,
29            _ => Some(repeated_field_to_json(m, fd)),
30        }
31    } else if fd.has_field(m) {
32        Some(singular_field_to_json(m, fd))
33    } else {
34        None
35    }
36}
37
38// Extracts a Vec<T> from a repeated proto field.
39// Most field types already have a function for extracting a Vec<T> directly,
40// however a few (e.g. Message) only have "len" and "get_item(i)" functions.
41// This function uses the len & get_item functions in order to create vector.
42#[allow(dead_code)]
43fn extract_vec_shim<'a, T>(
44    message: &'a Message,
45    get_size_fn: &Fn(&Message) -> usize,
46    extract_one_fn: &Fn(&'a Message, usize) -> &'a T) -> Vec<&'a T> {
47
48    let size = get_size_fn(message);
49    let mut v = Vec::new();
50    for i in 0..size {
51        v.push(extract_one_fn(message, i));
52    }
53    v
54}
55
56fn repeated_to_serde_array<T>(
57    message: &Message,
58    extract_fn: &Fn(&Message) -> Vec<T>,
59    convert_one_fn: &Fn(T) -> serde_json::Value) -> serde_json::Value {
60
61    serde_json::Value::Array(
62        extract_fn(message).into_iter().map(convert_one_fn).collect())
63}
64
65fn repeated_field_to_json(message: &Message,
66                          field_descriptor: &FieldDescriptor) -> serde_json::Value {
67
68    match field_descriptor.proto().get_field_type() {
69        FieldDescriptorProto_Type::TYPE_DOUBLE => {
70            repeated_to_serde_array(
71                message,
72                &|m| field_descriptor.get_rep_f64(m).to_vec(),
73                &|v| serde_json::Value::from(v))
74        },
75        FieldDescriptorProto_Type::TYPE_FLOAT => {
76            repeated_to_serde_array(
77                message,
78                &|m| field_descriptor.get_rep_f32(m).to_vec(),
79                &|v| serde_json::Value::from(v))
80        },
81        FieldDescriptorProto_Type::TYPE_INT32 |
82        FieldDescriptorProto_Type::TYPE_SINT32 |
83        FieldDescriptorProto_Type::TYPE_SFIXED32 => {
84            repeated_to_serde_array(
85                message,
86                &|m| field_descriptor.get_rep_i32(m).to_vec(),
87                &|v| serde_json::Value::from(v))
88        },
89        FieldDescriptorProto_Type::TYPE_INT64 |
90        FieldDescriptorProto_Type::TYPE_SINT64 |
91        FieldDescriptorProto_Type::TYPE_SFIXED64 => {
92            repeated_to_serde_array(
93                message,
94                &|m| field_descriptor.get_rep_i64(m).to_vec(),
95                &|v| serde_json::Value::from(v))
96        },
97        FieldDescriptorProto_Type::TYPE_UINT32 |
98        FieldDescriptorProto_Type::TYPE_FIXED32 => {
99            repeated_to_serde_array(
100                message,
101                &|m| field_descriptor.get_rep_u32(m).to_vec(),
102                &|v| serde_json::Value::from(v))
103        },
104        FieldDescriptorProto_Type::TYPE_UINT64 |
105        FieldDescriptorProto_Type::TYPE_FIXED64 => {
106            repeated_to_serde_array(
107                message,
108                &|m| field_descriptor.get_rep_u64(m).to_vec(),
109                &|v| serde_json::Value::from(v))
110        },
111        FieldDescriptorProto_Type::TYPE_BOOL => {
112            repeated_to_serde_array(
113                message,
114                &|m| field_descriptor.get_rep_bool(m).to_vec(),
115                &serde_json::Value::Bool)
116        },
117        FieldDescriptorProto_Type::TYPE_STRING => {
118            repeated_to_serde_array(
119                message,
120                &|m| field_descriptor.get_rep_str(m).to_vec(),
121                &serde_json::Value::String)
122        },
123        FieldDescriptorProto_Type::TYPE_BYTES => {
124            repeated_to_serde_array(
125                message,
126                &|m| field_descriptor.get_rep_bytes(m).to_vec(),
127                &|v| serde_json::Value::String(std::str::from_utf8(&v).unwrap().to_string()))
128        },
129        FieldDescriptorProto_Type::TYPE_MESSAGE => {
130            let mut sub_messages: Vec<&protobuf::Message> = Vec::new();
131            for i in 0..field_descriptor.len_field(message) {
132                sub_messages.push(
133                    field_descriptor.get_rep_message_item(message, i));
134            }
135
136            serde_json::Value::Array(sub_messages.into_iter().map(
137                |sub_message| proto_to_json(sub_message)).collect())
138
139            /* TODO: why doesn't this work?
140            return repeated_to_serde_array(
141                message,
142                &|m1: &protobuf::Message| extract_vec_shim(
143                    m1,
144                    &|m2| field_descriptor.len_field(m2),
145                    &|m2, i| field_descriptor.get_rep_message_item(m2, i),
146                ),
147                &|m: &protobuf::Message| proto_to_json(m));
148             */
149        },
150        FieldDescriptorProto_Type::TYPE_ENUM => {
151            let mut enums = Vec::new();
152            for i in 0..field_descriptor.len_field(message) {
153                enums.push(field_descriptor.get_rep_enum_item(message, i));
154            }
155            serde_json::Value::Array(enums.into_iter().map(
156                |e| serde_json::Value::String(e.name().to_string())).collect())
157        },
158        FieldDescriptorProto_Type::TYPE_GROUP => unimplemented!(),
159    }
160}
161
162fn singular_field_to_json(message: &protobuf::Message,
163                          field_descriptor: &protobuf::reflect::FieldDescriptor) -> serde_json::Value {
164    match field_descriptor.proto().get_field_type() {
165        FieldDescriptorProto_Type::TYPE_DOUBLE => {
166            serde_json::Value::from(field_descriptor.get_f64(message))
167        },
168        FieldDescriptorProto_Type::TYPE_FLOAT => {
169            serde_json::Value::from(f64::from(field_descriptor.get_f32(message)))
170        },
171        FieldDescriptorProto_Type::TYPE_INT32 |
172        FieldDescriptorProto_Type::TYPE_SINT32 |
173        FieldDescriptorProto_Type::TYPE_SFIXED32 => {
174            serde_json::Value::from(i64::from(field_descriptor.get_i32(message)))
175        },
176        FieldDescriptorProto_Type::TYPE_INT64 |
177        FieldDescriptorProto_Type::TYPE_SINT64 |
178        FieldDescriptorProto_Type::TYPE_SFIXED64 => {
179            serde_json::Value::from(field_descriptor.get_i64(message))
180        },
181        FieldDescriptorProto_Type::TYPE_UINT32 |
182        FieldDescriptorProto_Type::TYPE_FIXED32 => {
183            serde_json::Value::from(u64::from(field_descriptor.get_u32(message)))
184        },
185        FieldDescriptorProto_Type::TYPE_UINT64 |
186        FieldDescriptorProto_Type::TYPE_FIXED64 => {
187            serde_json::Value::from(field_descriptor.get_u64(message))
188        },
189        FieldDescriptorProto_Type::TYPE_BOOL => {
190            serde_json::Value::Bool(field_descriptor.get_bool(message))
191        },
192        FieldDescriptorProto_Type::TYPE_STRING => {
193            serde_json::Value::String(field_descriptor.get_str(message).to_string())
194        },
195        FieldDescriptorProto_Type::TYPE_BYTES => {
196            serde_json::Value::String(
197                std::str::from_utf8(
198                    field_descriptor.get_bytes(message)).unwrap().to_string())
199        },
200        FieldDescriptorProto_Type::TYPE_MESSAGE => {
201            let sub_message: &protobuf::Message =
202                field_descriptor.get_message(message);
203            proto_to_json(sub_message)
204        },
205        FieldDescriptorProto_Type::TYPE_ENUM => {
206            serde_json::Value::String(
207                field_descriptor.get_enum(message).name().to_string())
208
209        },
210        FieldDescriptorProto_Type::TYPE_GROUP => unimplemented!(),
211    }
212}