Add io_buffer and token_buffer methods
diff --git a/internal/cgen/base/io-public.h b/internal/cgen/base/io-public.h
index d28761d..7b535cd 100644
--- a/internal/cgen/base/io-public.h
+++ b/internal/cgen/base/io-public.h
@@ -36,6 +36,7 @@
   wuffs_base__io_buffer_meta meta;
 
 #ifdef __cplusplus
+  inline bool is_valid() const;
   inline void compact();
   inline uint64_t reader_available() const;
   inline uint64_t reader_io_position() const;
@@ -68,6 +69,30 @@
 }
 
 static inline wuffs_base__io_buffer  //
+wuffs_base__make_io_buffer_reader(wuffs_base__slice_u8 s, bool closed) {
+  wuffs_base__io_buffer ret;
+  ret.data.ptr = s.ptr;
+  ret.data.len = s.len;
+  ret.meta.wi = s.len;
+  ret.meta.ri = 0;
+  ret.meta.pos = 0;
+  ret.meta.closed = closed;
+  return ret;
+}
+
+static inline wuffs_base__io_buffer  //
+wuffs_base__make_io_buffer_writer(wuffs_base__slice_u8 s) {
+  wuffs_base__io_buffer ret;
+  ret.data.ptr = s.ptr;
+  ret.data.len = s.len;
+  ret.meta.wi = 0;
+  ret.meta.ri = 0;
+  ret.meta.pos = 0;
+  ret.meta.closed = false;
+  return ret;
+}
+
+static inline wuffs_base__io_buffer  //
 wuffs_base__empty_io_buffer() {
   wuffs_base__io_buffer ret;
   ret.data.ptr = NULL;
@@ -89,6 +114,18 @@
   return ret;
 }
 
+static inline bool  //
+wuffs_base__io_buffer__is_valid(const wuffs_base__io_buffer* buf) {
+  if (buf) {
+    if (buf->data.ptr) {
+      return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);
+    } else {
+      return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);
+    }
+  }
+  return false;
+}
+
 // wuffs_base__io_buffer__compact moves any written but unread bytes to the
 // start of the buffer.
 static inline void  //
@@ -127,6 +164,11 @@
 
 #ifdef __cplusplus
 
+inline bool  //
+wuffs_base__io_buffer::is_valid() const {
+  return wuffs_base__io_buffer__is_valid(this);
+}
+
 inline void  //
 wuffs_base__io_buffer::compact() {
   wuffs_base__io_buffer__compact(this);
diff --git a/internal/cgen/base/token-public.h b/internal/cgen/base/token-public.h
index 31f02e7..9f48d51 100644
--- a/internal/cgen/base/token-public.h
+++ b/internal/cgen/base/token-public.h
@@ -311,6 +311,7 @@
   wuffs_base__token_buffer_meta meta;
 
 #ifdef __cplusplus
+  inline bool is_valid() const;
   inline void compact();
   inline uint64_t reader_available() const;
   inline uint64_t reader_token_position() const;
@@ -343,6 +344,30 @@
 }
 
 static inline wuffs_base__token_buffer  //
+wuffs_base__make_token_buffer_reader(wuffs_base__slice_token s, bool closed) {
+  wuffs_base__token_buffer ret;
+  ret.data.ptr = s.ptr;
+  ret.data.len = s.len;
+  ret.meta.wi = s.len;
+  ret.meta.ri = 0;
+  ret.meta.pos = 0;
+  ret.meta.closed = closed;
+  return ret;
+}
+
+static inline wuffs_base__token_buffer  //
+wuffs_base__make_token_buffer_writer(wuffs_base__slice_token s) {
+  wuffs_base__token_buffer ret;
+  ret.data.ptr = s.ptr;
+  ret.data.len = s.len;
+  ret.meta.wi = 0;
+  ret.meta.ri = 0;
+  ret.meta.pos = 0;
+  ret.meta.closed = false;
+  return ret;
+}
+
+static inline wuffs_base__token_buffer  //
 wuffs_base__empty_token_buffer() {
   wuffs_base__token_buffer ret;
   ret.data.ptr = NULL;
@@ -364,6 +389,18 @@
   return ret;
 }
 
+static inline bool  //
+wuffs_base__token_buffer__is_valid(const wuffs_base__token_buffer* buf) {
+  if (buf) {
+    if (buf->data.ptr) {
+      return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);
+    } else {
+      return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);
+    }
+  }
+  return false;
+}
+
 // wuffs_base__token_buffer__compact moves any written but unread tokens to the
 // start of the buffer.
 static inline void  //
@@ -407,6 +444,11 @@
 
 #ifdef __cplusplus
 
+inline bool  //
+wuffs_base__token_buffer::is_valid() const {
+  return wuffs_base__token_buffer__is_valid(this);
+}
+
 inline void  //
 wuffs_base__token_buffer::compact() {
   wuffs_base__token_buffer__compact(this);
diff --git a/internal/cgen/data.go b/internal/cgen/data.go
index 9d9a653..e745d8b 100644
--- a/internal/cgen/data.go
+++ b/internal/cgen/data.go
@@ -268,10 +268,11 @@
 	""
 
 const baseIOPublicH = "" +
-	"// ---------------- I/O\n//\n// See (/doc/note/io-input-output.md).\n\n// wuffs_base__io_buffer_meta is the metadata for a wuffs_base__io_buffer's\n// data.\ntypedef struct {\n  size_t wi;     // Write index. Invariant: wi <= len.\n  size_t ri;     // Read  index. Invariant: ri <= wi.\n  uint64_t pos;  // Position of the buffer start relative to the stream start.\n  bool closed;   // No further writes are expected.\n} wuffs_base__io_buffer_meta;\n\n// wuffs_base__io_buffer is a 1-dimensional buffer (a pointer and length) plus\n// additional metadata.\n//\n// A value with all fields zero is a valid, empty buffer.\ntypedef struct {\n  wuffs_base__slice_u8 data;\n  wuffs_base__io_buffer_meta meta;\n\n#ifdef __cplusplus\n  inline void compact();\n  inline uint64_t reader_available() const;\n  inline uint64_t reader_io_position() const;\n  inline uint64_t writer_available() const;\n  inline uint64_t writer_io_position() const;\n#endif  // __cplusplus\n\n} wuffs_base__io_buffer;\n\nstatic inline wuffs_base__io_buffer  //\nwuffs_base__make_io_buff" +
-	"er(wuffs_base__slice_u8 data,\n                           wuffs_base__io_buffer_meta meta) {\n  wuffs_base__io_buffer ret;\n  ret.data = data;\n  ret.meta = meta;\n  return ret;\n}\n\nstatic inline wuffs_base__io_buffer_meta  //\nwuffs_base__make_io_buffer_meta(size_t wi,\n                                size_t ri,\n                                uint64_t pos,\n                                bool closed) {\n  wuffs_base__io_buffer_meta ret;\n  ret.wi = wi;\n  ret.ri = ri;\n  ret.pos = pos;\n  ret.closed = closed;\n  return ret;\n}\n\nstatic inline wuffs_base__io_buffer  //\nwuffs_base__empty_io_buffer() {\n  wuffs_base__io_buffer ret;\n  ret.data.ptr = NULL;\n  ret.data.len = 0;\n  ret.meta.wi = 0;\n  ret.meta.ri = 0;\n  ret.meta.pos = 0;\n  ret.meta.closed = false;\n  return ret;\n}\n\nstatic inline wuffs_base__io_buffer_meta  //\nwuffs_base__empty_io_buffer_meta() {\n  wuffs_base__io_buffer_meta ret;\n  ret.wi = 0;\n  ret.ri = 0;\n  ret.pos = 0;\n  ret.closed = false;\n  return ret;\n}\n\n// wuffs_base__io_buffer__compact moves any written but unr" +
-	"ead bytes to the\n// start of the buffer.\nstatic inline void  //\nwuffs_base__io_buffer__compact(wuffs_base__io_buffer* buf) {\n  if (!buf || (buf->meta.ri == 0)) {\n    return;\n  }\n  buf->meta.pos = wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri);\n  size_t n = buf->meta.wi - buf->meta.ri;\n  if (n != 0) {\n    memmove(buf->data.ptr, buf->data.ptr + buf->meta.ri, n);\n  }\n  buf->meta.wi = n;\n  buf->meta.ri = 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__io_buffer__reader_available(const wuffs_base__io_buffer* buf) {\n  return buf ? buf->meta.wi - buf->meta.ri : 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__io_buffer__reader_io_position(const wuffs_base__io_buffer* buf) {\n  return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri) : 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__io_buffer__writer_available(const wuffs_base__io_buffer* buf) {\n  return buf ? buf->data.len - buf->meta.wi : 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__io_buffer__writer_io_position(const wuffs_base__io_buffer* buf) {\n  return bu" +
-	"f ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.wi) : 0;\n}\n\n#ifdef __cplusplus\n\ninline void  //\nwuffs_base__io_buffer::compact() {\n  wuffs_base__io_buffer__compact(this);\n}\n\ninline uint64_t  //\nwuffs_base__io_buffer::reader_available() const {\n  return wuffs_base__io_buffer__reader_available(this);\n}\n\ninline uint64_t  //\nwuffs_base__io_buffer::reader_io_position() const {\n  return wuffs_base__io_buffer__reader_io_position(this);\n}\n\ninline uint64_t  //\nwuffs_base__io_buffer::writer_available() const {\n  return wuffs_base__io_buffer__writer_available(this);\n}\n\ninline uint64_t  //\nwuffs_base__io_buffer::writer_io_position() const {\n  return wuffs_base__io_buffer__writer_io_position(this);\n}\n\n#endif  // __cplusplus\n" +
+	"// ---------------- I/O\n//\n// See (/doc/note/io-input-output.md).\n\n// wuffs_base__io_buffer_meta is the metadata for a wuffs_base__io_buffer's\n// data.\ntypedef struct {\n  size_t wi;     // Write index. Invariant: wi <= len.\n  size_t ri;     // Read  index. Invariant: ri <= wi.\n  uint64_t pos;  // Position of the buffer start relative to the stream start.\n  bool closed;   // No further writes are expected.\n} wuffs_base__io_buffer_meta;\n\n// wuffs_base__io_buffer is a 1-dimensional buffer (a pointer and length) plus\n// additional metadata.\n//\n// A value with all fields zero is a valid, empty buffer.\ntypedef struct {\n  wuffs_base__slice_u8 data;\n  wuffs_base__io_buffer_meta meta;\n\n#ifdef __cplusplus\n  inline bool is_valid() const;\n  inline void compact();\n  inline uint64_t reader_available() const;\n  inline uint64_t reader_io_position() const;\n  inline uint64_t writer_available() const;\n  inline uint64_t writer_io_position() const;\n#endif  // __cplusplus\n\n} wuffs_base__io_buffer;\n\nstatic inline wuffs_base__io_buf" +
+	"fer  //\nwuffs_base__make_io_buffer(wuffs_base__slice_u8 data,\n                           wuffs_base__io_buffer_meta meta) {\n  wuffs_base__io_buffer ret;\n  ret.data = data;\n  ret.meta = meta;\n  return ret;\n}\n\nstatic inline wuffs_base__io_buffer_meta  //\nwuffs_base__make_io_buffer_meta(size_t wi,\n                                size_t ri,\n                                uint64_t pos,\n                                bool closed) {\n  wuffs_base__io_buffer_meta ret;\n  ret.wi = wi;\n  ret.ri = ri;\n  ret.pos = pos;\n  ret.closed = closed;\n  return ret;\n}\n\nstatic inline wuffs_base__io_buffer  //\nwuffs_base__make_io_buffer_reader(wuffs_base__slice_u8 s, bool closed) {\n  wuffs_base__io_buffer ret;\n  ret.data.ptr = s.ptr;\n  ret.data.len = s.len;\n  ret.meta.wi = s.len;\n  ret.meta.ri = 0;\n  ret.meta.pos = 0;\n  ret.meta.closed = closed;\n  return ret;\n}\n\nstatic inline wuffs_base__io_buffer  //\nwuffs_base__make_io_buffer_writer(wuffs_base__slice_u8 s) {\n  wuffs_base__io_buffer ret;\n  ret.data.ptr = s.ptr;\n  ret.data.len = s.le" +
+	"n;\n  ret.meta.wi = 0;\n  ret.meta.ri = 0;\n  ret.meta.pos = 0;\n  ret.meta.closed = false;\n  return ret;\n}\n\nstatic inline wuffs_base__io_buffer  //\nwuffs_base__empty_io_buffer() {\n  wuffs_base__io_buffer ret;\n  ret.data.ptr = NULL;\n  ret.data.len = 0;\n  ret.meta.wi = 0;\n  ret.meta.ri = 0;\n  ret.meta.pos = 0;\n  ret.meta.closed = false;\n  return ret;\n}\n\nstatic inline wuffs_base__io_buffer_meta  //\nwuffs_base__empty_io_buffer_meta() {\n  wuffs_base__io_buffer_meta ret;\n  ret.wi = 0;\n  ret.ri = 0;\n  ret.pos = 0;\n  ret.closed = false;\n  return ret;\n}\n\nstatic inline bool  //\nwuffs_base__io_buffer__is_valid(const wuffs_base__io_buffer* buf) {\n  if (buf) {\n    if (buf->data.ptr) {\n      return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);\n    } else {\n      return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);\n    }\n  }\n  return false;\n}\n\n// wuffs_base__io_buffer__compact moves any written but unread bytes to the\n// start of the buffer.\nstatic inline void  //\nwuffs_base__io_buffe" +
+	"r__compact(wuffs_base__io_buffer* buf) {\n  if (!buf || (buf->meta.ri == 0)) {\n    return;\n  }\n  buf->meta.pos = wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri);\n  size_t n = buf->meta.wi - buf->meta.ri;\n  if (n != 0) {\n    memmove(buf->data.ptr, buf->data.ptr + buf->meta.ri, n);\n  }\n  buf->meta.wi = n;\n  buf->meta.ri = 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__io_buffer__reader_available(const wuffs_base__io_buffer* buf) {\n  return buf ? buf->meta.wi - buf->meta.ri : 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__io_buffer__reader_io_position(const wuffs_base__io_buffer* buf) {\n  return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri) : 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__io_buffer__writer_available(const wuffs_base__io_buffer* buf) {\n  return buf ? buf->data.len - buf->meta.wi : 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__io_buffer__writer_io_position(const wuffs_base__io_buffer* buf) {\n  return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.wi) : 0;\n}\n\n#ifdef __cplusplus" +
+	"\n\ninline bool  //\nwuffs_base__io_buffer::is_valid() const {\n  return wuffs_base__io_buffer__is_valid(this);\n}\n\ninline void  //\nwuffs_base__io_buffer::compact() {\n  wuffs_base__io_buffer__compact(this);\n}\n\ninline uint64_t  //\nwuffs_base__io_buffer::reader_available() const {\n  return wuffs_base__io_buffer__reader_available(this);\n}\n\ninline uint64_t  //\nwuffs_base__io_buffer::reader_io_position() const {\n  return wuffs_base__io_buffer__reader_io_position(this);\n}\n\ninline uint64_t  //\nwuffs_base__io_buffer::writer_available() const {\n  return wuffs_base__io_buffer__writer_available(this);\n}\n\ninline uint64_t  //\nwuffs_base__io_buffer::writer_io_position() const {\n  return wuffs_base__io_buffer__writer_io_position(this);\n}\n\n#endif  // __cplusplus\n" +
 	""
 
 const baseRangePrivateH = "" +
@@ -374,10 +375,11 @@
 	"" +
 	"// --------\n\ntypedef WUFFS_BASE__SLICE(wuffs_base__token) wuffs_base__slice_token;\n\nstatic inline wuffs_base__slice_token  //\nwuffs_base__make_slice_token(wuffs_base__token* ptr, size_t len) {\n  wuffs_base__slice_token ret;\n  ret.ptr = ptr;\n  ret.len = len;\n  return ret;\n}\n\n" +
 	"" +
-	"// --------\n\n// wuffs_base__token_buffer_meta is the metadata for a\n// wuffs_base__token_buffer's data.\ntypedef struct {\n  size_t wi;     // Write index. Invariant: wi <= len.\n  size_t ri;     // Read  index. Invariant: ri <= wi.\n  uint64_t pos;  // Position of the buffer start relative to the stream start.\n  bool closed;   // No further writes are expected.\n} wuffs_base__token_buffer_meta;\n\n// wuffs_base__token_buffer is a 1-dimensional buffer (a pointer and length)\n// plus additional metadata.\n//\n// A value with all fields zero is a valid, empty buffer.\ntypedef struct {\n  wuffs_base__slice_token data;\n  wuffs_base__token_buffer_meta meta;\n\n#ifdef __cplusplus\n  inline void compact();\n  inline uint64_t reader_available() const;\n  inline uint64_t reader_token_position() const;\n  inline uint64_t writer_available() const;\n  inline uint64_t writer_token_position() const;\n#endif  // __cplusplus\n\n} wuffs_base__token_buffer;\n\nstatic inline wuffs_base__token_buffer  //\nwuffs_base__make_token_buffer(wuffs_base__slice_" +
-	"token data,\n                              wuffs_base__token_buffer_meta meta) {\n  wuffs_base__token_buffer ret;\n  ret.data = data;\n  ret.meta = meta;\n  return ret;\n}\n\nstatic inline wuffs_base__token_buffer_meta  //\nwuffs_base__make_token_buffer_meta(size_t wi,\n                                   size_t ri,\n                                   uint64_t pos,\n                                   bool closed) {\n  wuffs_base__token_buffer_meta ret;\n  ret.wi = wi;\n  ret.ri = ri;\n  ret.pos = pos;\n  ret.closed = closed;\n  return ret;\n}\n\nstatic inline wuffs_base__token_buffer  //\nwuffs_base__empty_token_buffer() {\n  wuffs_base__token_buffer ret;\n  ret.data.ptr = NULL;\n  ret.data.len = 0;\n  ret.meta.wi = 0;\n  ret.meta.ri = 0;\n  ret.meta.pos = 0;\n  ret.meta.closed = false;\n  return ret;\n}\n\nstatic inline wuffs_base__token_buffer_meta  //\nwuffs_base__empty_token_buffer_meta() {\n  wuffs_base__token_buffer_meta ret;\n  ret.wi = 0;\n  ret.ri = 0;\n  ret.pos = 0;\n  ret.closed = false;\n  return ret;\n}\n\n// wuffs_base__token_buffer__com" +
-	"pact moves any written but unread tokens to the\n// start of the buffer.\nstatic inline void  //\nwuffs_base__token_buffer__compact(wuffs_base__token_buffer* buf) {\n  if (!buf || (buf->meta.ri == 0)) {\n    return;\n  }\n  buf->meta.pos = wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri);\n  size_t n = buf->meta.wi - buf->meta.ri;\n  if (n != 0) {\n    memmove(buf->data.ptr, buf->data.ptr + buf->meta.ri,\n            n * sizeof(wuffs_base__token));\n  }\n  buf->meta.wi = n;\n  buf->meta.ri = 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__token_buffer__reader_available(\n    const wuffs_base__token_buffer* buf) {\n  return buf ? buf->meta.wi - buf->meta.ri : 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__token_buffer__reader_token_position(\n    const wuffs_base__token_buffer* buf) {\n  return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri) : 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__token_buffer__writer_available(\n    const wuffs_base__token_buffer* buf) {\n  return buf ? buf->data.len - buf->meta.wi : 0;\n}\n\nsta" +
-	"tic inline uint64_t  //\nwuffs_base__token_buffer__writer_token_position(\n    const wuffs_base__token_buffer* buf) {\n  return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.wi) : 0;\n}\n\n#ifdef __cplusplus\n\ninline void  //\nwuffs_base__token_buffer::compact() {\n  wuffs_base__token_buffer__compact(this);\n}\n\ninline uint64_t  //\nwuffs_base__token_buffer::reader_available() const {\n  return wuffs_base__token_buffer__reader_available(this);\n}\n\ninline uint64_t  //\nwuffs_base__token_buffer::reader_token_position() const {\n  return wuffs_base__token_buffer__reader_token_position(this);\n}\n\ninline uint64_t  //\nwuffs_base__token_buffer::writer_available() const {\n  return wuffs_base__token_buffer__writer_available(this);\n}\n\ninline uint64_t  //\nwuffs_base__token_buffer::writer_token_position() const {\n  return wuffs_base__token_buffer__writer_token_position(this);\n}\n\n#endif  // __cplusplus\n" +
+	"// --------\n\n// wuffs_base__token_buffer_meta is the metadata for a\n// wuffs_base__token_buffer's data.\ntypedef struct {\n  size_t wi;     // Write index. Invariant: wi <= len.\n  size_t ri;     // Read  index. Invariant: ri <= wi.\n  uint64_t pos;  // Position of the buffer start relative to the stream start.\n  bool closed;   // No further writes are expected.\n} wuffs_base__token_buffer_meta;\n\n// wuffs_base__token_buffer is a 1-dimensional buffer (a pointer and length)\n// plus additional metadata.\n//\n// A value with all fields zero is a valid, empty buffer.\ntypedef struct {\n  wuffs_base__slice_token data;\n  wuffs_base__token_buffer_meta meta;\n\n#ifdef __cplusplus\n  inline bool is_valid() const;\n  inline void compact();\n  inline uint64_t reader_available() const;\n  inline uint64_t reader_token_position() const;\n  inline uint64_t writer_available() const;\n  inline uint64_t writer_token_position() const;\n#endif  // __cplusplus\n\n} wuffs_base__token_buffer;\n\nstatic inline wuffs_base__token_buffer  //\nwuffs_base__make" +
+	"_token_buffer(wuffs_base__slice_token data,\n                              wuffs_base__token_buffer_meta meta) {\n  wuffs_base__token_buffer ret;\n  ret.data = data;\n  ret.meta = meta;\n  return ret;\n}\n\nstatic inline wuffs_base__token_buffer_meta  //\nwuffs_base__make_token_buffer_meta(size_t wi,\n                                   size_t ri,\n                                   uint64_t pos,\n                                   bool closed) {\n  wuffs_base__token_buffer_meta ret;\n  ret.wi = wi;\n  ret.ri = ri;\n  ret.pos = pos;\n  ret.closed = closed;\n  return ret;\n}\n\nstatic inline wuffs_base__token_buffer  //\nwuffs_base__make_token_buffer_reader(wuffs_base__slice_token s, bool closed) {\n  wuffs_base__token_buffer ret;\n  ret.data.ptr = s.ptr;\n  ret.data.len = s.len;\n  ret.meta.wi = s.len;\n  ret.meta.ri = 0;\n  ret.meta.pos = 0;\n  ret.meta.closed = closed;\n  return ret;\n}\n\nstatic inline wuffs_base__token_buffer  //\nwuffs_base__make_token_buffer_writer(wuffs_base__slice_token s) {\n  wuffs_base__token_buffer ret;\n  ret.data.p" +
+	"tr = s.ptr;\n  ret.data.len = s.len;\n  ret.meta.wi = 0;\n  ret.meta.ri = 0;\n  ret.meta.pos = 0;\n  ret.meta.closed = false;\n  return ret;\n}\n\nstatic inline wuffs_base__token_buffer  //\nwuffs_base__empty_token_buffer() {\n  wuffs_base__token_buffer ret;\n  ret.data.ptr = NULL;\n  ret.data.len = 0;\n  ret.meta.wi = 0;\n  ret.meta.ri = 0;\n  ret.meta.pos = 0;\n  ret.meta.closed = false;\n  return ret;\n}\n\nstatic inline wuffs_base__token_buffer_meta  //\nwuffs_base__empty_token_buffer_meta() {\n  wuffs_base__token_buffer_meta ret;\n  ret.wi = 0;\n  ret.ri = 0;\n  ret.pos = 0;\n  ret.closed = false;\n  return ret;\n}\n\nstatic inline bool  //\nwuffs_base__token_buffer__is_valid(const wuffs_base__token_buffer* buf) {\n  if (buf) {\n    if (buf->data.ptr) {\n      return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);\n    } else {\n      return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);\n    }\n  }\n  return false;\n}\n\n// wuffs_base__token_buffer__compact moves any written but unread tokens to the\n// sta" +
+	"rt of the buffer.\nstatic inline void  //\nwuffs_base__token_buffer__compact(wuffs_base__token_buffer* buf) {\n  if (!buf || (buf->meta.ri == 0)) {\n    return;\n  }\n  buf->meta.pos = wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri);\n  size_t n = buf->meta.wi - buf->meta.ri;\n  if (n != 0) {\n    memmove(buf->data.ptr, buf->data.ptr + buf->meta.ri,\n            n * sizeof(wuffs_base__token));\n  }\n  buf->meta.wi = n;\n  buf->meta.ri = 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__token_buffer__reader_available(\n    const wuffs_base__token_buffer* buf) {\n  return buf ? buf->meta.wi - buf->meta.ri : 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__token_buffer__reader_token_position(\n    const wuffs_base__token_buffer* buf) {\n  return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.ri) : 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__token_buffer__writer_available(\n    const wuffs_base__token_buffer* buf) {\n  return buf ? buf->data.len - buf->meta.wi : 0;\n}\n\nstatic inline uint64_t  //\nwuffs_base__token_buffer__writ" +
+	"er_token_position(\n    const wuffs_base__token_buffer* buf) {\n  return buf ? wuffs_base__u64__sat_add(buf->meta.pos, buf->meta.wi) : 0;\n}\n\n#ifdef __cplusplus\n\ninline bool  //\nwuffs_base__token_buffer::is_valid() const {\n  return wuffs_base__token_buffer__is_valid(this);\n}\n\ninline void  //\nwuffs_base__token_buffer::compact() {\n  wuffs_base__token_buffer__compact(this);\n}\n\ninline uint64_t  //\nwuffs_base__token_buffer::reader_available() const {\n  return wuffs_base__token_buffer__reader_available(this);\n}\n\ninline uint64_t  //\nwuffs_base__token_buffer::reader_token_position() const {\n  return wuffs_base__token_buffer__reader_token_position(this);\n}\n\ninline uint64_t  //\nwuffs_base__token_buffer::writer_available() const {\n  return wuffs_base__token_buffer__writer_available(this);\n}\n\ninline uint64_t  //\nwuffs_base__token_buffer::writer_token_position() const {\n  return wuffs_base__token_buffer__writer_token_position(this);\n}\n\n#endif  // __cplusplus\n" +
 	""
 
 const baseCopyright = "" +
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index c7559dd..94c1f4f 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -1613,6 +1613,7 @@
   wuffs_base__io_buffer_meta meta;
 
 #ifdef __cplusplus
+  inline bool is_valid() const;
   inline void compact();
   inline uint64_t reader_available() const;
   inline uint64_t reader_io_position() const;
@@ -1645,6 +1646,30 @@
 }
 
 static inline wuffs_base__io_buffer  //
+wuffs_base__make_io_buffer_reader(wuffs_base__slice_u8 s, bool closed) {
+  wuffs_base__io_buffer ret;
+  ret.data.ptr = s.ptr;
+  ret.data.len = s.len;
+  ret.meta.wi = s.len;
+  ret.meta.ri = 0;
+  ret.meta.pos = 0;
+  ret.meta.closed = closed;
+  return ret;
+}
+
+static inline wuffs_base__io_buffer  //
+wuffs_base__make_io_buffer_writer(wuffs_base__slice_u8 s) {
+  wuffs_base__io_buffer ret;
+  ret.data.ptr = s.ptr;
+  ret.data.len = s.len;
+  ret.meta.wi = 0;
+  ret.meta.ri = 0;
+  ret.meta.pos = 0;
+  ret.meta.closed = false;
+  return ret;
+}
+
+static inline wuffs_base__io_buffer  //
 wuffs_base__empty_io_buffer() {
   wuffs_base__io_buffer ret;
   ret.data.ptr = NULL;
@@ -1666,6 +1691,18 @@
   return ret;
 }
 
+static inline bool  //
+wuffs_base__io_buffer__is_valid(const wuffs_base__io_buffer* buf) {
+  if (buf) {
+    if (buf->data.ptr) {
+      return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);
+    } else {
+      return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);
+    }
+  }
+  return false;
+}
+
 // wuffs_base__io_buffer__compact moves any written but unread bytes to the
 // start of the buffer.
 static inline void  //
@@ -1704,6 +1741,11 @@
 
 #ifdef __cplusplus
 
+inline bool  //
+wuffs_base__io_buffer::is_valid() const {
+  return wuffs_base__io_buffer__is_valid(this);
+}
+
 inline void  //
 wuffs_base__io_buffer::compact() {
   wuffs_base__io_buffer__compact(this);
@@ -2028,6 +2070,7 @@
   wuffs_base__token_buffer_meta meta;
 
 #ifdef __cplusplus
+  inline bool is_valid() const;
   inline void compact();
   inline uint64_t reader_available() const;
   inline uint64_t reader_token_position() const;
@@ -2060,6 +2103,30 @@
 }
 
 static inline wuffs_base__token_buffer  //
+wuffs_base__make_token_buffer_reader(wuffs_base__slice_token s, bool closed) {
+  wuffs_base__token_buffer ret;
+  ret.data.ptr = s.ptr;
+  ret.data.len = s.len;
+  ret.meta.wi = s.len;
+  ret.meta.ri = 0;
+  ret.meta.pos = 0;
+  ret.meta.closed = closed;
+  return ret;
+}
+
+static inline wuffs_base__token_buffer  //
+wuffs_base__make_token_buffer_writer(wuffs_base__slice_token s) {
+  wuffs_base__token_buffer ret;
+  ret.data.ptr = s.ptr;
+  ret.data.len = s.len;
+  ret.meta.wi = 0;
+  ret.meta.ri = 0;
+  ret.meta.pos = 0;
+  ret.meta.closed = false;
+  return ret;
+}
+
+static inline wuffs_base__token_buffer  //
 wuffs_base__empty_token_buffer() {
   wuffs_base__token_buffer ret;
   ret.data.ptr = NULL;
@@ -2081,6 +2148,18 @@
   return ret;
 }
 
+static inline bool  //
+wuffs_base__token_buffer__is_valid(const wuffs_base__token_buffer* buf) {
+  if (buf) {
+    if (buf->data.ptr) {
+      return (buf->meta.ri <= buf->meta.wi) && (buf->meta.wi <= buf->data.len);
+    } else {
+      return (buf->meta.ri == 0) && (buf->meta.wi == 0) && (buf->data.len == 0);
+    }
+  }
+  return false;
+}
+
 // wuffs_base__token_buffer__compact moves any written but unread tokens to the
 // start of the buffer.
 static inline void  //
@@ -2124,6 +2203,11 @@
 
 #ifdef __cplusplus
 
+inline bool  //
+wuffs_base__token_buffer::is_valid() const {
+  return wuffs_base__token_buffer__is_valid(this);
+}
+
 inline void  //
 wuffs_base__token_buffer::compact() {
   wuffs_base__token_buffer__compact(this);
diff --git a/test/c/std/json.c b/test/c/std/json.c
index ae52f56..d24cd89 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -885,16 +885,10 @@
                 &dec, sizeof dec, WUFFS_VERSION,
                 WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
 
-        wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
-            .data = global_have_token_slice,
-        });
-
-        wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
-            .data = src_data,
-            .meta = wuffs_base__make_io_buffer_meta(src_data.len, 0, 0,
-                                                    closed != 0),
-        });
-
+        wuffs_base__token_buffer tok =
+            wuffs_base__make_token_buffer_writer(global_have_token_slice);
+        wuffs_base__io_buffer src =
+            wuffs_base__make_io_buffer_reader(src_data, closed != 0);
         const char* have =
             wuffs_json__decoder__decode_tokens(&dec, &tok, &src).repr;
 
@@ -1036,16 +1030,10 @@
           CHECK_STATUS("initialize", wuffs_json__decoder__initialize(
                                          &dec, sizeof dec, WUFFS_VERSION, 0));
 
-          wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
-              .data = global_have_token_slice,
-          });
-
-          wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
-              .data = src_data,
-              .meta = wuffs_base__make_io_buffer_meta(src_data.len, 0, 0,
-                                                      closed != 0),
-          });
-
+          wuffs_base__token_buffer tok =
+              wuffs_base__make_token_buffer_writer(global_have_token_slice);
+          wuffs_base__io_buffer src =
+              wuffs_base__make_io_buffer_reader(src_data, closed != 0);
           wuffs_json__decoder__decode_tokens(&dec, &tok, &src);
 
           size_t have = 0;
@@ -1139,15 +1127,12 @@
                      &dec, sizeof dec, WUFFS_VERSION,
                      WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
 
-    wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
-        .data = global_have_token_slice,
-    });
-    size_t n = strlen(test_cases[tc].str);
-    wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
-        .data = wuffs_base__make_slice_u8((void*)(test_cases[tc].str), n),
-        .meta = wuffs_base__make_io_buffer_meta(n, 0, 0, true),
-    });
-
+    wuffs_base__token_buffer tok =
+        wuffs_base__make_token_buffer_writer(global_have_token_slice);
+    wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+        wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+                                  strlen(test_cases[tc].str)),
+        true);
     wuffs_json__decoder__decode_tokens(&dec, &tok, &src);
 
     uint32_t have = fail;
@@ -1231,14 +1216,10 @@
 
     int closed;
     for (closed = 0; closed < 2; closed++) {
-      wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
-          .data = global_have_token_slice,
-      });
-      wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
-          .data = src_data,
-          .meta =
-              wuffs_base__make_io_buffer_meta(src_data.len, 0, 0, closed != 0),
-      });
+      wuffs_base__token_buffer tok =
+          wuffs_base__make_token_buffer_writer(global_have_token_slice);
+      wuffs_base__io_buffer src =
+          wuffs_base__make_io_buffer_reader(src_data, closed != 0);
       CHECK_STATUS("initialize",
                    wuffs_json__decoder__initialize(
                        &dec, sizeof dec, WUFFS_VERSION,
@@ -1338,15 +1319,12 @@
                      &dec, sizeof dec, WUFFS_VERSION,
                      WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
 
-    wuffs_base__token_buffer tok = ((wuffs_base__token_buffer){
-        .data = global_have_token_slice,
-    });
-    size_t n = strlen(test_cases[tc].str);
-    wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
-        .data = wuffs_base__make_slice_u8((void*)(test_cases[tc].str), n),
-        .meta = wuffs_base__make_io_buffer_meta(n, 0, 0, true),
-    });
-
+    wuffs_base__token_buffer tok =
+        wuffs_base__make_token_buffer_writer(global_have_token_slice);
+    wuffs_base__io_buffer src = wuffs_base__make_io_buffer_reader(
+        wuffs_base__make_slice_u8((void*)(test_cases[tc].str),
+                                  strlen(test_cases[tc].str)),
+        true);
     wuffs_base__status have_status =
         wuffs_json__decoder__decode_tokens(&dec, &tok, &src);