Have std/json return base."@end of data"
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 94c1f4f..247cba6 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -5972,6 +5972,8 @@
     wuffs_base__vtable vtable_for__wuffs_base__token_decoder;
     wuffs_base__vtable null_vtable;
 
+    bool f_end_of_data;
+
     uint32_t p_decode_tokens[1];
   } private_impl;
 
@@ -20412,6 +20414,10 @@
   switch (coro_susp_point) {
     WUFFS_BASE__COROUTINE_SUSPENSION_POINT_0;
 
+    while (self->private_impl.f_end_of_data) {
+      status = wuffs_base__make_status(wuffs_base__note__end_of_data);
+      goto ok;
+    }
     v_expect = 3762;
   label__outer__continue:;
     while (true) {
@@ -21164,6 +21170,7 @@
       v_expect = v_expect_after_value;
     }
   label__outer__break:;
+    self->private_impl.f_end_of_data = true;
 
     goto ok;
   ok:
diff --git a/std/json/decode_json.wuffs b/std/json/decode_json.wuffs
index 36aa2db..1bd524a 100644
--- a/std/json/decode_json.wuffs
+++ b/std/json/decode_json.wuffs
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 pub struct decoder? implements base.token_decoder(
+	end_of_data : base.bool,
 )(
 	// stack is conceptually an array of bits, implemented as an array of u32.
 	// The N'th bit being 0 or 1 means that we're in an array or object, where
@@ -77,6 +78,10 @@
 	var expect             : base.u32
 	var expect_after_value : base.u32
 
+	while this.end_of_data {
+		return base."@end of data"
+	}
+
 	expect = 0x0EB2  // EXPECT_VALUE
 
 	while.outer true {
@@ -835,6 +840,8 @@
 		}
 		expect = expect_after_value
 	} endwhile.outer
+
+	this.end_of_data = true
 }
 
 pri func decoder.decode_number!(src: base.io_reader) base.u32[..= 0x3FF] {
diff --git a/test/c/std/json.c b/test/c/std/json.c
index d24cd89..cdb91ca 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -798,6 +798,44 @@
 }
 
 const char*  //
+test_wuffs_json_decode_end_of_data() {
+  CHECK_FOCUS(__func__);
+
+  int i;
+  for (i = 0; i < 2; i++) {
+    uint8_t* src_ptr = (uint8_t*)("123null89");
+    size_t src_len = i ? 3 : 9;
+
+    wuffs_json__decoder dec;
+    CHECK_STATUS("initialize",
+                 wuffs_json__decoder__initialize(
+                     &dec, sizeof dec, WUFFS_VERSION,
+                     WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
+
+    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(src_ptr, src_len), true);
+    CHECK_STATUS("decode_tokens",
+                 wuffs_json__decoder__decode_tokens(&dec, &tok, &src));
+    if (src.meta.ri != 3) {
+      RETURN_FAIL("src.meta.ri: have %zu, want 3", src.meta.ri);
+    }
+
+    const char* have =
+        wuffs_json__decoder__decode_tokens(&dec, &tok, &src).repr;
+    if (have != wuffs_base__note__end_of_data) {
+      RETURN_FAIL("decode_tokens: have \"%s\", want \"%s\"", have,
+                  wuffs_base__note__end_of_data);
+    }
+    if (src.meta.ri != 3) {
+      RETURN_FAIL("src.meta.ri: have %zu, want 3", src.meta.ri);
+    }
+  }
+  return NULL;
+}
+
+const char*  //
 test_wuffs_json_decode_long_numbers() {
   CHECK_FOCUS(__func__);
 
@@ -1415,6 +1453,7 @@
     test_strconv_parse_number_u64,     //
     test_strconv_utf_8_next,           //
 
+    test_wuffs_json_decode_end_of_data,           //
     test_wuffs_json_decode_interface,             //
     test_wuffs_json_decode_long_numbers,          //
     test_wuffs_json_decode_prior_valid_utf_8,     //