protobuf_support/lexer/
float.rs

1#[derive(Debug)]
2pub enum ProtobufFloatParseError {
3    EmptyString,
4    CannotParseFloat,
5}
6
7pub type ProtobufFloatParseResult<T> = Result<T, ProtobufFloatParseError>;
8
9pub const PROTOBUF_NAN: &str = "nan";
10pub const PROTOBUF_INF: &str = "inf";
11
12/// Format float as in protobuf `.proto` files
13pub 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
29pub 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)]
49mod test {
50    use super::*;
51
52    #[test]
53    fn test_format_protobuf_float() {
54        assert_eq!("10", format_protobuf_float(10.0));
55    }
56}