diff options
Diffstat (limited to '2.27.1/src/float.rs')
-rw-r--r-- | 2.27.1/src/float.rs | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/2.27.1/src/float.rs b/2.27.1/src/float.rs new file mode 100644 index 0000000..78ca622 --- /dev/null +++ b/2.27.1/src/float.rs @@ -0,0 +1,67 @@ +use std::f64; + +#[derive(Debug)] +pub enum ProtobufFloatParseError { + EmptyString, + CannotParseFloat, +} + +pub type ProtobufFloatParseResult<T> = Result<T, ProtobufFloatParseError>; + +pub const PROTOBUF_NAN: &str = "nan"; +pub const PROTOBUF_INF: &str = "inf"; + +/// Format float as in protobuf `.proto` files +pub fn format_protobuf_float(f: f64) -> String { + if f.is_nan() { + PROTOBUF_NAN.to_owned() + } else if f.is_infinite() { + if f > 0.0 { + format!("{}", PROTOBUF_INF) + } else { + format!("-{}", PROTOBUF_INF) + } + } else { + let i = f as i64; + if i as f64 == f { + // Older rust versions did print float without `.0` suffix + format!("{:?}.0", i) + } else { + // TODO: make sure doesn't lose precision + format!("{:?}", f) + } + } +} + +/// Parse float from `.proto` format +pub fn parse_protobuf_float(s: &str) -> ProtobufFloatParseResult<f64> { + if s.is_empty() { + return Err(ProtobufFloatParseError::EmptyString); + } + if s == PROTOBUF_NAN { + return Ok(f64::NAN); + } + if s == PROTOBUF_INF || s == format!("+{}", PROTOBUF_INF) { + return Ok(f64::INFINITY); + } + if s == format!("-{}", PROTOBUF_INF) { + return Ok(f64::NEG_INFINITY); + } + match s.parse() { + Ok(f) => Ok(f), + Err(_) => Err(ProtobufFloatParseError::CannotParseFloat), + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_format_protobuf_float() { + assert_eq!("10.0", format_protobuf_float(10.0)); + assert_eq!("-10.0", format_protobuf_float(-10.0)); + assert_eq!("10.5", format_protobuf_float(10.5)); + assert_eq!("-10.5", format_protobuf_float(-10.5)); + } +} |