lang: add io_reader.peek_u8_at
diff --git a/internal/cgen/builtin.go b/internal/cgen/builtin.go
index cf33171..18e2e99 100644
--- a/internal/cgen/builtin.go
+++ b/internal/cgen/builtin.go
@@ -253,6 +253,14 @@
 		b.writeb(')')
 		return nil
 
+	case t.IDPeekU8At:
+		b.printf("%s%s[", iopPrefix, recvName)
+		if err := g.writeExpr(b, args[0].AsArg().Value(), false, depth); err != nil {
+			return err
+		}
+		b.writeb(']')
+		return nil
+
 	case t.IDPeekU64LEAt:
 		b.printf("wuffs_base__peek_u64le__no_bounds_check(%s%s + ", iopPrefix, recvName)
 		if err := g.writeExpr(b, args[0].AsArg().Value(), false, depth); err != nil {
diff --git a/lang/builtin/builtin.go b/lang/builtin/builtin.go
index da6a596..6dcb58a 100644
--- a/lang/builtin/builtin.go
+++ b/lang/builtin/builtin.go
@@ -510,8 +510,9 @@
 	"io_reader.peek_u64le() u64",
 
 	// As an implementation restriction, we require that offset has a constant
-	// value. The (0x1_0000 - sizeof(u64)) limit is arbitrary, but high enough
+	// value. The (0x1_0000 - sizeof(uxx)) limit is arbitrary, but high enough
 	// in practice.
+	"io_reader.peek_u8_at(offset: u32[..= 0xFFFF]) u8",
 	"io_reader.peek_u64le_at(offset: u32[..= 0xFFF8]) u64",
 
 	"io_reader.count_since(mark: u64) u64",
diff --git a/lang/check/bounds.go b/lang/check/bounds.go
index 25ca22c..4811cde 100644
--- a/lang/check/bounds.go
+++ b/lang/check/bounds.go
@@ -1259,16 +1259,20 @@
 				advanceExpr, update = actual, true
 			}
 
-		} else if method == t.IDPeekU64LEAt {
+		} else if (method == t.IDPeekU8At) || (method == t.IDPeekU64LEAt) {
 			args := n.Args()
 			if len(args) != 1 {
-				return bounds{}, fmt.Errorf("check: internal error: bad peek_u64le_at arguments")
+				return bounds{}, fmt.Errorf("check: internal error: bad peek_uxx_at arguments")
 			}
 			offset := args[0].AsArg().Value()
 			if offset.ConstValue() == nil {
-				return bounds{}, fmt.Errorf("check: peek_u64le_at offset is not a constant value")
+				return bounds{}, fmt.Errorf("check: peek_uxx_at offset is not a constant value")
 			}
-			advance, update = big.NewInt(8), false
+			adv := int64(1)
+			if method == t.IDPeekU64LEAt {
+				adv = 8
+			}
+			advance, update = big.NewInt(adv), false
 			advance.Add(advance, offset.ConstValue())
 
 		} else if method >= t.IDPeekU8 {
diff --git a/lang/token/list.go b/lang/token/list.go
index 98cf435..8daf2e6 100644
--- a/lang/token/list.go
+++ b/lang/token/list.go
@@ -570,6 +570,7 @@
 
 	IDPeekUndoByte = ID(0x1A0)
 	IDPeekU8       = ID(0x1A1)
+	IDPeekU8At     = ID(0x1A2)
 
 	IDPeekU8AsU16 = ID(0x1A5)
 	IDPeekU16BE   = ID(0x1A6)
@@ -1020,6 +1021,7 @@
 
 	IDPeekUndoByte: "peek_undo_byte",
 	IDPeekU8:       "peek_u8",
+	IDPeekU8At:     "peek_u8_at",
 
 	IDPeekU8AsU16: "peek_u8_as_u16",
 	IDPeekU16BE:   "peek_u16be",
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index d5836d3..320e924 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -51400,7 +51400,7 @@
     } else if (((uint64_t)(io2_a_src - iop_a_src)) <= 1u) {
       break;
     }
-    v_c8 = ((uint8_t)(((uint16_t)(wuffs_base__peek_u16le__no_bounds_check(iop_a_src) >> 8u))));
+    v_c8 = iop_a_src[1u];
     if (v_c8 == 0u) {
       self->private_data.f_bitstream_buffer[v_wi] = 255u;
       v_wi += 1u;
diff --git a/std/jpeg/decode_jpeg.wuffs b/std/jpeg/decode_jpeg.wuffs
index ba9e136..40ee683 100644
--- a/std/jpeg/decode_jpeg.wuffs
+++ b/std/jpeg/decode_jpeg.wuffs
@@ -1749,7 +1749,7 @@
             break
         }
 
-        c8 = (args.src.peek_u16le() >> 8) as base.u8
+        c8 = args.src.peek_u8_at(offset: 1)
         if c8 == 0x00 {
             this.bitstream_buffer[wi] = 0xFF
             wi += 1