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