:recycle: check for truncation

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp
index e0b5dcc..0090f5a 100644
--- a/include/nlohmann/detail/output/serializer.hpp
+++ b/include/nlohmann/detail/output/serializer.hpp
@@ -125,8 +125,7 @@
                     o->write_characters("{\n", 2);
 
                     // variable to hold indentation for recursive calls
-                    const auto new_indent = current_indent + indent_step;
-                    reserve_indent(new_indent);
+                    const auto new_indent = reserve_indent(current_indent, indent_step);
 
                     // first n-1 elements
                     auto i = val.m_data.m_value.object->cbegin();
@@ -195,8 +194,7 @@
                     o->write_characters("[\n", 2);
 
                     // variable to hold indentation for recursive calls
-                    const auto new_indent = current_indent + indent_step;
-                    reserve_indent(new_indent);
+                    const auto new_indent = reserve_indent(current_indent, indent_step);
 
                     // first n-1 elements
                     for (auto i = val.m_data.m_value.array->cbegin();
@@ -253,8 +251,7 @@
                     o->write_characters("{\n", 2);
 
                     // variable to hold indentation for recursive calls
-                    const auto new_indent = current_indent + indent_step;
-                    reserve_indent(new_indent);
+                    const auto new_indent = reserve_indent(current_indent, indent_step);
 
                     o->write_characters(indent_string.c_str(), new_indent);
 
@@ -365,22 +362,30 @@
     }
 
     /*!
-    @brief grow the indentation string so it can hold at least @a new_indent characters
+    @brief compute the next indentation level and grow the indentation string
 
-    The indentation string is grown by doubling its size, but at least to
-    @a new_indent characters, so that it can be used as a source for writing
-    @a new_indent indentation characters. The newly added characters use the
-    configured @ref indent_char.
+    Computes the new indentation level @a current_indent + @a indent_step and
+    grows the indentation string (by doubling its size, but at least to the new
+    level) so that it can be used as a source for writing that many indentation
+    characters. The newly added characters use the configured @ref indent_char.
 
-    @param[in] new_indent  the required number of indentation characters
+    @param[in] current_indent  the current indentation level
+    @param[in] indent_step     the number of characters to indent per level
+
+    @return the new indentation level @a current_indent + @a indent_step
     */
-    void reserve_indent(const std::size_t new_indent)
+    unsigned int reserve_indent(const unsigned int current_indent, const unsigned int indent_step)
     {
+        const unsigned int new_indent = current_indent + indent_step;
+        // a very large indent_step can wrap the unsigned accumulation on deep
+        // nesting, which would silently truncate the indentation
+        JSON_ASSERT(new_indent >= current_indent);
         if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
         {
-            indent_string.resize((std::max)(indent_string.size() * 2, new_indent), indent_char);
+            indent_string.resize((std::max)(indent_string.size() * 2, static_cast<std::size_t>(new_indent)), indent_char);
         }
         JSON_ASSERT(indent_string.size() >= new_indent);
+        return new_indent;
     }
 
   JSON_PRIVATE_UNLESS_TESTED:
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 7408238..a5fc13f 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -19299,8 +19299,7 @@
                     o->write_characters("{\n", 2);
 
                     // variable to hold indentation for recursive calls
-                    const auto new_indent = current_indent + indent_step;
-                    reserve_indent(new_indent);
+                    const auto new_indent = reserve_indent(current_indent, indent_step);
 
                     // first n-1 elements
                     auto i = val.m_data.m_value.object->cbegin();
@@ -19369,8 +19368,7 @@
                     o->write_characters("[\n", 2);
 
                     // variable to hold indentation for recursive calls
-                    const auto new_indent = current_indent + indent_step;
-                    reserve_indent(new_indent);
+                    const auto new_indent = reserve_indent(current_indent, indent_step);
 
                     // first n-1 elements
                     for (auto i = val.m_data.m_value.array->cbegin();
@@ -19427,8 +19425,7 @@
                     o->write_characters("{\n", 2);
 
                     // variable to hold indentation for recursive calls
-                    const auto new_indent = current_indent + indent_step;
-                    reserve_indent(new_indent);
+                    const auto new_indent = reserve_indent(current_indent, indent_step);
 
                     o->write_characters(indent_string.c_str(), new_indent);
 
@@ -19539,22 +19536,30 @@
     }
 
     /*!
-    @brief grow the indentation string so it can hold at least @a new_indent characters
+    @brief compute the next indentation level and grow the indentation string
 
-    The indentation string is grown by doubling its size, but at least to
-    @a new_indent characters, so that it can be used as a source for writing
-    @a new_indent indentation characters. The newly added characters use the
-    configured @ref indent_char.
+    Computes the new indentation level @a current_indent + @a indent_step and
+    grows the indentation string (by doubling its size, but at least to the new
+    level) so that it can be used as a source for writing that many indentation
+    characters. The newly added characters use the configured @ref indent_char.
 
-    @param[in] new_indent  the required number of indentation characters
+    @param[in] current_indent  the current indentation level
+    @param[in] indent_step     the number of characters to indent per level
+
+    @return the new indentation level @a current_indent + @a indent_step
     */
-    void reserve_indent(const std::size_t new_indent)
+    unsigned int reserve_indent(const unsigned int current_indent, const unsigned int indent_step)
     {
+        const unsigned int new_indent = current_indent + indent_step;
+        // a very large indent_step can wrap the unsigned accumulation on deep
+        // nesting, which would silently truncate the indentation
+        JSON_ASSERT(new_indent >= current_indent);
         if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
         {
-            indent_string.resize((std::max)(indent_string.size() * 2, new_indent), indent_char);
+            indent_string.resize((std::max)(indent_string.size() * 2, static_cast<std::size_t>(new_indent)), indent_char);
         }
         JSON_ASSERT(indent_string.size() >= new_indent);
+        return new_indent;
     }
 
   JSON_PRIVATE_UNLESS_TESTED: