pw_bytes: Added an ordered put method for values

Added functionality to insert values to the buffer in the endianness
order as specified by the user.

Change-Id: Ie33ac7a38a35cdd1cfdb2952233d13f09242cc8c
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/12472
Reviewed-by: Wyatt Hepler <hepler@google.com>
Commit-Queue: Shane Gomindes <shaneajg@google.com>
diff --git a/pw_bytes/byte_builder.cc b/pw_bytes/byte_builder.cc
index 80e74d2..bcfc9de 100644
--- a/pw_bytes/byte_builder.cc
+++ b/pw_bytes/byte_builder.cc
@@ -16,15 +16,8 @@
 
 namespace pw {
 
-void ByteBuilder::clear() {
-  size_ = 0;
-  status_ = Status::OK;
-  last_status_ = Status::OK;
-}
-
 ByteBuilder& ByteBuilder::append(size_t count, std::byte b) {
   std::byte* const append_destination = &buffer_[size_];
-
   std::memset(append_destination, static_cast<int>(b), ResizeForAppend(count));
   return *this;
 }
@@ -36,36 +29,27 @@
 }
 
 size_t ByteBuilder::ResizeForAppend(size_t bytes_to_append) {
-  const size_t copied = std::min(bytes_to_append, max_size() - size());
-  size_ += copied;
-
-  if (buffer_.empty() || bytes_to_append != copied) {
-    SetErrorStatus(Status::RESOURCE_EXHAUSTED);
-  } else {
-    last_status_ = Status::OK;
+  if (!status_.ok()) {
+    return 0;
   }
 
-  return copied;
+  if (bytes_to_append > max_size() - size()) {
+    status_ = Status::RESOURCE_EXHAUSTED;
+    return 0;
+  }
+
+  size_ += bytes_to_append;
+  status_ = Status::OK;
+  return bytes_to_append;
 }
 
 void ByteBuilder::resize(size_t new_size) {
   if (new_size <= size_) {
     size_ = new_size;
-    last_status_ = Status::OK;
+    status_ = Status::OK;
   } else {
-    SetErrorStatus(Status::OUT_OF_RANGE);
+    status_ = Status::OUT_OF_RANGE;
   }
 }
 
-void ByteBuilder::CopySizeAndStatus(const ByteBuilder& other) {
-  size_ = other.size_;
-  status_ = other.status_;
-  last_status_ = other.last_status_;
-}
-
-void ByteBuilder::SetErrorStatus(Status status) {
-  last_status_ = status;
-  status_ = status;
-}
-
 }  // namespace pw
diff --git a/pw_bytes/byte_builder_test.cc b/pw_bytes/byte_builder_test.cc
index f39c422..c649b20 100644
--- a/pw_bytes/byte_builder_test.cc
+++ b/pw_bytes/byte_builder_test.cc
@@ -99,14 +99,8 @@
   auto bytesTestLiteral = MakeBytes(0x04, 0x05, 0x06, 0x07);
 
   EXPECT_FALSE(bb.append(bytesTestLiteral.data(), 4).ok());
-  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.last_status());
-
-  EXPECT_EQ(byte{0x04}, bb.data()[0]);
-  EXPECT_EQ(byte{0x05}, bb.data()[1]);
-  EXPECT_EQ(byte{0x06}, bb.data()[2]);
-
-  EXPECT_EQ(bb.size(), bb.max_size());
-  EXPECT_EQ(3u, bb.size());
+  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.status());
+  EXPECT_EQ(0u, bb.size());
 }
 
 TEST(ByteBuilder, Append_RepeatedBytes) {
@@ -136,10 +130,7 @@
   ByteBuffer<8> bb;
 
   EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.append(9, byte{0x04}).status());
-
-  for (size_t i = 0; i < 8; i++) {
-    EXPECT_EQ(byte{0x04}, bb.data()[i]);
-  }
+  EXPECT_EQ(0u, bb.size());
 }
 
 TEST(ByteBuilder, Append_Partial) {
@@ -165,8 +156,7 @@
   ByteBuilder bb(buffer);
 
   bb.resize(1);
-
-  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.append(9, byte{0x04}).status());
+  EXPECT_EQ(Status::OUT_OF_RANGE, bb.append(9, byte{0x04}).status());
 }
 
 TEST(ByteBuilder, Resize_Smaller) {
@@ -208,43 +198,37 @@
 TEST(ByteBuilder, Status_StartsOk) {
   ByteBuffer<16> bb;
   EXPECT_EQ(Status::OK, bb.status());
-  EXPECT_EQ(Status::OK, bb.last_status());
 }
 
-TEST(ByteBuilder, Status_StatusAndLastStatusUpdate) {
+TEST(ByteBuilder, Status_StatusUpdate) {
   std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
   ByteBuffer<2> bb;
 
   EXPECT_FALSE(bb.append(buffer.data(), 3).ok());
   EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.status());
-  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.last_status());
 
   bb.resize(4);
   EXPECT_EQ(Status::OUT_OF_RANGE, bb.status());
-  EXPECT_EQ(Status::OUT_OF_RANGE, bb.last_status());
 
   EXPECT_FALSE(bb.append(buffer.data(), 0).ok());
   EXPECT_EQ(Status::OUT_OF_RANGE, bb.status());
-  EXPECT_EQ(Status::OK, bb.last_status());
 }
 
-TEST(ByteBuilder, Status_ClearStatus_SetsStatuesToOk) {
+TEST(ByteBuilder, Status_ClearStatus_SetsStatusToOk) {
   std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
   ByteBuffer<2> bb;
 
   EXPECT_FALSE(bb.append(buffer.data(), 3).ok());
   EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.status());
-  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.last_status());
 
   bb.clear_status();
   EXPECT_EQ(Status::OK, bb.status());
-  EXPECT_EQ(Status::OK, bb.last_status());
 }
 
 TEST(ByteBuilder, PushBack) {
   ByteBuffer<12> bb;
   bb.push_back(byte{0x01});
-  EXPECT_EQ(Status::OK, bb.last_status());
+  EXPECT_EQ(Status::OK, bb.status());
   EXPECT_EQ(1u, bb.size());
   EXPECT_EQ(byte{0x01}, bb.data()[0]);
 }
@@ -252,7 +236,7 @@
 TEST(ByteBuilder, PushBack_Full) {
   ByteBuffer<1> bb;
   bb.push_back(byte{0x01});
-  EXPECT_EQ(Status::OK, bb.last_status());
+  EXPECT_EQ(Status::OK, bb.status());
   EXPECT_EQ(1u, bb.size());
 }
 
@@ -261,7 +245,7 @@
   bb.push_back(byte{0x01});
   bb.push_back(byte{0x01});
 
-  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.last_status());
+  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.status());
   EXPECT_EQ(1u, bb.size());
 }
 
@@ -272,7 +256,7 @@
   bb.append(buffer.data(), 3);
 
   bb.pop_back();
-  EXPECT_EQ(Status::OK, bb.last_status());
+  EXPECT_EQ(Status::OK, bb.status());
   EXPECT_EQ(2u, bb.size());
   EXPECT_EQ(byte{0x01}, bb.data()[0]);
   EXPECT_EQ(byte{0x02}, bb.data()[1]);
@@ -286,7 +270,7 @@
   bb.pop_back();
   bb.pop_back();
   bb.pop_back();
-  EXPECT_EQ(Status::OK, bb.last_status());
+  EXPECT_EQ(Status::OK, bb.status());
   EXPECT_EQ(0u, bb.size());
   EXPECT_TRUE(bb.empty());
 }
@@ -323,14 +307,12 @@
   two.push_back(byte{0x01});
   two.push_back(byte{0x01});
   ASSERT_EQ(Status::RESOURCE_EXHAUSTED, two.status());
-  ASSERT_EQ(Status::RESOURCE_EXHAUSTED, two.last_status());
 
   one = two;
   EXPECT_EQ(byte{0x01}, two.data()[7]);
   EXPECT_EQ(byte{0x01}, two.data()[8]);
   EXPECT_EQ(byte{0x01}, two.data()[9]);
   EXPECT_EQ(Status::RESOURCE_EXHAUSTED, one.status());
-  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, one.last_status());
 }
 
 TEST(ByteBuffer, CopyConstructFromSameSize) {
@@ -356,9 +338,197 @@
 
   EXPECT_EQ(byte{0x01}, two.data()[0]);
   EXPECT_EQ(byte{0x02}, two.data()[1]);
-
   EXPECT_EQ(Status::OK, two.status());
 }
 
+TEST(ByteBuilder, ResizeError_NoDataAddedAfter) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+
+  EXPECT_TRUE(bb.append(buffer.data(), 3).ok());
+
+  EXPECT_EQ(3u, bb.size());
+  bb.resize(5);
+  EXPECT_EQ(3u, bb.size());
+  EXPECT_EQ(bb.status(), Status::OUT_OF_RANGE);
+
+  bb.PutInt8(0xFE);
+  EXPECT_EQ(3u, bb.size());
+  EXPECT_EQ(bb.status(), Status::OUT_OF_RANGE);
+}
+
+TEST(ByteBuilder, AddingNoBytesToZeroSizedByteBuffer) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<0> bb;
+
+  EXPECT_TRUE(bb.append(buffer.data(), 0).ok());
+  EXPECT_EQ(0u, bb.size());
+}
+
+TEST(ByteBuffer, Putting8ByteInts_Full) {
+  ByteBuffer<2> bb;
+  bb.PutInt8(0xFE);
+  bb.PutUint8(0x02);
+
+  EXPECT_EQ(byte{0xFE}, bb.data()[0]);
+  EXPECT_EQ(byte{0x02}, bb.data()[1]);
+  EXPECT_EQ(Status::OK, bb.status());
+}
+
+TEST(ByteBuffer, Putting8ByteInts_Exhausted) {
+  ByteBuffer<2> bb;
+  bb.PutInt8(0xFE);
+  bb.PutUint8(0x02);
+  bb.PutUint8(0x05);
+
+  EXPECT_EQ(byte{0xFE}, bb.data()[0]);
+  EXPECT_EQ(byte{0x02}, bb.data()[1]);
+  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.status());
+}
+
+TEST(ByteBuffer, Putting16ByteInts_Full_kLittleEndian) {
+  ByteBuffer<4> bb;
+  bb.PutInt16(0xFFF7);
+  bb.PutUint16(0x0008);
+
+  EXPECT_EQ(byte{0xF7}, bb.data()[0]);
+  EXPECT_EQ(byte{0xFF}, bb.data()[1]);
+  EXPECT_EQ(byte{0x08}, bb.data()[2]);
+  EXPECT_EQ(byte{0x00}, bb.data()[3]);
+
+  EXPECT_EQ(Status::OK, bb.status());
+}
+
+TEST(ByteBuffer, Putting16ByteInts_Exhausted_kBigEndian) {
+  ByteBuffer<5> bb;
+  bb.PutInt16(0xFFF7, ByteOrder::kBigEndian);
+  bb.PutUint16(0x0008, ByteOrder::kBigEndian);
+
+  EXPECT_EQ(byte{0xFF}, bb.data()[0]);
+  EXPECT_EQ(byte{0xF7}, bb.data()[1]);
+  EXPECT_EQ(byte{0x00}, bb.data()[2]);
+  EXPECT_EQ(byte{0x08}, bb.data()[3]);
+
+  bb.PutInt16(0xFAFA, ByteOrder::kBigEndian);
+  EXPECT_EQ(4u, bb.size());
+  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.status());
+}
+
+TEST(ByteBuffer, Putting32ByteInts_Full_kLittleEndian) {
+  ByteBuffer<8> bb;
+  bb.PutInt32(0xFFFFFFF1);
+  bb.PutUint32(0x00000014);
+
+  EXPECT_EQ(byte{0xF1}, bb.data()[0]);
+  EXPECT_EQ(byte{0xFF}, bb.data()[1]);
+  EXPECT_EQ(byte{0xFF}, bb.data()[2]);
+  EXPECT_EQ(byte{0xFF}, bb.data()[3]);
+  EXPECT_EQ(byte{0x14}, bb.data()[4]);
+  EXPECT_EQ(byte{0x00}, bb.data()[5]);
+  EXPECT_EQ(byte{0x00}, bb.data()[6]);
+  EXPECT_EQ(byte{0x00}, bb.data()[7]);
+
+  EXPECT_EQ(Status::OK, bb.status());
+}
+
+TEST(ByteBuffer, Putting32ByteInts_Exhausted_kBigEndian) {
+  ByteBuffer<10> bb;
+  bb.PutInt32(0xF92927B2, ByteOrder::kBigEndian);
+  bb.PutUint32(0x0C90739E, ByteOrder::kBigEndian);
+
+  EXPECT_EQ(byte{0xF9}, bb.data()[0]);
+  EXPECT_EQ(byte{0x29}, bb.data()[1]);
+  EXPECT_EQ(byte{0x27}, bb.data()[2]);
+  EXPECT_EQ(byte{0xB2}, bb.data()[3]);
+  EXPECT_EQ(byte{0x0C}, bb.data()[4]);
+  EXPECT_EQ(byte{0x90}, bb.data()[5]);
+  EXPECT_EQ(byte{0x73}, bb.data()[6]);
+  EXPECT_EQ(byte{0x9E}, bb.data()[7]);
+
+  bb.PutInt32(-114743374, ByteOrder::kBigEndian);
+  EXPECT_EQ(8u, bb.size());
+  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.status());
+}
+
+TEST(ByteBuffer, Putting64ByteInts_Full_kLittleEndian) {
+  ByteBuffer<16> bb;
+  bb.PutInt64(0x000001E8A7A0D569);
+  bb.PutUint64(0xFFFFFE17585F2A97);
+
+  EXPECT_EQ(byte{0x69}, bb.data()[0]);
+  EXPECT_EQ(byte{0xD5}, bb.data()[1]);
+  EXPECT_EQ(byte{0xA0}, bb.data()[2]);
+  EXPECT_EQ(byte{0xA7}, bb.data()[3]);
+  EXPECT_EQ(byte{0xE8}, bb.data()[4]);
+  EXPECT_EQ(byte{0x01}, bb.data()[5]);
+  EXPECT_EQ(byte{0x00}, bb.data()[6]);
+  EXPECT_EQ(byte{0x00}, bb.data()[7]);
+  EXPECT_EQ(byte{0x97}, bb.data()[8]);
+  EXPECT_EQ(byte{0x2A}, bb.data()[9]);
+  EXPECT_EQ(byte{0x5F}, bb.data()[10]);
+  EXPECT_EQ(byte{0x58}, bb.data()[11]);
+  EXPECT_EQ(byte{0x17}, bb.data()[12]);
+  EXPECT_EQ(byte{0xFE}, bb.data()[13]);
+  EXPECT_EQ(byte{0xFF}, bb.data()[14]);
+  EXPECT_EQ(byte{0xFF}, bb.data()[15]);
+
+  EXPECT_EQ(Status::OK, bb.status());
+}
+
+TEST(ByteBuffer, Putting64ByteInts_Exhausted_kBigEndian) {
+  ByteBuffer<20> bb;
+  bb.PutUint64(0x000001E8A7A0D569, ByteOrder::kBigEndian);
+  bb.PutInt64(0xFFFFFE17585F2A97, ByteOrder::kBigEndian);
+
+  EXPECT_EQ(byte{0x00}, bb.data()[0]);
+  EXPECT_EQ(byte{0x00}, bb.data()[1]);
+  EXPECT_EQ(byte{0x01}, bb.data()[2]);
+  EXPECT_EQ(byte{0xE8}, bb.data()[3]);
+  EXPECT_EQ(byte{0xA7}, bb.data()[4]);
+  EXPECT_EQ(byte{0xA0}, bb.data()[5]);
+  EXPECT_EQ(byte{0xD5}, bb.data()[6]);
+  EXPECT_EQ(byte{0x69}, bb.data()[7]);
+  EXPECT_EQ(byte{0xFF}, bb.data()[8]);
+  EXPECT_EQ(byte{0xFF}, bb.data()[9]);
+  EXPECT_EQ(byte{0xFE}, bb.data()[10]);
+  EXPECT_EQ(byte{0x17}, bb.data()[11]);
+  EXPECT_EQ(byte{0x58}, bb.data()[12]);
+  EXPECT_EQ(byte{0x5F}, bb.data()[13]);
+  EXPECT_EQ(byte{0x2A}, bb.data()[14]);
+  EXPECT_EQ(byte{0x97}, bb.data()[15]);
+
+  bb.PutInt64(-6099875637501324530, ByteOrder::kBigEndian);
+  EXPECT_EQ(16u, bb.size());
+  EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.status());
+}
+
+TEST(ByteBuffer, PuttingInts_MixedTypes_MixedEndian) {
+  ByteBuffer<16> bb;
+  bb.PutUint8(0x03);
+  bb.PutInt16(0xFD6D, ByteOrder::kBigEndian);
+  bb.PutUint32(0x482B3D9E);
+  bb.PutInt64(0x9A1C3641843DF317, ByteOrder::kBigEndian);
+  bb.PutInt8(0xFB);
+
+  EXPECT_EQ(byte{0x03}, bb.data()[0]);
+  EXPECT_EQ(byte{0xFD}, bb.data()[1]);
+  EXPECT_EQ(byte{0x6D}, bb.data()[2]);
+  EXPECT_EQ(byte{0x9E}, bb.data()[3]);
+  EXPECT_EQ(byte{0x3D}, bb.data()[4]);
+  EXPECT_EQ(byte{0x2B}, bb.data()[5]);
+  EXPECT_EQ(byte{0x48}, bb.data()[6]);
+  EXPECT_EQ(byte{0x9A}, bb.data()[7]);
+  EXPECT_EQ(byte{0x1C}, bb.data()[8]);
+  EXPECT_EQ(byte{0x36}, bb.data()[9]);
+  EXPECT_EQ(byte{0x41}, bb.data()[10]);
+  EXPECT_EQ(byte{0x84}, bb.data()[11]);
+  EXPECT_EQ(byte{0x3D}, bb.data()[12]);
+  EXPECT_EQ(byte{0xF3}, bb.data()[13]);
+  EXPECT_EQ(byte{0x17}, bb.data()[14]);
+  EXPECT_EQ(byte{0xFB}, bb.data()[15]);
+
+  EXPECT_EQ(Status::OK, bb.status());
+}
+
 }  // namespace
 }  // namespace pw
diff --git a/pw_bytes/docs.rst b/pw_bytes/docs.rst
index 83e9f1b..d67a8df 100644
--- a/pw_bytes/docs.rst
+++ b/pw_bytes/docs.rst
@@ -27,6 +27,13 @@
 ByteBuilder is a utility class which facilitates the creation and
 building of formatted bytes in a fixed-size buffer.
 
+Utilities for building byte arrays at run time
+------------------------------------------------
+-``PutInt8``, ``PutUInt8``: Inserts 8-bit integers.
+-``PutInt16``, ``PutInt16``: Inserts 16-bit integers in little/big endian.
+-``PutInt32``, ``PutUInt32``: Inserts 32-bit integers in little/big endian.
+-``PutInt64``, ``PutInt64``: Inserts 64-bit integers in little/big endian.
+
 Future work
 ^^^^^^^^^^^
-* Adding Endianness
+- Utilities for building byte arrays at compile time.
diff --git a/pw_bytes/public/pw_bytes/byte_builder.h b/pw_bytes/public/pw_bytes/byte_builder.h
index 923f3db..eade658 100644
--- a/pw_bytes/public/pw_bytes/byte_builder.h
+++ b/pw_bytes/public/pw_bytes/byte_builder.h
@@ -25,6 +25,14 @@
 
 namespace pw {
 
+// ByteOrder enum class enables users of ByteBuffer to specify the
+// desired Endianness for ordering the values to be inserted.
+enum class ByteOrder { kLittleEndian, kBigEndian };
+
+inline constexpr ByteOrder kSystemEndianness =
+    (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ? ByteOrder::kLittleEndian
+                                               : ByteOrder::kBigEndian);
+
 // ByteBuilder facilitates building bytes in a fixed-size buffer.
 // BytesBuilders never overflow. Status is tracked for each operation and
 // an overall status is maintained, which reflects the most recent error.
@@ -32,7 +40,6 @@
 // A ByteBuilder does not own the buffer it writes to. It can be used to write
 // bytes to any buffer. The ByteBuffer template class, defined below,
 // allocates a buffer alongside a ByteBuilder.
-
 class ByteBuilder {
  public:
   // Creates an empty ByteBuilder.
@@ -63,31 +70,28 @@
     return StatusWithSize(status_, size_);
   }
 
-  // The status from the last operation. May be OK while status() is not OK.
-  Status last_status() const { return last_status_; }
-
   // True if status() is Status::OK.
   bool ok() const { return status_.ok(); }
 
   // True if the bytes builder is empty.
   bool empty() const { return size() == 0u; }
 
-  // Returns the current length of the bytes, excluding the null terminator.
+  // Returns the current length of the bytes.
   size_t size() const { return size_; }
 
-  // Returns the maximum length of the bytes, excluding the null terminator.
+  // Returns the maximum length of the bytes.
   size_t max_size() const { return buffer_.size(); }
 
   // Clears the bytes and resets its error state.
-  void clear();
+  void clear() {
+    size_ = 0;
+    status_ = Status::OK;
+  };
 
   // Sets the statuses to Status::OK;
-  void clear_status() {
-    status_ = Status::OK;
-    last_status_ = Status::OK;
-  }
+  void clear_status() { status_ = Status::OK; }
 
-  // Appends a single byte. Stets the status to RESOURCE_EXHAUSTED if the
+  // Appends a single byte. Sets the status to RESOURCE_EXHAUSTED if the
   // byte cannot be added because the buffer is full.
   void push_back(std::byte b) { append(1, b); }
 
@@ -101,8 +105,8 @@
   ByteBuilder& append(size_t count, std::byte b);
 
   // Appends count bytes from 'bytes' to the end of the ByteBuilder. If count
-  // exceeds the remaining space in the ByteBuffer, max_size() - size()
-  // bytes are appended and the status is set to RESOURCE_EXHAUSTED.
+  // exceeds the remaining space in the ByteBuffer, no bytes will be appended
+  // and the status is set to RESOURCE_EXHAUSTED.
   ByteBuilder& append(const void* bytes, size_t count);
 
   // Appends bytes from a byte span that calls the pointer/length version.
@@ -114,26 +118,84 @@
   // new_size > size(), it sets status to OUT_OF_RANGE and does nothing.
   void resize(size_t new_size);
 
+  // Put methods for inserting different 8-bit ints
+  ByteBuilder& PutUint8(uint8_t val) { return WriteInOrder(val); }
+
+  ByteBuilder& PutInt8(int8_t val) { return WriteInOrder(val); }
+
+  // Put methods for inserting different 16-bit ints
+  ByteBuilder& PutUint16(uint16_t value,
+                         ByteOrder order = ByteOrder::kLittleEndian) {
+    if (kSystemEndianness != order) {
+      value = ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8);
+    }
+    return WriteInOrder(value);
+  }
+
+  ByteBuilder& PutInt16(int16_t value,
+                        ByteOrder order = ByteOrder::kLittleEndian) {
+    return PutUint16(static_cast<uint16_t>(value), order);
+  }
+
+  // Put methods for inserting different 32-bit ints
+  ByteBuilder& PutUint32(uint32_t value,
+                         ByteOrder order = ByteOrder::kLittleEndian) {
+    if (kSystemEndianness != order) {
+      value = ((value & 0x000000FF) << 3 * 8) |  //
+              ((value & 0x0000FF00) << 1 * 8) |  //
+              ((value & 0x00FF0000) >> 1 * 8) |  //
+              ((value & 0xFF000000) >> 3 * 8);
+    }
+    return WriteInOrder(value);
+  }
+
+  ByteBuilder& PutInt32(int32_t value,
+                        ByteOrder order = ByteOrder::kLittleEndian) {
+    return PutUint32(static_cast<uint32_t>(value), order);
+  }
+
+  // Put methods for inserting different 64-bit ints
+  ByteBuilder& PutUint64(uint64_t value,
+                         ByteOrder order = ByteOrder::kLittleEndian) {
+    if (kSystemEndianness != order) {
+      value = ((value & 0x00000000000000FF) << 7 * 8) |  //
+              ((value & 0x000000000000FF00) << 5 * 8) |  //
+              ((value & 0x0000000000FF0000) << 3 * 8) |  //
+              ((value & 0x00000000FF000000) << 1 * 8) |  //
+              ((value & 0x000000FF00000000) >> 1 * 8) |  //
+              ((value & 0x0000FF0000000000) >> 3 * 8) |  //
+              ((value & 0x00FF000000000000) >> 5 * 8) |  //
+              ((value & 0xFF00000000000000) >> 7 * 8);
+    }
+    return WriteInOrder(value);
+  }
+
+  ByteBuilder& PutInt64(int64_t value,
+                        ByteOrder order = ByteOrder::kLittleEndian) {
+    return PutUint64(static_cast<uint64_t>(value), order);
+  }
+
  protected:
   // Functions to support ByteBuffer copies.
   constexpr ByteBuilder(const span<std::byte>& buffer, const ByteBuilder& other)
-      : buffer_(buffer),
-        size_(other.size_),
-        status_(other.status_),
-        last_status_(other.last_status_) {}
+      : buffer_(buffer), size_(other.size_), status_(other.status_) {}
 
-  void CopySizeAndStatus(const ByteBuilder& other);
+  void CopySizeAndStatus(const ByteBuilder& other) {
+    size_ = other.size_;
+    status_ = other.status_;
+  };
 
  private:
+  template <typename T>
+  ByteBuilder& WriteInOrder(T value) {
+    return append(&value, sizeof(value));
+  }
   size_t ResizeForAppend(size_t bytes_to_append);
 
-  void SetErrorStatus(Status status);
-
   const span<std::byte> buffer_;
 
   size_t size_;
   Status status_;
-  Status last_status_;
 };
 
 // ByteBuffers declare a buffer along with a ByteBuilder.