From a9baab76c27704467df03bcf2a30ec463207b4b4 Mon Sep 17 00:00:00 2001
From: Niels Lohmann <mail@nlohmann.me>
Date: Wed, 28 Mar 2018 18:20:55 +0200
Subject: [PATCH 1/2] :ambulance: fix for #1021

---
 include/nlohmann/detail/exceptions.hpp        |  1 +
 .../nlohmann/detail/output/binary_writer.hpp  | 50 +++++++++++++++---
 single_include/nlohmann/json.hpp              | 51 ++++++++++++++++---
 test/src/unit-regression.cpp                  | 18 +++++++
 4 files changed, 108 insertions(+), 12 deletions(-)

diff --git a/include/nlohmann/detail/exceptions.hpp b/include/nlohmann/detail/exceptions.hpp
index b73d7b1f..53b38ec8 100644
--- a/include/nlohmann/detail/exceptions.hpp
+++ b/include/nlohmann/detail/exceptions.hpp
@@ -301,6 +301,7 @@ Exceptions have ids 5xx.
 name / id                      | example message | description
 ------------------------------ | --------------- | -------------------------
 json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.
+json.exception.other_error.502 | type for number_float_t is not supported | The template type for a number is not supported for the binary serialization in CBOR, MessagePack or UBJSON.
 
 @sa @ref exception for the base class of the library exceptions
 @sa @ref parse_error for exceptions indicating a parse error
diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp
index 1b15bdaf..13968fed 100644
--- a/include/nlohmann/detail/output/binary_writer.hpp
+++ b/include/nlohmann/detail/output/binary_writer.hpp
@@ -149,9 +149,19 @@ class binary_writer
                 break;
             }
 
-            case value_t::number_float: // Double-Precision Float
+            case value_t::number_float:
             {
-                oa->write_character(static_cast<CharType>(0xFB));
+                switch (sizeof(typename BasicJsonType::number_float_t))
+                {
+                    case 4:  // Single-Precision Float
+                        oa->write_character(static_cast<CharType>(0xFA));
+                        break;
+                    case 8:  // Double-Precision Float
+                        oa->write_character(static_cast<CharType>(0xFB));
+                        break;
+                    default:
+                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
+                }
                 write_number(j.m_value.number_float);
                 break;
             }
@@ -409,9 +419,19 @@ class binary_writer
                 break;
             }
 
-            case value_t::number_float: // float 64
+            case value_t::number_float:
             {
-                oa->write_character(static_cast<CharType>(0xCB));
+                switch (sizeof(typename BasicJsonType::number_float_t))
+                {
+                    case 4:  // float 32
+                        oa->write_character(static_cast<CharType>(0xCA));
+                        break;
+                    case 8:  // float 64
+                        oa->write_character(static_cast<CharType>(0xCB));
+                        break;
+                    default:
+                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
+                }
                 write_number(j.m_value.number_float);
                 break;
             }
@@ -712,7 +732,17 @@ class binary_writer
     {
         if (add_prefix)
         {
-            oa->write_character(static_cast<CharType>('D'));  // float64
+            switch (sizeof(typename BasicJsonType::number_float_t))
+            {
+                case 4:  // float 32
+                    oa->write_character(static_cast<CharType>('d'));
+                    break;
+                case 8:  // float 64
+                    oa->write_character(static_cast<CharType>('D'));
+                    break;
+                default:
+                    JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
+            }
         }
         write_number(n);
     }
@@ -892,7 +922,15 @@ class binary_writer
             }
 
             case value_t::number_float:
-                return 'D';
+                switch (sizeof(typename BasicJsonType::number_float_t))
+                {
+                    case 4:  // float 32
+                        return 'd';
+                    case 8:  // float 64
+                        return 'D';
+                    default:
+                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
+                }
 
             case value_t::string:
                 return 'S';
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 6b6655af..deeb9d5d 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -794,6 +794,7 @@ Exceptions have ids 5xx.
 name / id                      | example message | description
 ------------------------------ | --------------- | -------------------------
 json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.
+json.exception.other_error.502 | type for number_float_t is not supported | The template type for a number is not supported for the binary serialization in CBOR, MessagePack or UBJSON.
 
 @sa @ref exception for the base class of the library exceptions
 @sa @ref parse_error for exceptions indicating a parse error
@@ -6357,9 +6358,19 @@ class binary_writer
                 break;
             }
 
-            case value_t::number_float: // Double-Precision Float
+            case value_t::number_float:
             {
-                oa->write_character(static_cast<CharType>(0xFB));
+                switch (sizeof(typename BasicJsonType::number_float_t))
+                {
+                    case 4:  // Single-Precision Float
+                        oa->write_character(static_cast<CharType>(0xFA));
+                        break;
+                    case 8:  // Double-Precision Float
+                        oa->write_character(static_cast<CharType>(0xFB));
+                        break;
+                    default:
+                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
+                }
                 write_number(j.m_value.number_float);
                 break;
             }
@@ -6617,9 +6628,19 @@ class binary_writer
                 break;
             }
 
-            case value_t::number_float: // float 64
+            case value_t::number_float:
             {
-                oa->write_character(static_cast<CharType>(0xCB));
+                switch (sizeof(typename BasicJsonType::number_float_t))
+                {
+                    case 4:  // float 32
+                        oa->write_character(static_cast<CharType>(0xCA));
+                        break;
+                    case 8:  // float 64
+                        oa->write_character(static_cast<CharType>(0xCB));
+                        break;
+                    default:
+                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
+                }
                 write_number(j.m_value.number_float);
                 break;
             }
@@ -6920,7 +6941,17 @@ class binary_writer
     {
         if (add_prefix)
         {
-            oa->write_character(static_cast<CharType>('D'));  // float64
+            switch (sizeof(typename BasicJsonType::number_float_t))
+            {
+                case 4:  // float 32
+                    oa->write_character(static_cast<CharType>('d'));
+                    break;
+                case 8:  // float 64
+                    oa->write_character(static_cast<CharType>('D'));
+                    break;
+                default:
+                    JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
+            }
         }
         write_number(n);
     }
@@ -7100,7 +7131,15 @@ class binary_writer
             }
 
             case value_t::number_float:
-                return 'D';
+                switch (sizeof(typename BasicJsonType::number_float_t))
+                {
+                    case 4:  // float 32
+                        return 'd';
+                    case 8:  // float 64
+                        return 'D';
+                    default:
+                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
+                }
 
             case value_t::string:
                 return 'S';
diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp
index c4ca93d9..faa38a14 100644
--- a/test/src/unit-regression.cpp
+++ b/test/src/unit-regression.cpp
@@ -114,6 +114,13 @@ struct nocopy
 };
 }
 
+/////////////////////////////////////////////////////////////////////
+// for #1021
+/////////////////////////////////////////////////////////////////////
+
+using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int32_t, std::uint32_t, float>;
+
+
 TEST_CASE("regression tests")
 {
     SECTION("issue #60 - Double quotation mark is not parsed correctly")
@@ -1597,4 +1604,15 @@ TEST_CASE("regression tests")
         auto j = json::parse(geojsonExample, cb, true);
         CHECK(j == json());
     }
+
+    SECTION("issue #1021 - to/from_msgpack only works with standard typization")
+    {
+        float_json j = 1000.0;
+        CHECK(float_json::from_cbor(float_json::to_cbor(j)) == j);
+        CHECK(float_json::from_msgpack(float_json::to_msgpack(j)) == j);
+        CHECK(float_json::from_ubjson(float_json::to_ubjson(j)) == j);
+
+        float_json j2 = {1000.0, 2000.0, 3000.0};
+        CHECK(float_json::from_ubjson(float_json::to_ubjson(j2, true, true)) == j2);
+    }
 }

From 896a9db461adbad68d025ef07396905ad6e90fb5 Mon Sep 17 00:00:00 2001
From: Niels Lohmann <mail@nlohmann.me>
Date: Wed, 28 Mar 2018 19:37:21 +0200
Subject: [PATCH 2/2] :hammer: improved code #1021

---
 include/nlohmann/detail/exceptions.hpp        |  1 -
 .../nlohmann/detail/output/binary_writer.hpp  | 86 +++++++++---------
 single_include/nlohmann/json.hpp              | 87 +++++++++----------
 test/src/unit-regression.cpp                  |  2 +-
 4 files changed, 79 insertions(+), 97 deletions(-)

diff --git a/include/nlohmann/detail/exceptions.hpp b/include/nlohmann/detail/exceptions.hpp
index 53b38ec8..b73d7b1f 100644
--- a/include/nlohmann/detail/exceptions.hpp
+++ b/include/nlohmann/detail/exceptions.hpp
@@ -301,7 +301,6 @@ Exceptions have ids 5xx.
 name / id                      | example message | description
 ------------------------------ | --------------- | -------------------------
 json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.
-json.exception.other_error.502 | type for number_float_t is not supported | The template type for a number is not supported for the binary serialization in CBOR, MessagePack or UBJSON.
 
 @sa @ref exception for the base class of the library exceptions
 @sa @ref parse_error for exceptions indicating a parse error
diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp
index 13968fed..71e5ec81 100644
--- a/include/nlohmann/detail/output/binary_writer.hpp
+++ b/include/nlohmann/detail/output/binary_writer.hpp
@@ -151,17 +151,7 @@ class binary_writer
 
             case value_t::number_float:
             {
-                switch (sizeof(typename BasicJsonType::number_float_t))
-                {
-                    case 4:  // Single-Precision Float
-                        oa->write_character(static_cast<CharType>(0xFA));
-                        break;
-                    case 8:  // Double-Precision Float
-                        oa->write_character(static_cast<CharType>(0xFB));
-                        break;
-                    default:
-                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
-                }
+                oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
                 write_number(j.m_value.number_float);
                 break;
             }
@@ -421,17 +411,7 @@ class binary_writer
 
             case value_t::number_float:
             {
-                switch (sizeof(typename BasicJsonType::number_float_t))
-                {
-                    case 4:  // float 32
-                        oa->write_character(static_cast<CharType>(0xCA));
-                        break;
-                    case 8:  // float 64
-                        oa->write_character(static_cast<CharType>(0xCB));
-                        break;
-                    default:
-                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
-                }
+                oa->write_character(get_msgpack_float_prefix(j.m_value.number_float));
                 write_number(j.m_value.number_float);
                 break;
             }
@@ -608,7 +588,7 @@ class binary_writer
                 if (use_type and not j.m_value.array->empty())
                 {
                     assert(use_count);
-                    const char first_prefix = ubjson_prefix(j.front());
+                    const CharType first_prefix = ubjson_prefix(j.front());
                     const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
                                                          [this, first_prefix](const BasicJsonType & v)
                     {
@@ -619,7 +599,7 @@ class binary_writer
                     {
                         prefix_required = false;
                         oa->write_character(static_cast<CharType>('$'));
-                        oa->write_character(static_cast<CharType>(first_prefix));
+                        oa->write_character(first_prefix);
                     }
                 }
 
@@ -653,7 +633,7 @@ class binary_writer
                 if (use_type and not j.m_value.object->empty())
                 {
                     assert(use_count);
-                    const char first_prefix = ubjson_prefix(j.front());
+                    const CharType first_prefix = ubjson_prefix(j.front());
                     const bool same_prefix = std::all_of(j.begin(), j.end(),
                                                          [this, first_prefix](const BasicJsonType & v)
                     {
@@ -664,7 +644,7 @@ class binary_writer
                     {
                         prefix_required = false;
                         oa->write_character(static_cast<CharType>('$'));
-                        oa->write_character(static_cast<CharType>(first_prefix));
+                        oa->write_character(first_prefix);
                     }
                 }
 
@@ -732,17 +712,7 @@ class binary_writer
     {
         if (add_prefix)
         {
-            switch (sizeof(typename BasicJsonType::number_float_t))
-            {
-                case 4:  // float 32
-                    oa->write_character(static_cast<CharType>('d'));
-                    break;
-                case 8:  // float 64
-                    oa->write_character(static_cast<CharType>('D'));
-                    break;
-                default:
-                    JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
-            }
+            oa->write_character(get_ubjson_float_prefix(n));
         }
         write_number(n);
     }
@@ -863,7 +833,7 @@ class binary_writer
           write_number_with_ubjson_prefix. Therefore, we return 'L' for any
           value that does not fit the previous limits.
     */
-    char ubjson_prefix(const BasicJsonType& j) const noexcept
+    CharType ubjson_prefix(const BasicJsonType& j) const noexcept
     {
         switch (j.type())
         {
@@ -922,15 +892,7 @@ class binary_writer
             }
 
             case value_t::number_float:
-                switch (sizeof(typename BasicJsonType::number_float_t))
-                {
-                    case 4:  // float 32
-                        return 'd';
-                    case 8:  // float 64
-                        return 'D';
-                    default:
-                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
-                }
+                return get_ubjson_float_prefix(j.m_value.number_float);
 
             case value_t::string:
                 return 'S';
@@ -946,6 +908,36 @@ class binary_writer
         }
     }
 
+    static constexpr CharType get_cbor_float_prefix(float)
+    {
+        return static_cast<CharType>(0xFA);  // Single-Precision Float
+    }
+
+    static constexpr CharType get_cbor_float_prefix(double)
+    {
+        return static_cast<CharType>(0xFB);  // Double-Precision Float
+    }
+
+    static constexpr CharType get_msgpack_float_prefix(float)
+    {
+        return static_cast<CharType>(0xCA);  // float 32
+    }
+
+    static constexpr CharType get_msgpack_float_prefix(double)
+    {
+        return static_cast<CharType>(0xCB);  // float 64
+    }
+
+    static constexpr CharType get_ubjson_float_prefix(float)
+    {
+        return 'd';  // float 32
+    }
+
+    static constexpr CharType get_ubjson_float_prefix(double)
+    {
+        return 'D';  // float 64
+    }
+
   private:
     /// whether we can assume little endianess
     const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index deeb9d5d..b7558aa5 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -794,7 +794,6 @@ Exceptions have ids 5xx.
 name / id                      | example message | description
 ------------------------------ | --------------- | -------------------------
 json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.
-json.exception.other_error.502 | type for number_float_t is not supported | The template type for a number is not supported for the binary serialization in CBOR, MessagePack or UBJSON.
 
 @sa @ref exception for the base class of the library exceptions
 @sa @ref parse_error for exceptions indicating a parse error
@@ -6360,17 +6359,7 @@ class binary_writer
 
             case value_t::number_float:
             {
-                switch (sizeof(typename BasicJsonType::number_float_t))
-                {
-                    case 4:  // Single-Precision Float
-                        oa->write_character(static_cast<CharType>(0xFA));
-                        break;
-                    case 8:  // Double-Precision Float
-                        oa->write_character(static_cast<CharType>(0xFB));
-                        break;
-                    default:
-                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
-                }
+                oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
                 write_number(j.m_value.number_float);
                 break;
             }
@@ -6630,17 +6619,7 @@ class binary_writer
 
             case value_t::number_float:
             {
-                switch (sizeof(typename BasicJsonType::number_float_t))
-                {
-                    case 4:  // float 32
-                        oa->write_character(static_cast<CharType>(0xCA));
-                        break;
-                    case 8:  // float 64
-                        oa->write_character(static_cast<CharType>(0xCB));
-                        break;
-                    default:
-                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
-                }
+                oa->write_character(get_msgpack_float_prefix(j.m_value.number_float));
                 write_number(j.m_value.number_float);
                 break;
             }
@@ -6817,7 +6796,7 @@ class binary_writer
                 if (use_type and not j.m_value.array->empty())
                 {
                     assert(use_count);
-                    const char first_prefix = ubjson_prefix(j.front());
+                    const CharType first_prefix = ubjson_prefix(j.front());
                     const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
                                                          [this, first_prefix](const BasicJsonType & v)
                     {
@@ -6828,7 +6807,7 @@ class binary_writer
                     {
                         prefix_required = false;
                         oa->write_character(static_cast<CharType>('$'));
-                        oa->write_character(static_cast<CharType>(first_prefix));
+                        oa->write_character(first_prefix);
                     }
                 }
 
@@ -6862,7 +6841,7 @@ class binary_writer
                 if (use_type and not j.m_value.object->empty())
                 {
                     assert(use_count);
-                    const char first_prefix = ubjson_prefix(j.front());
+                    const CharType first_prefix = ubjson_prefix(j.front());
                     const bool same_prefix = std::all_of(j.begin(), j.end(),
                                                          [this, first_prefix](const BasicJsonType & v)
                     {
@@ -6873,7 +6852,7 @@ class binary_writer
                     {
                         prefix_required = false;
                         oa->write_character(static_cast<CharType>('$'));
-                        oa->write_character(static_cast<CharType>(first_prefix));
+                        oa->write_character(first_prefix);
                     }
                 }
 
@@ -6941,17 +6920,7 @@ class binary_writer
     {
         if (add_prefix)
         {
-            switch (sizeof(typename BasicJsonType::number_float_t))
-            {
-                case 4:  // float 32
-                    oa->write_character(static_cast<CharType>('d'));
-                    break;
-                case 8:  // float 64
-                    oa->write_character(static_cast<CharType>('D'));
-                    break;
-                default:
-                    JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
-            }
+            oa->write_character(get_ubjson_float_prefix(n));
         }
         write_number(n);
     }
@@ -7072,7 +7041,7 @@ class binary_writer
           write_number_with_ubjson_prefix. Therefore, we return 'L' for any
           value that does not fit the previous limits.
     */
-    char ubjson_prefix(const BasicJsonType& j) const noexcept
+    CharType ubjson_prefix(const BasicJsonType& j) const noexcept
     {
         switch (j.type())
         {
@@ -7131,15 +7100,7 @@ class binary_writer
             }
 
             case value_t::number_float:
-                switch (sizeof(typename BasicJsonType::number_float_t))
-                {
-                    case 4:  // float 32
-                        return 'd';
-                    case 8:  // float 64
-                        return 'D';
-                    default:
-                        JSON_THROW(other_error::create(502, "type for number_float_t is not supported"));
-                }
+                return get_ubjson_float_prefix(j.m_value.number_float);
 
             case value_t::string:
                 return 'S';
@@ -7155,6 +7116,36 @@ class binary_writer
         }
     }
 
+    static constexpr CharType get_cbor_float_prefix(float)
+    {
+        return static_cast<CharType>(0xFA);  // Single-Precision Float
+    }
+
+    static constexpr CharType get_cbor_float_prefix(double)
+    {
+        return static_cast<CharType>(0xFB);  // Double-Precision Float
+    }
+
+    static constexpr CharType get_msgpack_float_prefix(float)
+    {
+        return static_cast<CharType>(0xCA);  // float 32
+    }
+
+    static constexpr CharType get_msgpack_float_prefix(double)
+    {
+        return static_cast<CharType>(0xCB);  // float 64
+    }
+
+    static constexpr CharType get_ubjson_float_prefix(float)
+    {
+        return 'd';  // float 32
+    }
+
+    static constexpr CharType get_ubjson_float_prefix(double)
+    {
+        return 'D';  // float 64
+    }
+
   private:
     /// whether we can assume little endianess
     const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();
diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp
index faa38a14..01e68957 100644
--- a/test/src/unit-regression.cpp
+++ b/test/src/unit-regression.cpp
@@ -118,7 +118,7 @@ struct nocopy
 // for #1021
 /////////////////////////////////////////////////////////////////////
 
-using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int32_t, std::uint32_t, float>;
+using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>;
 
 
 TEST_CASE("regression tests")