Let wuffs_base__utf_8__etc take ptr-to-const-u8
diff --git a/example/jsonptr/jsonptr.cc b/example/jsonptr/jsonptr.cc
index 099a379..c285b27 100644
--- a/example/jsonptr/jsonptr.cc
+++ b/example/jsonptr/jsonptr.cc
@@ -578,7 +578,7 @@
         wuffs_base__make_slice_u8((uint8_t*)query_c_string, length);
     bool previous_was_tilde = false;
     while (s.len > 0) {
-      wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next(s);
+      wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next(s.ptr, s.len);
       if (!o.is_valid()) {
         return false;
       }
@@ -1163,8 +1163,8 @@
         // Walk the end backwards to a UTF-8 boundary, so that each chunk of
         // the multi-chunk string is also valid UTF-8.
         while (available > 0) {
-          wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next_from_end(
-              wuffs_base__make_slice_u8(ptr, available));
+          wuffs_base__utf_8__next__output o =
+              wuffs_base__utf_8__next_from_end(ptr, available);
           if ((o.code_point != WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER) ||
               (o.byte_length != 1)) {
             break;
diff --git a/fuzz/c/std/json_fuzzer.c b/fuzz/c/std/json_fuzzer.c
index 916237c..6a92371 100644
--- a/fuzz/c/std/json_fuzzer.c
+++ b/fuzz/c/std/json_fuzzer.c
@@ -169,11 +169,11 @@
         wuffs_base__slice_u8 s =
             wuffs_base__make_slice_u8(src->data.ptr + *ti - len, len);
         if ((vbd & WUFFS_BASE__TOKEN__VBD__STRING__DEFINITELY_UTF_8) &&
-            (s.len != wuffs_base__utf_8__longest_valid_prefix(s))) {
+            (s.len != wuffs_base__utf_8__longest_valid_prefix(s.ptr, s.len))) {
           return "fuzz: internal error: invalid UTF-8";
         }
         if ((vbd & WUFFS_BASE__TOKEN__VBD__STRING__DEFINITELY_ASCII) &&
-            (s.len != wuffs_base__ascii__longest_valid_prefix(s))) {
+            (s.len != wuffs_base__ascii__longest_valid_prefix(s.ptr, s.len))) {
           return "fuzz: internal error: invalid ASCII";
         }
       }
diff --git a/internal/cgen/base/strconv-public.h b/internal/cgen/base/strconv-public.h
index 8cde012..6f117f5 100644
--- a/internal/cgen/base/strconv-public.h
+++ b/internal/cgen/base/strconv-public.h
@@ -563,7 +563,7 @@
 wuffs_base__utf_8__encode(wuffs_base__slice_u8 dst, uint32_t code_point);
 
 // wuffs_base__utf_8__next returns the next UTF-8 code point (and that code
-// point's byte length) at the start of s.
+// point's byte length) at the start of the read-only slice (s_ptr, s_len).
 //
 // There are exactly two cases in which this function returns something where
 // wuffs_base__utf_8__next__output__is_valid is false:
@@ -576,7 +576,7 @@
 //
 // In any case, it always returns an output that satisfies both of:
 //  - (output.code_point  <= WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL).
-//  - (output.byte_length <= s.len).
+//  - (output.byte_length <= s_len).
 //
 // If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice
 // boundary occurs in the middle of a multi-byte UTF-8 encoding of a single
@@ -587,41 +587,43 @@
 // function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just
 // WUFFS_CONFIG__MODULE__BASE__CORE.
 WUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //
-wuffs_base__utf_8__next(wuffs_base__slice_u8 s);
+wuffs_base__utf_8__next(const uint8_t* s_ptr, size_t s_len);
 
 // wuffs_base__utf_8__next_from_end is like wuffs_base__utf_8__next except that
-// it looks at the end of s instead of the start.
+// it looks at the end of (s_ptr, s_len) instead of the start.
 //
 // For modular builds that divide the base module into sub-modules, using this
 // function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just
 // WUFFS_CONFIG__MODULE__BASE__CORE.
 WUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //
-wuffs_base__utf_8__next_from_end(wuffs_base__slice_u8 s);
+wuffs_base__utf_8__next_from_end(const uint8_t* s_ptr, size_t s_len);
 
 // wuffs_base__utf_8__longest_valid_prefix returns the largest n such that the
-// sub-slice s[..n] is valid UTF-8.
+// sub-slice s[..n] is valid UTF-8, where s is the read-only slice (s_ptr,
+// s_len).
 //
-// In particular, it returns s.len if and only if all of s is valid UTF-8.
+// In particular, it returns s_len if and only if all of s is valid UTF-8.
 //
 // If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice
 // boundary occurs in the middle of a multi-byte UTF-8 encoding of a single
-// code point, then this function will return less than s.len. It is the
+// code point, then this function will return less than s_len. It is the
 // caller's responsibility to split on or otherwise manage UTF-8 boundaries.
 //
 // For modular builds that divide the base module into sub-modules, using this
 // function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just
 // WUFFS_CONFIG__MODULE__BASE__CORE.
 WUFFS_BASE__MAYBE_STATIC size_t  //
-wuffs_base__utf_8__longest_valid_prefix(wuffs_base__slice_u8 s);
+wuffs_base__utf_8__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len);
 
 // wuffs_base__ascii__longest_valid_prefix returns the largest n such that the
-// sub-slice s[..n] is valid ASCII.
+// sub-slice s[..n] is valid ASCII, where s is the read-only slice (s_ptr,
+// s_len).
 //
-// In particular, it returns s.len if and only if all of s is valid ASCII.
+// In particular, it returns s_len if and only if all of s is valid ASCII.
 // Equivalently, when none of the bytes in s have the 0x80 high bit set.
 //
 // For modular builds that divide the base module into sub-modules, using this
 // function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just
 // WUFFS_CONFIG__MODULE__BASE__CORE.
 WUFFS_BASE__MAYBE_STATIC size_t  //
-wuffs_base__ascii__longest_valid_prefix(wuffs_base__slice_u8 s);
+wuffs_base__ascii__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len);
diff --git a/internal/cgen/base/utf8-submodule.c b/internal/cgen/base/utf8-submodule.c
index 40a70cb..2106d09 100644
--- a/internal/cgen/base/utf8-submodule.c
+++ b/internal/cgen/base/utf8-submodule.c
@@ -112,20 +112,20 @@
 };
 
 WUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //
-wuffs_base__utf_8__next(wuffs_base__slice_u8 s) {
-  if (s.len == 0) {
+wuffs_base__utf_8__next(const uint8_t* s_ptr, size_t s_len) {
+  if (s_len == 0) {
     return wuffs_base__make_utf_8__next__output(0, 0);
   }
-  uint32_t c = s.ptr[0];
+  uint32_t c = s_ptr[0];
   switch (wuffs_base__utf_8__byte_length_minus_1[c & 0xFF]) {
     case 0:
       return wuffs_base__make_utf_8__next__output(c, 1);
 
     case 1:
-      if (s.len < 2) {
+      if (s_len < 2) {
         break;
       }
-      c = wuffs_base__load_u16le__no_bounds_check(s.ptr);
+      c = wuffs_base__load_u16le__no_bounds_check(s_ptr);
       if ((c & 0xC000) != 0x8000) {
         break;
       }
@@ -133,10 +133,10 @@
       return wuffs_base__make_utf_8__next__output(c, 2);
 
     case 2:
-      if (s.len < 3) {
+      if (s_len < 3) {
         break;
       }
-      c = wuffs_base__load_u24le__no_bounds_check(s.ptr);
+      c = wuffs_base__load_u24le__no_bounds_check(s_ptr);
       if ((c & 0xC0C000) != 0x808000) {
         break;
       }
@@ -148,10 +148,10 @@
       return wuffs_base__make_utf_8__next__output(c, 3);
 
     case 3:
-      if (s.len < 4) {
+      if (s_len < 4) {
         break;
       }
-      c = wuffs_base__load_u32le__no_bounds_check(s.ptr);
+      c = wuffs_base__load_u32le__no_bounds_check(s_ptr);
       if ((c & 0xC0C0C000) != 0x80808000) {
         break;
       }
@@ -168,16 +168,16 @@
 }
 
 WUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //
-wuffs_base__utf_8__next_from_end(wuffs_base__slice_u8 s) {
-  if (s.len == 0) {
+wuffs_base__utf_8__next_from_end(const uint8_t* s_ptr, size_t s_len) {
+  if (s_len == 0) {
     return wuffs_base__make_utf_8__next__output(0, 0);
   }
-  uint8_t* ptr = &s.ptr[s.len - 1];
+  const uint8_t* ptr = &s_ptr[s_len - 1];
   if (*ptr < 0x80) {
     return wuffs_base__make_utf_8__next__output(*ptr, 1);
 
   } else if (*ptr < 0xC0) {
-    uint8_t* too_far = &s.ptr[(s.len > 4) ? (s.len - 4) : 0];
+    const uint8_t* too_far = &s_ptr[(s_len > 4) ? (s_len - 4) : 0];
     uint32_t n = 1;
     while (ptr != too_far) {
       ptr--;
@@ -187,8 +187,7 @@
       } else if (*ptr < 0xC0) {
         continue;
       }
-      wuffs_base__utf_8__next__output o =
-          wuffs_base__utf_8__next(wuffs_base__make_slice_u8(ptr, n));
+      wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next(ptr, n);
       if (o.byte_length != n) {
         break;
       }
@@ -201,29 +200,29 @@
 }
 
 WUFFS_BASE__MAYBE_STATIC size_t  //
-wuffs_base__utf_8__longest_valid_prefix(wuffs_base__slice_u8 s) {
+wuffs_base__utf_8__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len) {
   // TODO: possibly optimize the all-ASCII case (4 or 8 bytes at a time).
   //
   // TODO: possibly optimize this by manually inlining the
   // wuffs_base__utf_8__next calls.
-  size_t original_len = s.len;
-  while (s.len > 0) {
-    wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next(s);
+  size_t original_len = s_len;
+  while (s_len > 0) {
+    wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next(s_ptr, s_len);
     if ((o.code_point > 0x7F) && (o.byte_length == 1)) {
       break;
     }
-    s.ptr += o.byte_length;
-    s.len -= o.byte_length;
+    s_ptr += o.byte_length;
+    s_len -= o.byte_length;
   }
-  return original_len - s.len;
+  return original_len - s_len;
 }
 
 WUFFS_BASE__MAYBE_STATIC size_t  //
-wuffs_base__ascii__longest_valid_prefix(wuffs_base__slice_u8 s) {
+wuffs_base__ascii__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len) {
   // TODO: possibly optimize this by checking 4 or 8 bytes at a time.
-  uint8_t* original_ptr = s.ptr;
-  uint8_t* p = s.ptr;
-  uint8_t* q = s.ptr + s.len;
+  const uint8_t* original_ptr = s_ptr;
+  const uint8_t* p = s_ptr;
+  const uint8_t* q = s_ptr + s_len;
   for (; (p != q) && ((*p & 0x80) == 0); p++) {
   }
   return (size_t)(p - original_ptr);
diff --git a/internal/cgen/data/data.go b/internal/cgen/data/data.go
index 29f8440..44573dd 100644
--- a/internal/cgen/data/data.go
+++ b/internal/cgen/data/data.go
@@ -280,10 +280,10 @@
 	" ((code_point >> 6) & 0x3F));\n      dst.ptr[3] = (uint8_t)(0x80 | ((code_point >> 0) & 0x3F));\n      return 4;\n    }\n  }\n\n  return 0;\n}\n\n// wuffs_base__utf_8__byte_length_minus_1 is the byte length (minus 1) of a\n// UTF-8 encoded code point, based on the encoding's initial byte.\n//  - 0x00 is 1-byte UTF-8 (ASCII).\n//  - 0x01 is the start of 2-byte UTF-8.\n//  - 0x02 is the start of 3-byte UTF-8.\n//  - 0x03 is the start of 4-byte UTF-8.\n//  - 0x40 is a UTF-8 tail byte.\n//  - 0x80 is invalid UTF-8.\n//\n// RFC 3629 (UTF-8) gives this grammar for valid UTF-8:\n//    UTF8-1      = %x00-7F\n//    UTF8-2      = %xC2-DF UTF8-tail\n//    UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /\n//                  %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )\n//    UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /\n//                  %xF4 %x80-8F 2( UTF8-tail )\n//    UTF8-tail   = %x80-BF\nstatic const uint8_t wuffs_base__utf_8__byte_length_minus_1[256] = {\n    // 0     1     2     3     4     5  " +
 	"   6     7\n    // 8     9     A     B     C     D     E     F\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x00 ..= 0x07.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x08 ..= 0x0F.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x10 ..= 0x17.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x18 ..= 0x1F.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x20 ..= 0x27.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x28 ..= 0x2F.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x30 ..= 0x37.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x38 ..= 0x3F.\n\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x40 ..= 0x47.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x48 ..= 0x4F.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x50 ..= 0x57.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x58 ..= 0x5F.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x60 ..= 0x67.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00" +
 	", 0x00, 0x00,  // 0x68 ..= 0x6F.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x70 ..= 0x77.\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // 0x78 ..= 0x7F.\n\n    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0x80 ..= 0x87.\n    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0x88 ..= 0x8F.\n    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0x90 ..= 0x97.\n    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0x98 ..= 0x9F.\n    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0xA0 ..= 0xA7.\n    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0xA8 ..= 0xAF.\n    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0xB0 ..= 0xB7.\n    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0xB8 ..= 0xBF.\n\n    0x80, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,  // 0xC0 ..= 0xC7.\n    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,  // 0xC8 ..= 0xCF.\n    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,  // 0xD0 ..= 0xD7.\n    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,  // 0xD8 ..= 0" +
-	"xDF.\n    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  // 0xE0 ..= 0xE7.\n    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  // 0xE8 ..= 0xEF.\n    0x03, 0x03, 0x03, 0x03, 0x03, 0x80, 0x80, 0x80,  // 0xF0 ..= 0xF7.\n    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,  // 0xF8 ..= 0xFF.\n    // 0     1     2     3     4     5     6     7\n    // 8     9     A     B     C     D     E     F\n};\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //\nwuffs_base__utf_8__next(wuffs_base__slice_u8 s) {\n  if (s.len == 0) {\n    return wuffs_base__make_utf_8__next__output(0, 0);\n  }\n  uint32_t c = s.ptr[0];\n  switch (wuffs_base__utf_8__byte_length_minus_1[c & 0xFF]) {\n    case 0:\n      return wuffs_base__make_utf_8__next__output(c, 1);\n\n    case 1:\n      if (s.len < 2) {\n        break;\n      }\n      c = wuffs_base__load_u16le__no_bounds_check(s.ptr);\n      if ((c & 0xC000) != 0x8000) {\n        break;\n      }\n      c = (0x0007C0 & (c << 6)) | (0x00003F & (c >> 8));\n      return wuffs_base__make_utf_8__next__output(" +
-	"c, 2);\n\n    case 2:\n      if (s.len < 3) {\n        break;\n      }\n      c = wuffs_base__load_u24le__no_bounds_check(s.ptr);\n      if ((c & 0xC0C000) != 0x808000) {\n        break;\n      }\n      c = (0x00F000 & (c << 12)) | (0x000FC0 & (c >> 2)) |\n          (0x00003F & (c >> 16));\n      if ((c <= 0x07FF) || ((0xD800 <= c) && (c <= 0xDFFF))) {\n        break;\n      }\n      return wuffs_base__make_utf_8__next__output(c, 3);\n\n    case 3:\n      if (s.len < 4) {\n        break;\n      }\n      c = wuffs_base__load_u32le__no_bounds_check(s.ptr);\n      if ((c & 0xC0C0C000) != 0x80808000) {\n        break;\n      }\n      c = (0x1C0000 & (c << 18)) | (0x03F000 & (c << 4)) |\n          (0x000FC0 & (c >> 10)) | (0x00003F & (c >> 24));\n      if ((c <= 0xFFFF) || (0x110000 <= c)) {\n        break;\n      }\n      return wuffs_base__make_utf_8__next__output(c, 4);\n  }\n\n  return wuffs_base__make_utf_8__next__output(\n      WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER, 1);\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //\nwuff" +
-	"s_base__utf_8__next_from_end(wuffs_base__slice_u8 s) {\n  if (s.len == 0) {\n    return wuffs_base__make_utf_8__next__output(0, 0);\n  }\n  uint8_t* ptr = &s.ptr[s.len - 1];\n  if (*ptr < 0x80) {\n    return wuffs_base__make_utf_8__next__output(*ptr, 1);\n\n  } else if (*ptr < 0xC0) {\n    uint8_t* too_far = &s.ptr[(s.len > 4) ? (s.len - 4) : 0];\n    uint32_t n = 1;\n    while (ptr != too_far) {\n      ptr--;\n      n++;\n      if (*ptr < 0x80) {\n        break;\n      } else if (*ptr < 0xC0) {\n        continue;\n      }\n      wuffs_base__utf_8__next__output o =\n          wuffs_base__utf_8__next(wuffs_base__make_slice_u8(ptr, n));\n      if (o.byte_length != n) {\n        break;\n      }\n      return o;\n    }\n  }\n\n  return wuffs_base__make_utf_8__next__output(\n      WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER, 1);\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t  //\nwuffs_base__utf_8__longest_valid_prefix(wuffs_base__slice_u8 s) {\n  // TODO: possibly optimize the all-ASCII case (4 or 8 bytes at a time).\n  //\n  // TODO: possibly optimize this b" +
-	"y manually inlining the\n  // wuffs_base__utf_8__next calls.\n  size_t original_len = s.len;\n  while (s.len > 0) {\n    wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next(s);\n    if ((o.code_point > 0x7F) && (o.byte_length == 1)) {\n      break;\n    }\n    s.ptr += o.byte_length;\n    s.len -= o.byte_length;\n  }\n  return original_len - s.len;\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t  //\nwuffs_base__ascii__longest_valid_prefix(wuffs_base__slice_u8 s) {\n  // TODO: possibly optimize this by checking 4 or 8 bytes at a time.\n  uint8_t* original_ptr = s.ptr;\n  uint8_t* p = s.ptr;\n  uint8_t* q = s.ptr + s.len;\n  for (; (p != q) && ((*p & 0x80) == 0); p++) {\n  }\n  return (size_t)(p - original_ptr);\n}\n" +
+	"xDF.\n    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  // 0xE0 ..= 0xE7.\n    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  // 0xE8 ..= 0xEF.\n    0x03, 0x03, 0x03, 0x03, 0x03, 0x80, 0x80, 0x80,  // 0xF0 ..= 0xF7.\n    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,  // 0xF8 ..= 0xFF.\n    // 0     1     2     3     4     5     6     7\n    // 8     9     A     B     C     D     E     F\n};\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //\nwuffs_base__utf_8__next(const uint8_t* s_ptr, size_t s_len) {\n  if (s_len == 0) {\n    return wuffs_base__make_utf_8__next__output(0, 0);\n  }\n  uint32_t c = s_ptr[0];\n  switch (wuffs_base__utf_8__byte_length_minus_1[c & 0xFF]) {\n    case 0:\n      return wuffs_base__make_utf_8__next__output(c, 1);\n\n    case 1:\n      if (s_len < 2) {\n        break;\n      }\n      c = wuffs_base__load_u16le__no_bounds_check(s_ptr);\n      if ((c & 0xC000) != 0x8000) {\n        break;\n      }\n      c = (0x0007C0 & (c << 6)) | (0x00003F & (c >> 8));\n      return wuffs_base__make_utf_8__n" +
+	"ext__output(c, 2);\n\n    case 2:\n      if (s_len < 3) {\n        break;\n      }\n      c = wuffs_base__load_u24le__no_bounds_check(s_ptr);\n      if ((c & 0xC0C000) != 0x808000) {\n        break;\n      }\n      c = (0x00F000 & (c << 12)) | (0x000FC0 & (c >> 2)) |\n          (0x00003F & (c >> 16));\n      if ((c <= 0x07FF) || ((0xD800 <= c) && (c <= 0xDFFF))) {\n        break;\n      }\n      return wuffs_base__make_utf_8__next__output(c, 3);\n\n    case 3:\n      if (s_len < 4) {\n        break;\n      }\n      c = wuffs_base__load_u32le__no_bounds_check(s_ptr);\n      if ((c & 0xC0C0C000) != 0x80808000) {\n        break;\n      }\n      c = (0x1C0000 & (c << 18)) | (0x03F000 & (c << 4)) |\n          (0x000FC0 & (c >> 10)) | (0x00003F & (c >> 24));\n      if ((c <= 0xFFFF) || (0x110000 <= c)) {\n        break;\n      }\n      return wuffs_base__make_utf_8__next__output(c, 4);\n  }\n\n  return wuffs_base__make_utf_8__next__output(\n      WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER, 1);\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__out" +
+	"put  //\nwuffs_base__utf_8__next_from_end(const uint8_t* s_ptr, size_t s_len) {\n  if (s_len == 0) {\n    return wuffs_base__make_utf_8__next__output(0, 0);\n  }\n  const uint8_t* ptr = &s_ptr[s_len - 1];\n  if (*ptr < 0x80) {\n    return wuffs_base__make_utf_8__next__output(*ptr, 1);\n\n  } else if (*ptr < 0xC0) {\n    const uint8_t* too_far = &s_ptr[(s_len > 4) ? (s_len - 4) : 0];\n    uint32_t n = 1;\n    while (ptr != too_far) {\n      ptr--;\n      n++;\n      if (*ptr < 0x80) {\n        break;\n      } else if (*ptr < 0xC0) {\n        continue;\n      }\n      wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next(ptr, n);\n      if (o.byte_length != n) {\n        break;\n      }\n      return o;\n    }\n  }\n\n  return wuffs_base__make_utf_8__next__output(\n      WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER, 1);\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t  //\nwuffs_base__utf_8__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len) {\n  // TODO: possibly optimize the all-ASCII case (4 or 8 bytes at a time).\n  //\n  // TODO: possibly opti" +
+	"mize this by manually inlining the\n  // wuffs_base__utf_8__next calls.\n  size_t original_len = s_len;\n  while (s_len > 0) {\n    wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next(s_ptr, s_len);\n    if ((o.code_point > 0x7F) && (o.byte_length == 1)) {\n      break;\n    }\n    s_ptr += o.byte_length;\n    s_len -= o.byte_length;\n  }\n  return original_len - s_len;\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t  //\nwuffs_base__ascii__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len) {\n  // TODO: possibly optimize this by checking 4 or 8 bytes at a time.\n  const uint8_t* original_ptr = s_ptr;\n  const uint8_t* p = s_ptr;\n  const uint8_t* q = s_ptr + s_len;\n  for (; (p != q) && ((*p & 0x80) == 0); p++) {\n  }\n  return (size_t)(p - original_ptr);\n}\n" +
 	""
 
 const BaseFundamentalPrivateH = "" +
@@ -552,10 +552,10 @@
 	"// --------\n\n// wuffs_base__utf_8__next__output is the type returned by\n// wuffs_base__utf_8__next.\ntypedef struct {\n  uint32_t code_point;\n  uint32_t byte_length;\n\n#ifdef __cplusplus\n  inline bool is_valid() const;\n#endif  // __cplusplus\n\n} wuffs_base__utf_8__next__output;\n\nstatic inline wuffs_base__utf_8__next__output  //\nwuffs_base__make_utf_8__next__output(uint32_t code_point,\n                                     uint32_t byte_length) {\n  wuffs_base__utf_8__next__output ret;\n  ret.code_point = code_point;\n  ret.byte_length = byte_length;\n  return ret;\n}\n\nstatic inline bool  //\nwuffs_base__utf_8__next__output__is_valid(\n    const wuffs_base__utf_8__next__output* o) {\n  if (o) {\n    uint32_t cp = o->code_point;\n    switch (o->byte_length) {\n      case 1:\n        return (cp <= 0x7F);\n      case 2:\n        return (0x080 <= cp) && (cp <= 0x7FF);\n      case 3:\n        // Avoid the 0xD800 ..= 0xDFFF surrogate range.\n        return ((0x0800 <= cp) && (cp <= 0xD7FF)) ||\n               ((0xE000 <= cp) && (cp <= 0xF" +
 	"FFF));\n      case 4:\n        return (0x00010000 <= cp) && (cp <= 0x0010FFFF);\n    }\n  }\n  return false;\n}\n\n#ifdef __cplusplus\n\ninline bool  //\nwuffs_base__utf_8__next__output::is_valid() const {\n  return wuffs_base__utf_8__next__output__is_valid(this);\n}\n\n#endif  // __cplusplus\n\n" +
 	"" +
-	"// --------\n\n// wuffs_base__utf_8__encode writes the UTF-8 encoding of code_point to s and\n// returns the number of bytes written. If code_point is invalid, or if s is\n// shorter than the entire encoding, it returns 0 (and no bytes are written).\n//\n// s will never be too short if its length is at least 4, also known as\n// WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just\n// WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC size_t  //\nwuffs_base__utf_8__encode(wuffs_base__slice_u8 dst, uint32_t code_point);\n\n// wuffs_base__utf_8__next returns the next UTF-8 code point (and that code\n// point's byte length) at the start of s.\n//\n// There are exactly two cases in which this function returns something where\n// wuffs_base__utf_8__next__output__is_valid is false:\n//  - If s is empty then it returns {.code_point=0, .byte_length=0}.\n//  - If s is non-empty a" +
-	"nd starts with invalid UTF-8 then it returns\n//    {.code_point=WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER, .byte_length=1}.\n//\n// Otherwise, it returns something where\n// wuffs_base__utf_8__next__output__is_valid is true.\n//\n// In any case, it always returns an output that satisfies both of:\n//  - (output.code_point  <= WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL).\n//  - (output.byte_length <= s.len).\n//\n// If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice\n// boundary occurs in the middle of a multi-byte UTF-8 encoding of a single\n// code point, then this function may return something invalid. It is the\n// caller's responsibility to split on or otherwise manage UTF-8 boundaries.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just\n// WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //\nwuffs_base__utf_8__next(wuffs_base__slice_u8 s);\n\n// wuff" +
-	"s_base__utf_8__next_from_end is like wuffs_base__utf_8__next except that\n// it looks at the end of s instead of the start.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just\n// WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //\nwuffs_base__utf_8__next_from_end(wuffs_base__slice_u8 s);\n\n// wuffs_base__utf_8__longest_valid_prefix returns the largest n such that the\n// sub-slice s[..n] is valid UTF-8.\n//\n// In particular, it returns s.len if and only if all of s is valid UTF-8.\n//\n// If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice\n// boundary occurs in the middle of a multi-byte UTF-8 encoding of a single\n// code point, then this function will return less than s.len. It is the\n// caller's responsibility to split on or otherwise manage UTF-8 boundaries.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// " +
-	"function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just\n// WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC size_t  //\nwuffs_base__utf_8__longest_valid_prefix(wuffs_base__slice_u8 s);\n\n// wuffs_base__ascii__longest_valid_prefix returns the largest n such that the\n// sub-slice s[..n] is valid ASCII.\n//\n// In particular, it returns s.len if and only if all of s is valid ASCII.\n// Equivalently, when none of the bytes in s have the 0x80 high bit set.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just\n// WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC size_t  //\nwuffs_base__ascii__longest_valid_prefix(wuffs_base__slice_u8 s);\n" +
+	"// --------\n\n// wuffs_base__utf_8__encode writes the UTF-8 encoding of code_point to s and\n// returns the number of bytes written. If code_point is invalid, or if s is\n// shorter than the entire encoding, it returns 0 (and no bytes are written).\n//\n// s will never be too short if its length is at least 4, also known as\n// WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just\n// WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC size_t  //\nwuffs_base__utf_8__encode(wuffs_base__slice_u8 dst, uint32_t code_point);\n\n// wuffs_base__utf_8__next returns the next UTF-8 code point (and that code\n// point's byte length) at the start of the read-only slice (s_ptr, s_len).\n//\n// There are exactly two cases in which this function returns something where\n// wuffs_base__utf_8__next__output__is_valid is false:\n//  - If s is empty then it returns {.code_point=0, .byte_len" +
+	"gth=0}.\n//  - If s is non-empty and starts with invalid UTF-8 then it returns\n//    {.code_point=WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER, .byte_length=1}.\n//\n// Otherwise, it returns something where\n// wuffs_base__utf_8__next__output__is_valid is true.\n//\n// In any case, it always returns an output that satisfies both of:\n//  - (output.code_point  <= WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL).\n//  - (output.byte_length <= s_len).\n//\n// If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice\n// boundary occurs in the middle of a multi-byte UTF-8 encoding of a single\n// code point, then this function may return something invalid. It is the\n// caller's responsibility to split on or otherwise manage UTF-8 boundaries.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just\n// WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //\nwuffs_base__utf_8__next(" +
+	"const uint8_t* s_ptr, size_t s_len);\n\n// wuffs_base__utf_8__next_from_end is like wuffs_base__utf_8__next except that\n// it looks at the end of (s_ptr, s_len) instead of the start.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just\n// WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //\nwuffs_base__utf_8__next_from_end(const uint8_t* s_ptr, size_t s_len);\n\n// wuffs_base__utf_8__longest_valid_prefix returns the largest n such that the\n// sub-slice s[..n] is valid UTF-8, where s is the read-only slice (s_ptr,\n// s_len).\n//\n// In particular, it returns s_len if and only if all of s is valid UTF-8.\n//\n// If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice\n// boundary occurs in the middle of a multi-byte UTF-8 encoding of a single\n// code point, then this function will return less than s_len. It is the\n// caller's responsibility to split on or " +
+	"otherwise manage UTF-8 boundaries.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just\n// WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC size_t  //\nwuffs_base__utf_8__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len);\n\n// wuffs_base__ascii__longest_valid_prefix returns the largest n such that the\n// sub-slice s[..n] is valid ASCII, where s is the read-only slice (s_ptr,\n// s_len).\n//\n// In particular, it returns s_len if and only if all of s is valid ASCII.\n// Equivalently, when none of the bytes in s have the 0x80 high bit set.\n//\n// For modular builds that divide the base module into sub-modules, using this\n// function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just\n// WUFFS_CONFIG__MODULE__BASE__CORE.\nWUFFS_BASE__MAYBE_STATIC size_t  //\nwuffs_base__ascii__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len);\n" +
 	""
 
 const BaseTokenPrivateH = "" +
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 4fd0018..714c72c 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -4504,7 +4504,7 @@
 wuffs_base__utf_8__encode(wuffs_base__slice_u8 dst, uint32_t code_point);
 
 // wuffs_base__utf_8__next returns the next UTF-8 code point (and that code
-// point's byte length) at the start of s.
+// point's byte length) at the start of the read-only slice (s_ptr, s_len).
 //
 // There are exactly two cases in which this function returns something where
 // wuffs_base__utf_8__next__output__is_valid is false:
@@ -4517,7 +4517,7 @@
 //
 // In any case, it always returns an output that satisfies both of:
 //  - (output.code_point  <= WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL).
-//  - (output.byte_length <= s.len).
+//  - (output.byte_length <= s_len).
 //
 // If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice
 // boundary occurs in the middle of a multi-byte UTF-8 encoding of a single
@@ -4528,44 +4528,46 @@
 // function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just
 // WUFFS_CONFIG__MODULE__BASE__CORE.
 WUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //
-wuffs_base__utf_8__next(wuffs_base__slice_u8 s);
+wuffs_base__utf_8__next(const uint8_t* s_ptr, size_t s_len);
 
 // wuffs_base__utf_8__next_from_end is like wuffs_base__utf_8__next except that
-// it looks at the end of s instead of the start.
+// it looks at the end of (s_ptr, s_len) instead of the start.
 //
 // For modular builds that divide the base module into sub-modules, using this
 // function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just
 // WUFFS_CONFIG__MODULE__BASE__CORE.
 WUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //
-wuffs_base__utf_8__next_from_end(wuffs_base__slice_u8 s);
+wuffs_base__utf_8__next_from_end(const uint8_t* s_ptr, size_t s_len);
 
 // wuffs_base__utf_8__longest_valid_prefix returns the largest n such that the
-// sub-slice s[..n] is valid UTF-8.
+// sub-slice s[..n] is valid UTF-8, where s is the read-only slice (s_ptr,
+// s_len).
 //
-// In particular, it returns s.len if and only if all of s is valid UTF-8.
+// In particular, it returns s_len if and only if all of s is valid UTF-8.
 //
 // If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice
 // boundary occurs in the middle of a multi-byte UTF-8 encoding of a single
-// code point, then this function will return less than s.len. It is the
+// code point, then this function will return less than s_len. It is the
 // caller's responsibility to split on or otherwise manage UTF-8 boundaries.
 //
 // For modular builds that divide the base module into sub-modules, using this
 // function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just
 // WUFFS_CONFIG__MODULE__BASE__CORE.
 WUFFS_BASE__MAYBE_STATIC size_t  //
-wuffs_base__utf_8__longest_valid_prefix(wuffs_base__slice_u8 s);
+wuffs_base__utf_8__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len);
 
 // wuffs_base__ascii__longest_valid_prefix returns the largest n such that the
-// sub-slice s[..n] is valid ASCII.
+// sub-slice s[..n] is valid ASCII, where s is the read-only slice (s_ptr,
+// s_len).
 //
-// In particular, it returns s.len if and only if all of s is valid ASCII.
+// In particular, it returns s_len if and only if all of s is valid ASCII.
 // Equivalently, when none of the bytes in s have the 0x80 high bit set.
 //
 // For modular builds that divide the base module into sub-modules, using this
 // function requires the WUFFS_CONFIG__MODULE__BASE__UTF8 sub-module, not just
 // WUFFS_CONFIG__MODULE__BASE__CORE.
 WUFFS_BASE__MAYBE_STATIC size_t  //
-wuffs_base__ascii__longest_valid_prefix(wuffs_base__slice_u8 s);
+wuffs_base__ascii__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len);
 
 // ---------------- Interface Declarations.
 
@@ -14638,20 +14640,20 @@
 };
 
 WUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //
-wuffs_base__utf_8__next(wuffs_base__slice_u8 s) {
-  if (s.len == 0) {
+wuffs_base__utf_8__next(const uint8_t* s_ptr, size_t s_len) {
+  if (s_len == 0) {
     return wuffs_base__make_utf_8__next__output(0, 0);
   }
-  uint32_t c = s.ptr[0];
+  uint32_t c = s_ptr[0];
   switch (wuffs_base__utf_8__byte_length_minus_1[c & 0xFF]) {
     case 0:
       return wuffs_base__make_utf_8__next__output(c, 1);
 
     case 1:
-      if (s.len < 2) {
+      if (s_len < 2) {
         break;
       }
-      c = wuffs_base__load_u16le__no_bounds_check(s.ptr);
+      c = wuffs_base__load_u16le__no_bounds_check(s_ptr);
       if ((c & 0xC000) != 0x8000) {
         break;
       }
@@ -14659,10 +14661,10 @@
       return wuffs_base__make_utf_8__next__output(c, 2);
 
     case 2:
-      if (s.len < 3) {
+      if (s_len < 3) {
         break;
       }
-      c = wuffs_base__load_u24le__no_bounds_check(s.ptr);
+      c = wuffs_base__load_u24le__no_bounds_check(s_ptr);
       if ((c & 0xC0C000) != 0x808000) {
         break;
       }
@@ -14674,10 +14676,10 @@
       return wuffs_base__make_utf_8__next__output(c, 3);
 
     case 3:
-      if (s.len < 4) {
+      if (s_len < 4) {
         break;
       }
-      c = wuffs_base__load_u32le__no_bounds_check(s.ptr);
+      c = wuffs_base__load_u32le__no_bounds_check(s_ptr);
       if ((c & 0xC0C0C000) != 0x80808000) {
         break;
       }
@@ -14694,16 +14696,16 @@
 }
 
 WUFFS_BASE__MAYBE_STATIC wuffs_base__utf_8__next__output  //
-wuffs_base__utf_8__next_from_end(wuffs_base__slice_u8 s) {
-  if (s.len == 0) {
+wuffs_base__utf_8__next_from_end(const uint8_t* s_ptr, size_t s_len) {
+  if (s_len == 0) {
     return wuffs_base__make_utf_8__next__output(0, 0);
   }
-  uint8_t* ptr = &s.ptr[s.len - 1];
+  const uint8_t* ptr = &s_ptr[s_len - 1];
   if (*ptr < 0x80) {
     return wuffs_base__make_utf_8__next__output(*ptr, 1);
 
   } else if (*ptr < 0xC0) {
-    uint8_t* too_far = &s.ptr[(s.len > 4) ? (s.len - 4) : 0];
+    const uint8_t* too_far = &s_ptr[(s_len > 4) ? (s_len - 4) : 0];
     uint32_t n = 1;
     while (ptr != too_far) {
       ptr--;
@@ -14713,8 +14715,7 @@
       } else if (*ptr < 0xC0) {
         continue;
       }
-      wuffs_base__utf_8__next__output o =
-          wuffs_base__utf_8__next(wuffs_base__make_slice_u8(ptr, n));
+      wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next(ptr, n);
       if (o.byte_length != n) {
         break;
       }
@@ -14727,29 +14728,29 @@
 }
 
 WUFFS_BASE__MAYBE_STATIC size_t  //
-wuffs_base__utf_8__longest_valid_prefix(wuffs_base__slice_u8 s) {
+wuffs_base__utf_8__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len) {
   // TODO: possibly optimize the all-ASCII case (4 or 8 bytes at a time).
   //
   // TODO: possibly optimize this by manually inlining the
   // wuffs_base__utf_8__next calls.
-  size_t original_len = s.len;
-  while (s.len > 0) {
-    wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next(s);
+  size_t original_len = s_len;
+  while (s_len > 0) {
+    wuffs_base__utf_8__next__output o = wuffs_base__utf_8__next(s_ptr, s_len);
     if ((o.code_point > 0x7F) && (o.byte_length == 1)) {
       break;
     }
-    s.ptr += o.byte_length;
-    s.len -= o.byte_length;
+    s_ptr += o.byte_length;
+    s_len -= o.byte_length;
   }
-  return original_len - s.len;
+  return original_len - s_len;
 }
 
 WUFFS_BASE__MAYBE_STATIC size_t  //
-wuffs_base__ascii__longest_valid_prefix(wuffs_base__slice_u8 s) {
+wuffs_base__ascii__longest_valid_prefix(const uint8_t* s_ptr, size_t s_len) {
   // TODO: possibly optimize this by checking 4 or 8 bytes at a time.
-  uint8_t* original_ptr = s.ptr;
-  uint8_t* p = s.ptr;
-  uint8_t* q = s.ptr + s.len;
+  const uint8_t* original_ptr = s_ptr;
+  const uint8_t* p = s_ptr;
+  const uint8_t* q = s_ptr + s_len;
   for (; (p != q) && ((*p & 0x80) == 0); p++) {
   }
   return (size_t)(p - original_ptr);
diff --git a/test/c/std/json.c b/test/c/std/json.c
index 9f6101d..df0d78b 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -2278,7 +2278,8 @@
     {
       uint32_t want_bl = test_cases[tc].want0 >> 24;
       uint32_t want_cp = test_cases[tc].want0 & 0xFFFFFF;
-      wuffs_base__utf_8__next__output have = wuffs_base__utf_8__next(s);
+      wuffs_base__utf_8__next__output have =
+          wuffs_base__utf_8__next(s.ptr, s.len);
       if ((have.code_point != want_cp) || (have.byte_length != want_bl)) {
         RETURN_FAIL("next(\"%s\"): have cp=0x%" PRIX32 " bl=%" PRIu32
                     ", want cp=0x%" PRIX32 " bl=%" PRIu32,
@@ -2292,7 +2293,7 @@
       uint32_t want_bl = test_cases[tc].want1 >> 24;
       uint32_t want_cp = test_cases[tc].want1 & 0xFFFFFF;
       wuffs_base__utf_8__next__output have =
-          wuffs_base__utf_8__next_from_end(s);
+          wuffs_base__utf_8__next_from_end(s.ptr, s.len);
       if ((have.code_point != want_cp) || (have.byte_length != want_bl)) {
         RETURN_FAIL("next_from_end(\"%s\"): have cp=0x%" PRIX32 " bl=%" PRIu32
                     ", want cp=0x%" PRIX32 " bl=%" PRIu32,
@@ -2664,9 +2665,8 @@
     size_t n = strlen(test_cases[tc]);
     size_t num_preceding = 0;
     while (num_preceding < n) {
-      wuffs_base__utf_8__next__output x =
-          wuffs_base__utf_8__next(wuffs_base__make_slice_u8(
-              (void*)(test_cases[tc]) + num_preceding, n - num_preceding));
+      wuffs_base__utf_8__next__output x = wuffs_base__utf_8__next(
+          (void*)(test_cases[tc]) + num_preceding, n - num_preceding);
       if (!wuffs_base__utf_8__next__output__is_valid(&x) ||
           (x.code_point < 0x20) || (x.code_point == '\\')) {
         break;