From 0c0f2e44b5bad1be335d68b35965ef05eb905e90 Mon Sep 17 00:00:00 2001
From: Julian Becker <becker.julian@gmail.com>
Date: Sat, 15 Sep 2018 03:23:54 +0200
Subject: [PATCH] BSON: support doubles

---
 .../nlohmann/detail/input/binary_reader.hpp   | 12 ++--
 .../nlohmann/detail/output/binary_writer.hpp  | 29 ++++++++-
 single_include/nlohmann/json.hpp              | 41 ++++++++++--
 test/src/unit-bson.cpp                        | 64 +++++++++++++------
 4 files changed, 115 insertions(+), 31 deletions(-)

diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp
index 54833cc3..dc9015b8 100644
--- a/include/nlohmann/detail/input/binary_reader.hpp
+++ b/include/nlohmann/detail/input/binary_reader.hpp
@@ -137,8 +137,6 @@ class binary_reader
     }
 
     /*!
-    @param[in] len  the length of the array or std::size_t(-1) for an
-                    array of indefinite size
     @return whether array creation completed
     */
     bool get_bson_str(string_t& result)
@@ -179,15 +177,19 @@ class binary_reader
                     string_t key;
                     get_bson_str(key);
                     sax->key(key);
-                    sax->boolean(static_cast<bool>(get()));
-                } break;
+                    double number;
+                    get_number_little_endian(number);
+                    sax->number_float(static_cast<number_float_t>(number), "");
+                }
+                break;
                 case 0x08:
                 {
                     string_t key;
                     get_bson_str(key);
                     sax->key(key);
                     sax->boolean(static_cast<bool>(get()));
-                } break;
+                }
+                break;
             }
         }
 
diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp
index 98e6104b..283c2cf2 100644
--- a/include/nlohmann/detail/output/binary_writer.hpp
+++ b/include/nlohmann/detail/output/binary_writer.hpp
@@ -676,8 +676,7 @@ class binary_writer
         }
     }
 
-
-    std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    std::size_t write_bson_boolean(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
     {
         oa->write_character(static_cast<CharType>(0x08)); // boolean
         oa->write_characters(
@@ -687,6 +686,32 @@ class binary_writer
         return /*id*/ 1ul + name.size() + 1u + /*boolean value*/ 1u;
     }
 
+    std::size_t write_bson_double(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    {
+        oa->write_character(static_cast<CharType>(0x01)); // boolean
+        oa->write_characters(
+            reinterpret_cast<const CharType*>(name.c_str()),
+            name.size() + 1u);
+        write_number_little_endian(j.m_value.number_float);
+        return /*id*/ 1ul + name.size() + 1u + /*double value*/ 8u;
+    }
+
+    std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    {
+        switch (j.type())
+        {
+            default:
+                JSON_THROW(type_error::create(317, "JSON value cannot be serialized to requested format"));
+                break;
+            case value_t::boolean:
+                return write_bson_boolean(name, j);
+            case value_t::number_float:
+                return write_bson_double(name, j);
+        };
+
+        return 0ul;
+    }
+
     /*!
     @param[in] j  JSON value to serialize
     @pre       j.type() == value_t::object
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 6b81d354..3da42389 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -6121,8 +6121,6 @@ class binary_reader
     }
 
     /*!
-    @param[in] len  the length of the array or std::size_t(-1) for an
-                    array of indefinite size
     @return whether array creation completed
     */
     bool get_bson_str(string_t& result)
@@ -6158,6 +6156,16 @@ class binary_reader
         {
             switch (entry_type)
             {
+                case 0x01:
+                {
+                    string_t key;
+                    get_bson_str(key);
+                    sax->key(key);
+                    double number;
+                    get_number_little_endian(number);
+                    sax->number_float(static_cast<number_float_t>(number), "");
+                }
+                break;
                 case 0x08:
                 {
                     string_t key;
@@ -8461,8 +8469,7 @@ class binary_writer
         }
     }
 
-
-    std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    std::size_t write_bson_boolean(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
     {
         oa->write_character(static_cast<CharType>(0x08)); // boolean
         oa->write_characters(
@@ -8472,6 +8479,32 @@ class binary_writer
         return /*id*/ 1ul + name.size() + 1u + /*boolean value*/ 1u;
     }
 
+    std::size_t write_bson_double(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    {
+        oa->write_character(static_cast<CharType>(0x01)); // boolean
+        oa->write_characters(
+            reinterpret_cast<const CharType*>(name.c_str()),
+            name.size() + 1u);
+        write_number_little_endian(j.m_value.number_float);
+        return /*id*/ 1ul + name.size() + 1u + /*double value*/ 8u;
+    }
+
+    std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j)
+    {
+        switch (j.type())
+        {
+            default:
+                JSON_THROW(type_error::create(317, "JSON value cannot be serialized to requested format"));
+                break;
+            case value_t::boolean:
+                return write_bson_boolean(name, j);
+            case value_t::number_float:
+                return write_bson_double(name, j);
+        };
+
+        return 0ul;
+    }
+
     /*!
     @param[in] j  JSON value to serialize
     @pre       j.type() == value_t::object
diff --git a/test/src/unit-bson.cpp b/test/src/unit-bson.cpp
index 9a710707..97746807 100644
--- a/test/src/unit-bson.cpp
+++ b/test/src/unit-bson.cpp
@@ -136,28 +136,52 @@ TEST_CASE("BSON")
             CHECK(json::from_bson(result, true, false) == j);
         }
 
-        // SECTION("non-empty object with double")
-        // {
-        //     json j =
-        //     {
-        //         { "entry", true }
-        //     };
+        SECTION("non-empty object with bool")
+        {
+            json j =
+            {
+                { "entry", false }
+            };
 
-        //     std::vector<uint8_t> expected =
-        //     {
-        //         0x14, 0x00, 0x00, 0x00, // size (little endian)
-        //         0x01, /// entry: double
-        //         'e', 'n', 't', 'r', 'y', '\x00',
-        //         0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
-        //         0x00 // end marker
-        //     };
+            std::vector<uint8_t> expected =
+            {
+                0x0D, 0x00, 0x00, 0x00, // size (little endian)
+                0x08,               // entry: boolean
+                'e', 'n', 't', 'r', 'y', '\x00',
+                0x00,           // value = false
+                0x00                    // end marker
+            };
 
-        //     const auto result = json::to_bson(j);
-        //     CHECK(result == expected);
+            const auto result = json::to_bson(j);
+            CHECK(result == expected);
 
-        //     // roundtrip
-        //     //CHECK(json::from_bson(result) == j);
-        //     //CHECK(json::from_bson(result, true, false) == j);
-        // }
+            // roundtrip
+            CHECK(json::from_bson(result) == j);
+            CHECK(json::from_bson(result, true, false) == j);
+        }
+
+        SECTION("non-empty object with double")
+        {
+            json j =
+            {
+                { "entry", 4.2 }
+            };
+
+            std::vector<uint8_t> expected =
+            {
+                0x14, 0x00, 0x00, 0x00, // size (little endian)
+                0x01, /// entry: double
+                'e', 'n', 't', 'r', 'y', '\x00',
+                0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
+                0x00 // end marker
+            };
+
+            const auto result = json::to_bson(j);
+            CHECK(result == expected);
+
+            // roundtrip
+            CHECK(json::from_bson(result) == j);
+            CHECK(json::from_bson(result, true, false) == j);
+        }
     }
 }