1 use std::f64;
2
3 #[derive(Debug)]
4 pub enum ProtobufFloatParseError {
5 EmptyString,
6 CannotParseFloat,
7 }
8
9 pub type ProtobufFloatParseResult<T> = Result<T, ProtobufFloatParseError>;
10
11 pub const PROTOBUF_NAN: &str = "nan";
12 pub const PROTOBUF_INF: &str = "inf";
13
14 /// Format float as in protobuf `.proto` files
format_protobuf_float(f: f64) -> String15 pub fn format_protobuf_float(f: f64) -> String {
16 if f.is_nan() {
17 PROTOBUF_NAN.to_owned()
18 } else if f.is_infinite() {
19 if f > 0.0 {
20 format!("{}", PROTOBUF_INF)
21 } else {
22 format!("-{}", PROTOBUF_INF)
23 }
24 } else {
25 // TODO: make sure doesn't lose precision
26 format!("{}", f)
27 }
28 }
29
30 /// Parse float from `.proto` format
parse_protobuf_float(s: &str) -> ProtobufFloatParseResult<f64>31 pub fn parse_protobuf_float(s: &str) -> ProtobufFloatParseResult<f64> {
32 if s.is_empty() {
33 return Err(ProtobufFloatParseError::EmptyString);
34 }
35 if s == PROTOBUF_NAN {
36 return Ok(f64::NAN);
37 }
38 if s == PROTOBUF_INF || s == format!("+{}", PROTOBUF_INF) {
39 return Ok(f64::INFINITY);
40 }
41 if s == format!("-{}", PROTOBUF_INF) {
42 return Ok(f64::NEG_INFINITY);
43 }
44 match s.parse() {
45 Ok(f) => Ok(f),
46 Err(_) => Err(ProtobufFloatParseError::CannotParseFloat),
47 }
48 }
49
50 #[cfg(test)]
51 mod test {
52 use super::*;
53
54 #[test]
test_format_protobuf_float()55 fn test_format_protobuf_float() {
56 assert_eq!("10", format_protobuf_float(10.0));
57 }
58 }
59