aboutsummaryrefslogtreecommitdiff
path: root/2.27.1/src/float.rs
diff options
context:
space:
mode:
Diffstat (limited to '2.27.1/src/float.rs')
-rw-r--r--2.27.1/src/float.rs67
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));
+ }
+}