pw_varint: C support

This change exposes a subset of the pw::varint API for use in C code.

Change-Id: I7db2dd1d2622711785e23c8534de6119301c57c3
diff --git a/pw_varint/BUILD b/pw_varint/BUILD
index abfa158..78bc286 100644
--- a/pw_varint/BUILD
+++ b/pw_varint/BUILD
@@ -1,4 +1,4 @@
-# Copyright 2019 The Pigweed Authors
+# Copyright 2020 The Pigweed Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
 # use this file except in compliance with the License. You may obtain a copy of
@@ -38,6 +38,9 @@
 
 pw_cc_test(
     name = "varint_test",
-    srcs = ["varint_test.cc"],
+    srcs = [
+        "varint_test.c",
+        "varint_test.cc",
+    ],
     deps = ["//pw_varint"],
 )
diff --git a/pw_varint/BUILD.gn b/pw_varint/BUILD.gn
index 80af019..cb46782 100644
--- a/pw_varint/BUILD.gn
+++ b/pw_varint/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Pigweed Authors
+# Copyright 2020 The Pigweed Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
 # use this file except in compliance with the License. You may obtain a copy of
@@ -44,6 +44,7 @@
     ":pw_varint",
   ]
   sources = [
+    "varint_test.c",
     "varint_test.cc",
   ]
 }
diff --git a/pw_varint/public/pw_varint/varint.h b/pw_varint/public/pw_varint/varint.h
index eab1b59..d0dc830 100644
--- a/pw_varint/public/pw_varint/varint.h
+++ b/pw_varint/public/pw_varint/varint.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Pigweed Authors
+// Copyright 2020 The Pigweed Authors
 //
 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
 // use this file except in compliance with the License. You may obtain a copy of
@@ -13,8 +13,27 @@
 // the License.
 #pragma once
 
-#include <cstddef>
-#include <cstdint>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Expose a subset of the varint API for use in C code.
+
+size_t pw_VarintEncode(uint64_t integer, void* output, size_t output_size);
+size_t pw_VarintZigZagEncode(int64_t integer, void* output, size_t output_size);
+
+size_t pw_VarintDecode(const void* input, size_t input_size, uint64_t* output);
+size_t pw_VarintZigZagDecode(const void* input,
+                             size_t input_size,
+                             int64_t* output);
+
+#ifdef __cplusplus
+
+}  // extern "C"
+
 #include <type_traits>
 
 #include "pw_span/span.h"
@@ -51,8 +70,10 @@
 }
 
 // Encodes a uint64_t with Little-Endian Base 128 (LEB128) encoding.
-size_t EncodeLittleEndianBase128(uint64_t integer,
-                                 const span<std::byte>& output);
+inline size_t EncodeLittleEndianBase128(uint64_t integer,
+                                        const span<std::byte>& output) {
+  return pw_VarintEncode(integer, output.data(), output.size());
+}
 
 // Encodes the provided integer using a variable-length encoding and returns the
 // number of bytes written.
@@ -67,9 +88,9 @@
 template <typename T>
 size_t Encode(T integer, const span<std::byte>& output) {
   if constexpr (std::is_signed<T>()) {
-    return EncodeLittleEndianBase128(ZigZagEncode(integer), output);
+    return pw_VarintZigZagEncode(integer, output.data(), output.size());
   } else {
-    return EncodeLittleEndianBase128(integer, output);
+    return pw_VarintEncode(integer, output.data(), output.size());
   }
 }
 
@@ -93,7 +114,14 @@
 //     data = data.subspan(bytes)
 //   }
 //
-size_t Decode(const span<const std::byte>& input, int64_t* value);
-size_t Decode(const span<const std::byte>& input, uint64_t* value);
+inline size_t Decode(const span<const std::byte>& input, int64_t* value) {
+  return pw_VarintZigZagDecode(input.data(), input.size(), value);
+}
+
+inline size_t Decode(const span<const std::byte>& input, uint64_t* value) {
+  return pw_VarintDecode(input.data(), input.size(), value);
+}
 
 }  // namespace pw::varint
+
+#endif  // __cplusplus
diff --git a/pw_varint/varint.cc b/pw_varint/varint.cc
index e9c5199..006952c 100644
--- a/pw_varint/varint.cc
+++ b/pw_varint/varint.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Pigweed Authors
+// Copyright 2020 The Pigweed Authors
 //
 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
 // use this file except in compliance with the License. You may obtain a copy of
@@ -18,35 +18,41 @@
 
 namespace pw::varint {
 
-size_t EncodeLittleEndianBase128(uint64_t integer,
-                                 const span<std::byte>& output) {
+extern "C" size_t pw_VarintEncode(uint64_t integer,
+                                  void* output,
+                                  size_t output_size) {
   size_t written = 0;
+  std::byte* buffer = static_cast<std::byte*>(output);
+
   do {
-    if (written >= output.size()) {
+    if (written >= output_size) {
       return 0;
     }
 
     // Grab 7 bits; the eighth bit is set to 1 to indicate more data coming.
-    output[written++] = static_cast<std::byte>(integer) | std::byte{0x80};
+    buffer[written++] = static_cast<std::byte>(integer) | std::byte{0x80};
     integer >>= 7;
   } while (integer != 0u);
 
-  output[written - 1] &= std::byte{0x7f};  // clear the top bit of the last byte
+  buffer[written - 1] &= std::byte{0x7f};  // clear the top bit of the last byte
   return written;
 }
 
-size_t Decode(const span<const std::byte>& input, int64_t* value) {
-  const size_t bytes = Decode(input, reinterpret_cast<uint64_t*>(value));
-  *value = ZigZagDecode(static_cast<uint64_t>(*value));
-  return bytes;
+extern "C" size_t pw_VarintZigZagEncode(int64_t integer,
+                                        void* output,
+                                        size_t output_size) {
+  return pw_VarintEncode(ZigZagEncode(integer), output, output_size);
 }
 
-size_t Decode(const span<const std::byte>& input, uint64_t* value) {
+extern "C" size_t pw_VarintDecode(const void* input,
+                                  size_t input_size,
+                                  uint64_t* output) {
   uint64_t decoded_value = 0;
   uint_fast8_t count = 0;
+  const std::byte* buffer = static_cast<const std::byte*>(input);
 
   // The largest 64-bit ints require 10 B.
-  const size_t max_count = std::min(kMaxVarintSizeBytes, input.size());
+  const size_t max_count = std::min(kMaxVarintSizeBytes, input_size);
 
   while (true) {
     if (count >= max_count) {
@@ -54,17 +60,26 @@
     }
 
     // Add the bottom seven bits of the next byte to the result.
-    decoded_value |= static_cast<uint64_t>(input[count] & std::byte{0x7f})
+    decoded_value |= static_cast<uint64_t>(buffer[count] & std::byte{0x7f})
                      << (7 * count);
 
     // Stop decoding if the top bit is not set.
-    if ((input[count++] & std::byte{0x80}) == std::byte{0}) {
+    if ((buffer[count++] & std::byte{0x80}) == std::byte{0}) {
       break;
     }
   }
 
-  *value = decoded_value;
+  *output = decoded_value;
   return count;
 }
 
+extern "C" size_t pw_VarintZigZagDecode(const void* input,
+                                        size_t input_size,
+                                        int64_t* output) {
+  uint64_t value = 0;
+  size_t bytes = pw_VarintDecode(input, input_size, &value);
+  *output = ZigZagDecode(value);
+  return bytes;
+}
+
 }  // namespace pw::varint
diff --git a/pw_varint/varint_test.c b/pw_varint/varint_test.c
new file mode 100644
index 0000000..e0ee8db
--- /dev/null
+++ b/pw_varint/varint_test.c
@@ -0,0 +1,40 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// These tests call the pw_varint module API from C. The return values are
+// checked in the main C++ tests.
+
+#include "pw_varint/varint.h"
+
+#include <stddef.h>
+
+size_t pw_VarintCallEncode(uint64_t integer, void* output, size_t output_size) {
+  return pw_VarintEncode(integer, output, output_size);
+}
+
+size_t pw_VarintCallZigZagEncode(int64_t integer,
+                                 void* output,
+                                 size_t output_size) {
+  return pw_VarintZigZagEncode(integer, output, output_size);
+}
+
+size_t pw_VarintCallDecode(void* input, size_t input_size, uint64_t* output) {
+  return pw_VarintDecode(input, input_size, output);
+}
+
+size_t pw_VarintCallZigZagDecode(void* input,
+                                 size_t input_size,
+                                 int64_t* output) {
+  return pw_VarintZigZagDecode(input, input_size, output);
+}
diff --git a/pw_varint/varint_test.cc b/pw_varint/varint_test.cc
index c50df32..dc03f31 100644
--- a/pw_varint/varint_test.cc
+++ b/pw_varint/varint_test.cc
@@ -24,6 +24,20 @@
 namespace pw::varint {
 namespace {
 
+extern "C" {
+
+// Functions defined in varint_test.c which call the varint API from C.
+size_t pw_VarintCallEncode(uint64_t integer, void* output, size_t output_size);
+size_t pw_VarintCallZigZagEncode(int64_t integer,
+                                 void* output,
+                                 size_t output_size);
+size_t pw_VarintCallDecode(void* input, size_t input_size, uint64_t* output);
+size_t pw_VarintCallZigZagDecode(void* input,
+                                 size_t input_size,
+                                 int64_t* output);
+
+}  // extern "C"
+
 class Varint : public ::testing::Test {
  protected:
   Varint()
@@ -49,6 +63,15 @@
   EXPECT_EQ(std::byte{2}, buffer_[0]);
 }
 
+TEST_F(Varint, EncodeSizeUnsigned32_SmallSingleByte_C) {
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT32_C(0), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{0}, buffer_[0]);
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT32_C(1), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{1}, buffer_[0]);
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT32_C(2), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{2}, buffer_[0]);
+}
+
 TEST_F(Varint, EncodeSizeUnsigned32_LargeSingleByte) {
   ASSERT_EQ(1u, Encode(UINT32_C(63), buffer_));
   EXPECT_EQ(std::byte{63}, buffer_[0]);
@@ -60,6 +83,17 @@
   EXPECT_EQ(std::byte{127}, buffer_[0]);
 }
 
+TEST_F(Varint, EncodeSizeUnsigned32_LargeSingleByte_C) {
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT32_C(63), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{63}, buffer_[0]);
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT32_C(64), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{64}, buffer_[0]);
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT32_C(126), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{126}, buffer_[0]);
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT32_C(127), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{127}, buffer_[0]);
+}
+
 TEST_F(Varint, EncodeSizeUnsigned32_MultiByte) {
   ASSERT_EQ(2u, Encode(UINT32_C(128), buffer_));
   EXPECT_EQ(std::memcmp("\x80\x01", buffer_, 2), 0);
@@ -73,6 +107,25 @@
   EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\x0f", buffer_, 5), 0);
 }
 
+TEST_F(Varint, EncodeSizeUnsigned32_MultiByte_C) {
+  ASSERT_EQ(2u, pw_VarintCallEncode(UINT32_C(128), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\x80\x01", buffer_, 2), 0);
+  ASSERT_EQ(2u, pw_VarintCallEncode(UINT32_C(129), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\x81\x01", buffer_, 2), 0);
+
+  ASSERT_EQ(
+      5u,
+      pw_VarintCallEncode(
+          std::numeric_limits<uint32_t>::max() - 1, buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\x0f", buffer_, 5), 0);
+
+  ASSERT_EQ(
+      5u,
+      pw_VarintCallEncode(
+          std::numeric_limits<uint32_t>::max(), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\x0f", buffer_, 5), 0);
+}
+
 TEST_F(Varint, EncodeSizeSigned32_SmallSingleByte) {
   ASSERT_EQ(1u, Encode(INT32_C(0), buffer_));
   EXPECT_EQ(std::byte{0}, buffer_[0]);
@@ -86,6 +139,24 @@
   EXPECT_EQ(std::byte{4}, buffer_[0]);
 }
 
+TEST_F(Varint, EncodeSizeSigned32_SmallSingleByte_C) {
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT32_C(0), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{0}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT32_C(-1), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{1}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT32_C(1), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{2}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT32_C(-2), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{3}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT32_C(2), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{4}, buffer_[0]);
+}
+
 TEST_F(Varint, EncodeSizeSigned32_LargeSingleByte) {
   ASSERT_EQ(1u, Encode(INT32_C(-63), buffer_));
   EXPECT_EQ(std::byte{125}, buffer_[0]);
@@ -95,6 +166,18 @@
   EXPECT_EQ(std::byte{127}, buffer_[0]);
 }
 
+TEST_F(Varint, EncodeSizeSigned32_LargeSingleByte_C) {
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT32_C(-63), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{125}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT32_C(63), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{126}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT32_C(-64), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{127}, buffer_[0]);
+}
+
 TEST_F(Varint, EncodeSizeSigned32_MultiByte) {
   ASSERT_EQ(2u, Encode(INT32_C(64), buffer_));
   EXPECT_EQ(std::memcmp("\x80\x01", buffer_, 2), 0);
@@ -110,6 +193,28 @@
   EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\x0f", buffer_, 5), 0);
 }
 
+TEST_F(Varint, EncodeSizeSigned32_MultiByte_C) {
+  ASSERT_EQ(2u,
+            pw_VarintCallZigZagEncode(INT32_C(64), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\x80\x01", buffer_, 2), 0);
+  ASSERT_EQ(2u,
+            pw_VarintCallZigZagEncode(INT32_C(-65), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\x81\x01", buffer_, 2), 0);
+  ASSERT_EQ(2u,
+            pw_VarintCallZigZagEncode(INT32_C(65), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\x82\x01", buffer_, 2), 0);
+
+  ASSERT_EQ(5u,
+            pw_VarintCallZigZagEncode(
+                std::numeric_limits<int32_t>::min(), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\x0f", buffer_, 5), 0);
+
+  ASSERT_EQ(5u,
+            pw_VarintCallZigZagEncode(
+                std::numeric_limits<int32_t>::max(), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\x0f", buffer_, 5), 0);
+}
+
 TEST_F(Varint, EncodeSizeUnsigned64_SmallSingleByte) {
   ASSERT_EQ(1u, Encode(UINT64_C(0), buffer_));
   EXPECT_EQ(std::byte{0}, buffer_[0]);
@@ -119,6 +224,15 @@
   EXPECT_EQ(std::byte{2}, buffer_[0]);
 }
 
+TEST_F(Varint, EncodeSizeUnsigned64_SmallSingleByte_C) {
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT64_C(0), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{0}, buffer_[0]);
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT64_C(1), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{1}, buffer_[0]);
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT64_C(2), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{2}, buffer_[0]);
+}
+
 TEST_F(Varint, EncodeSizeUnsigned64_LargeSingleByte) {
   ASSERT_EQ(1u, Encode(UINT64_C(63), buffer_));
   EXPECT_EQ(std::byte{63}, buffer_[0]);
@@ -130,6 +244,17 @@
   EXPECT_EQ(std::byte{127}, buffer_[0]);
 }
 
+TEST_F(Varint, EncodeSizeUnsigned64_LargeSingleByte_C) {
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT64_C(63), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{63}, buffer_[0]);
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT64_C(64), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{64}, buffer_[0]);
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT64_C(126), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{126}, buffer_[0]);
+  ASSERT_EQ(1u, pw_VarintCallEncode(UINT64_C(127), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{127}, buffer_[0]);
+}
+
 TEST_F(Varint, EncodeSizeUnsigned64_MultiByte) {
   ASSERT_EQ(2u, Encode(UINT64_C(128), buffer_));
   EXPECT_EQ(std::memcmp("\x80\x01", buffer_, 2), 0);
@@ -151,6 +276,39 @@
       std::memcmp("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer_, 10), 0);
 }
 
+TEST_F(Varint, EncodeSizeUnsigned64_MultiByte_C) {
+  ASSERT_EQ(2u, pw_VarintCallEncode(UINT64_C(128), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\x80\x01", buffer_, 2), 0);
+  ASSERT_EQ(2u, pw_VarintCallEncode(UINT64_C(129), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\x81\x01", buffer_, 2), 0);
+
+  ASSERT_EQ(
+      5u,
+      pw_VarintCallEncode(
+          std::numeric_limits<uint32_t>::max() - 1, buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\x0f", buffer_, 5), 0);
+
+  ASSERT_EQ(
+      5u,
+      pw_VarintCallEncode(
+          std::numeric_limits<uint32_t>::max(), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\x0f", buffer_, 5), 0);
+
+  ASSERT_EQ(
+      10u,
+      pw_VarintCallEncode(
+          std::numeric_limits<uint64_t>::max() - 1, buffer_, sizeof(buffer_)));
+  EXPECT_EQ(
+      std::memcmp("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer_, 10), 0);
+
+  ASSERT_EQ(
+      10u,
+      pw_VarintCallEncode(
+          std::numeric_limits<uint64_t>::max(), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(
+      std::memcmp("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer_, 10), 0);
+}
+
 TEST_F(Varint, EncodeSizeSigned64_SmallSingleByte) {
   ASSERT_EQ(1u, Encode(INT64_C(0), buffer_));
   EXPECT_EQ(std::byte{0}, buffer_[0]);
@@ -164,6 +322,24 @@
   EXPECT_EQ(std::byte{4}, buffer_[0]);
 }
 
+TEST_F(Varint, EncodeSizeSigned64_SmallSingleByte_C) {
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT64_C(0), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{0}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT64_C(-1), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{1}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT64_C(1), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{2}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT64_C(-2), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{3}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT64_C(2), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{4}, buffer_[0]);
+}
+
 TEST_F(Varint, EncodeSizeSigned64_LargeSingleByte) {
   ASSERT_EQ(1u, Encode(INT64_C(-63), buffer_));
   EXPECT_EQ(std::byte{125}, buffer_[0]);
@@ -173,6 +349,18 @@
   EXPECT_EQ(std::byte{127}, buffer_[0]);
 }
 
+TEST_F(Varint, EncodeSizeSigned64_LargeSingleByte_C) {
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT64_C(-63), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{125}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT64_C(63), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{126}, buffer_[0]);
+  ASSERT_EQ(1u,
+            pw_VarintCallZigZagEncode(INT64_C(-64), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::byte{127}, buffer_[0]);
+}
+
 TEST_F(Varint, EncodeSizeSigned64_MultiByte) {
   ASSERT_EQ(2u, Encode(INT64_C(64), buffer_));
   EXPECT_EQ(std::memcmp("\x80\x01", buffer_, 2), 0);
@@ -200,6 +388,44 @@
       std::memcmp("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer_, 10), 0);
 }
 
+TEST_F(Varint, EncodeSizeSigned64_MultiByte_C) {
+  ASSERT_EQ(2u,
+            pw_VarintCallZigZagEncode(INT64_C(64), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\x80\x01", buffer_, 2), 0);
+  ASSERT_EQ(2u,
+            pw_VarintCallZigZagEncode(INT64_C(-65), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\x81\x01", buffer_, 2), 0);
+  ASSERT_EQ(2u,
+            pw_VarintCallZigZagEncode(INT64_C(65), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\x82\x01", buffer_, 2), 0);
+
+  ASSERT_EQ(5u,
+            pw_VarintCallZigZagEncode(
+                static_cast<int64_t>(std::numeric_limits<int32_t>::min()),
+                buffer_,
+                sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\xff\xff\xff\xff\x0f", buffer_, 5), 0);
+
+  ASSERT_EQ(5u,
+            pw_VarintCallZigZagEncode(
+                static_cast<int64_t>(std::numeric_limits<int32_t>::max()),
+                buffer_,
+                sizeof(buffer_)));
+  EXPECT_EQ(std::memcmp("\xfe\xff\xff\xff\x0f", buffer_, 5), 0);
+
+  ASSERT_EQ(10u,
+            pw_VarintCallZigZagEncode(
+                std::numeric_limits<int64_t>::min(), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(
+      std::memcmp("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer_, 10), 0);
+
+  ASSERT_EQ(10u,
+            pw_VarintCallZigZagEncode(
+                std::numeric_limits<int64_t>::max(), buffer_, sizeof(buffer_)));
+  EXPECT_EQ(
+      std::memcmp("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01", buffer_, 10), 0);
+}
+
 TEST_F(Varint, EncodeDecodeSigned32) {
   // Set the increment to 1 to test every number (this is slow)
   static constexpr int kIncrement = 1'000'009;
@@ -222,6 +448,29 @@
   }
 }
 
+TEST_F(Varint, EncodeDecodeSigned32_C) {
+  // Set the increment to 1 to test every number (this is slow)
+  static constexpr int kIncrement = 1'000'009;
+
+  int32_t i = std::numeric_limits<int32_t>::min();
+  while (true) {
+    size_t encoded = pw_VarintCallZigZagEncode(i, buffer_, sizeof(buffer_));
+
+    int64_t result;
+    size_t decoded =
+        pw_VarintCallZigZagDecode(buffer_, sizeof(buffer_), &result);
+
+    EXPECT_EQ(encoded, decoded);
+    ASSERT_EQ(i, result);
+
+    if (i > std::numeric_limits<int32_t>::max() - kIncrement) {
+      break;
+    }
+
+    i += kIncrement;
+  }
+}
+
 TEST_F(Varint, EncodeDecodeUnsigned32) {
   // Set the increment to 1 to test every number (this is slow)
   static constexpr int kIncrement = 1'000'009;
@@ -244,6 +493,28 @@
   }
 }
 
+TEST_F(Varint, EncodeDecodeUnsigned32_C) {
+  // Set the increment to 1 to test every number (this is slow)
+  static constexpr int kIncrement = 1'000'009;
+
+  uint32_t i = 0;
+  while (true) {
+    size_t encoded = pw_VarintCallEncode(i, buffer_, sizeof(buffer_));
+
+    uint64_t result;
+    size_t decoded = pw_VarintCallDecode(buffer_, sizeof(buffer_), &result);
+
+    EXPECT_EQ(encoded, decoded);
+    ASSERT_EQ(i, result);
+
+    if (i > std::numeric_limits<uint32_t>::max() - kIncrement) {
+      break;
+    }
+
+    i += kIncrement;
+  }
+}
+
 template <size_t kStringSize>
 auto MakeBuffer(const char (&data)[kStringSize]) {
   constexpr size_t kSizeBytes = kStringSize - 1;
@@ -276,6 +547,40 @@
   EXPECT_EQ(value, 2);
 }
 
+TEST(VarintDecode, DecodeSigned64_SingleByte_C) {
+  int64_t value = -1234;
+
+  auto buffer = MakeBuffer("\x00");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer.data(), buffer.size(), &value),
+            1u);
+  EXPECT_EQ(value, 0);
+
+  buffer = MakeBuffer("\x01");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer.data(), buffer.size(), &value),
+            1u);
+  EXPECT_EQ(value, -1);
+
+  buffer = MakeBuffer("\x02");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer.data(), buffer.size(), &value),
+            1u);
+  EXPECT_EQ(value, 1);
+
+  buffer = MakeBuffer("\x03");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer.data(), buffer.size(), &value),
+            1u);
+  EXPECT_EQ(value, -2);
+
+  buffer = MakeBuffer("\x04");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer.data(), buffer.size(), &value),
+            1u);
+  EXPECT_EQ(value, 2);
+
+  buffer = MakeBuffer("\x04");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer.data(), buffer.size(), &value),
+            1u);
+  EXPECT_EQ(value, 2);
+}
+
 TEST(VarintDecode, DecodeSigned64_MultiByte) {
   int64_t value = -1234;
 
@@ -305,6 +610,45 @@
   EXPECT_EQ(value, std::numeric_limits<int64_t>::max());
 }
 
+TEST(VarintDecode, DecodeSigned64_MultiByte_C) {
+  int64_t value = -1234;
+
+  auto buffer2 = MakeBuffer("\x80\x01");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer2.data(), buffer2.size(), &value),
+            2u);
+  EXPECT_EQ(value, 64);
+
+  buffer2 = MakeBuffer("\x81\x01");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer2.data(), buffer2.size(), &value),
+            2u);
+  EXPECT_EQ(value, -65);
+
+  buffer2 = MakeBuffer("\x82\x01");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer2.data(), buffer2.size(), &value),
+            2u);
+  EXPECT_EQ(value, 65);
+
+  auto buffer4 = MakeBuffer("\xff\xff\xff\xff\x0f");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer4.data(), buffer4.size(), &value),
+            5u);
+  EXPECT_EQ(value, std::numeric_limits<int32_t>::min());
+
+  buffer4 = MakeBuffer("\xfe\xff\xff\xff\x0f");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer4.data(), buffer4.size(), &value),
+            5u);
+  EXPECT_EQ(value, std::numeric_limits<int32_t>::max());
+
+  auto buffer8 = MakeBuffer("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer8.data(), buffer8.size(), &value),
+            10u);
+  EXPECT_EQ(value, std::numeric_limits<int64_t>::min());
+
+  buffer8 = MakeBuffer("\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01");
+  EXPECT_EQ(pw_VarintCallZigZagDecode(buffer8.data(), buffer8.size(), &value),
+            10u);
+  EXPECT_EQ(value, std::numeric_limits<int64_t>::max());
+}
+
 TEST(Varint, ZigZagEncode_Int8) {
   EXPECT_EQ(ZigZagEncode(int8_t(0)), uint8_t(0));
   EXPECT_EQ(ZigZagEncode(int8_t(-1)), uint8_t(1));