Use QpackEncoder::InstructionWithValues to refactor QpackInstructionEncoder interface.

This change is inspired by rch's suggestion at cr/258561443.

gfe-relnote: n/a, change to QUIC v99-only code.  Protected by existing disabled gfe2_reloadable_flag_quic_enable_version_99.
PiperOrigin-RevId: 277699504
Change-Id: Iebde22504ae29f2307433458defb9f308bc5cb64
diff --git a/quic/core/qpack/qpack_constants.cc b/quic/core/qpack/qpack_constants.cc
index 6644918..1e43060 100644
--- a/quic/core/qpack/qpack_constants.cc
+++ b/quic/core/qpack/qpack_constants.cc
@@ -199,4 +199,133 @@
   return language;
 }
 
+// static
+QpackInstructionWithValues QpackInstructionWithValues::InsertWithNameReference(
+    bool is_static,
+    uint64_t name_index,
+    QuicStringPiece value) {
+  QpackInstructionWithValues instruction_with_values;
+  instruction_with_values.instruction_ = InsertWithNameReferenceInstruction();
+  instruction_with_values.s_bit_ = is_static;
+  instruction_with_values.varint_ = name_index;
+  instruction_with_values.value_ = value;
+
+  return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues
+QpackInstructionWithValues::InsertWithoutNameReference(QuicStringPiece name,
+                                                       QuicStringPiece value) {
+  QpackInstructionWithValues instruction_with_values;
+  instruction_with_values.instruction_ =
+      InsertWithoutNameReferenceInstruction();
+  instruction_with_values.name_ = name;
+  instruction_with_values.value_ = value;
+
+  return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::Duplicate(
+    uint64_t index) {
+  QpackInstructionWithValues instruction_with_values;
+  instruction_with_values.instruction_ = DuplicateInstruction();
+  instruction_with_values.varint_ = index;
+
+  return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::SetDynamicTableCapacity(
+    uint64_t capacity) {
+  QpackInstructionWithValues instruction_with_values;
+  instruction_with_values.instruction_ = SetDynamicTableCapacityInstruction();
+  instruction_with_values.varint_ = capacity;
+
+  return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::InsertCountIncrement(
+    uint64_t increment) {
+  QpackInstructionWithValues instruction_with_values;
+  instruction_with_values.instruction_ = InsertCountIncrementInstruction();
+  instruction_with_values.varint_ = increment;
+
+  return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::HeaderAcknowledgement(
+    uint64_t stream_id) {
+  QpackInstructionWithValues instruction_with_values;
+  instruction_with_values.instruction_ = HeaderAcknowledgementInstruction();
+  instruction_with_values.varint_ = stream_id;
+
+  return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::StreamCancellation(
+    uint64_t stream_id) {
+  QpackInstructionWithValues instruction_with_values;
+  instruction_with_values.instruction_ = StreamCancellationInstruction();
+  instruction_with_values.varint_ = stream_id;
+
+  return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::Prefix(
+    uint64_t required_insert_count) {
+  QpackInstructionWithValues instruction_with_values;
+  instruction_with_values.instruction_ = QpackPrefixInstruction();
+  instruction_with_values.varint_ = required_insert_count;
+  instruction_with_values.varint2_ = 0;    // Delta Base.
+  instruction_with_values.s_bit_ = false;  // Delta Base sign.
+
+  return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::IndexedHeaderField(
+    bool is_static,
+    uint64_t index) {
+  QpackInstructionWithValues instruction_with_values;
+  instruction_with_values.instruction_ = QpackIndexedHeaderFieldInstruction();
+  instruction_with_values.s_bit_ = is_static;
+  instruction_with_values.varint_ = index;
+
+  return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues
+QpackInstructionWithValues::LiteralHeaderFieldNameReference(
+    bool is_static,
+    uint64_t index,
+    QuicStringPiece value) {
+  QpackInstructionWithValues instruction_with_values;
+  instruction_with_values.instruction_ =
+      QpackLiteralHeaderFieldNameReferenceInstruction();
+  instruction_with_values.s_bit_ = is_static;
+  instruction_with_values.varint_ = index;
+  instruction_with_values.value_ = value;
+
+  return instruction_with_values;
+}
+
+// static
+QpackInstructionWithValues QpackInstructionWithValues::LiteralHeaderField(
+    QuicStringPiece name,
+    QuicStringPiece value) {
+  QpackInstructionWithValues instruction_with_values;
+  instruction_with_values.instruction_ = QpackLiteralHeaderFieldInstruction();
+  instruction_with_values.name_ = name;
+  instruction_with_values.value_ = value;
+
+  return instruction_with_values;
+}
+
 }  // namespace quic
diff --git a/quic/core/qpack/qpack_constants.h b/quic/core/qpack/qpack_constants.h
index 35e4d56..2604e37 100644
--- a/quic/core/qpack/qpack_constants.h
+++ b/quic/core/qpack/qpack_constants.h
@@ -11,9 +11,14 @@
 #include <vector>
 
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
 
 namespace quic {
 
+namespace test {
+class QpackInstructionWithValuesPeer;
+}  // namespace test
+
 // Each instruction is identified with an opcode in the first byte.
 // |mask| determines which bits are part of the opcode.
 // |value| is the value of these bits.  (Other bits in value must be zero.)
@@ -137,6 +142,66 @@
 // Request and push stream language.
 const QpackLanguage* QpackRequestStreamLanguage();
 
+// Storage for instruction and field values to be encoded.
+// This class can only be instantiated using factory methods that take exactly
+// the arguments that the corresponding instruction needs.
+class QUIC_EXPORT_PRIVATE QpackInstructionWithValues {
+ public:
+  // 5.2 Encoder stream instructions
+  static QpackInstructionWithValues InsertWithNameReference(
+      bool is_static,
+      uint64_t name_index,
+      QuicStringPiece value);
+  static QpackInstructionWithValues InsertWithoutNameReference(
+      QuicStringPiece name,
+      QuicStringPiece value);
+  static QpackInstructionWithValues Duplicate(uint64_t index);
+  static QpackInstructionWithValues SetDynamicTableCapacity(uint64_t capacity);
+
+  // 5.3 Decoder stream instructions
+  static QpackInstructionWithValues InsertCountIncrement(uint64_t increment);
+  static QpackInstructionWithValues HeaderAcknowledgement(uint64_t stream_id);
+  static QpackInstructionWithValues StreamCancellation(uint64_t stream_id);
+
+  // 5.4.1. Header data prefix.  Delta Base is hardcoded to be zero.
+  static QpackInstructionWithValues Prefix(uint64_t required_insert_count);
+
+  // 5.4.2. Request and push stream instructions
+  static QpackInstructionWithValues IndexedHeaderField(bool is_static,
+                                                       uint64_t index);
+  static QpackInstructionWithValues LiteralHeaderFieldNameReference(
+      bool is_static,
+      uint64_t index,
+      QuicStringPiece value);
+  static QpackInstructionWithValues LiteralHeaderField(QuicStringPiece name,
+                                                       QuicStringPiece value);
+
+  const QpackInstruction* instruction() const { return instruction_; }
+  bool s_bit() const { return s_bit_; }
+  uint64_t varint() const { return varint_; }
+  uint64_t varint2() const { return varint2_; }
+  QuicStringPiece name() const { return name_; }
+  QuicStringPiece value() const { return value_; }
+
+  // Used by QpackEncoder, because in the first pass it stores absolute indices,
+  // which are converted into relative indices in the second pass after base is
+  // determined.
+  void set_varint(uint64_t varint) { varint_ = varint; }
+
+ private:
+  friend test::QpackInstructionWithValuesPeer;
+
+  QpackInstructionWithValues() = default;
+
+  // |*instruction| is not owned.
+  const QpackInstruction* instruction_;
+  bool s_bit_;
+  uint64_t varint_;
+  uint64_t varint2_;
+  QuicStringPiece name_;
+  QuicStringPiece value_;
+};
+
 }  // namespace quic
 
 #endif  // QUICHE_QUIC_CORE_QPACK_QPACK_CONSTANTS_H_
diff --git a/quic/core/qpack/qpack_decoder_stream_sender.cc b/quic/core/qpack/qpack_decoder_stream_sender.cc
index 68e4d67..078a54e 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender.cc
+++ b/quic/core/qpack/qpack_decoder_stream_sender.cc
@@ -16,25 +16,19 @@
 QpackDecoderStreamSender::QpackDecoderStreamSender() : delegate_(nullptr) {}
 
 void QpackDecoderStreamSender::SendInsertCountIncrement(uint64_t increment) {
-  values_.varint = increment;
-
-  instruction_encoder_.Encode(InsertCountIncrementInstruction(), values_,
-                              &buffer_);
+  instruction_encoder_.Encode(
+      QpackInstructionWithValues::InsertCountIncrement(increment), &buffer_);
 }
 
 void QpackDecoderStreamSender::SendHeaderAcknowledgement(
     QuicStreamId stream_id) {
-  values_.varint = stream_id;
-
-  instruction_encoder_.Encode(HeaderAcknowledgementInstruction(), values_,
-                              &buffer_);
+  instruction_encoder_.Encode(
+      QpackInstructionWithValues::HeaderAcknowledgement(stream_id), &buffer_);
 }
 
 void QpackDecoderStreamSender::SendStreamCancellation(QuicStreamId stream_id) {
-  values_.varint = stream_id;
-
-  instruction_encoder_.Encode(StreamCancellationInstruction(), values_,
-                              &buffer_);
+  instruction_encoder_.Encode(
+      QpackInstructionWithValues::StreamCancellation(stream_id), &buffer_);
 }
 
 void QpackDecoderStreamSender::Flush() {
diff --git a/quic/core/qpack/qpack_decoder_stream_sender.h b/quic/core/qpack/qpack_decoder_stream_sender.h
index 93d95d9..d9033b0 100644
--- a/quic/core/qpack/qpack_decoder_stream_sender.h
+++ b/quic/core/qpack/qpack_decoder_stream_sender.h
@@ -44,7 +44,6 @@
  private:
   QpackStreamSenderDelegate* delegate_;
   QpackInstructionEncoder instruction_encoder_;
-  QpackInstructionEncoder::Values values_;
   std::string buffer_;
 };
 
diff --git a/quic/core/qpack/qpack_encoder.cc b/quic/core/qpack/qpack_encoder.cc
index 599c575..c47dccd 100644
--- a/quic/core/qpack/qpack_encoder.cc
+++ b/quic/core/qpack/qpack_encoder.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 #include <utility>
 
-#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_index_conversions.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_instruction_encoder.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_required_insert_count.h"
@@ -42,47 +41,37 @@
 QpackEncoder::~QpackEncoder() {}
 
 // static
-QpackEncoder::InstructionWithValues QpackEncoder::EncodeIndexedHeaderField(
+QpackInstructionWithValues QpackEncoder::EncodeIndexedHeaderField(
     bool is_static,
     uint64_t index,
     QpackBlockingManager::IndexSet* referred_indices) {
-  InstructionWithValues instruction{QpackIndexedHeaderFieldInstruction(), {}};
-  instruction.values.s_bit = is_static;
-  instruction.values.varint = index;
   // Add |index| to |*referred_indices| only if entry is in the dynamic table.
   if (!is_static) {
     referred_indices->insert(index);
   }
-  return instruction;
+  return QpackInstructionWithValues::IndexedHeaderField(is_static, index);
 }
 
 // static
-QpackEncoder::InstructionWithValues
+QpackInstructionWithValues
 QpackEncoder::EncodeLiteralHeaderFieldWithNameReference(
     bool is_static,
     uint64_t index,
     QuicStringPiece value,
     QpackBlockingManager::IndexSet* referred_indices) {
-  InstructionWithValues instruction{
-      QpackLiteralHeaderFieldNameReferenceInstruction(), {}};
-  instruction.values.s_bit = is_static;
-  instruction.values.varint = index;
-  instruction.values.value = value;
   // Add |index| to |*referred_indices| only if entry is in the dynamic table.
   if (!is_static) {
     referred_indices->insert(index);
   }
-  return instruction;
+  return QpackInstructionWithValues::LiteralHeaderFieldNameReference(
+      is_static, index, value);
 }
 
 // static
-QpackEncoder::InstructionWithValues QpackEncoder::EncodeLiteralHeaderField(
+QpackInstructionWithValues QpackEncoder::EncodeLiteralHeaderField(
     QuicStringPiece name,
     QuicStringPiece value) {
-  InstructionWithValues instruction{QpackLiteralHeaderFieldInstruction(), {}};
-  instruction.values.name = name;
-  instruction.values.value = value;
-  return instruction;
+  return QpackInstructionWithValues::LiteralHeaderField(name, value);
 }
 
 QpackEncoder::Instructions QpackEncoder::FirstPassEncode(
@@ -325,29 +314,24 @@
   std::string encoded_headers;
 
   // Header block prefix.
-  QpackInstructionEncoder::Values values;
-  values.varint = QpackEncodeRequiredInsertCount(required_insert_count,
-                                                 header_table_.max_entries());
-  values.varint2 = 0;    // Delta Base.
-  values.s_bit = false;  // Delta Base sign.
-  const uint64_t base = required_insert_count;
+  instruction_encoder.Encode(
+      QpackInstructionWithValues::Prefix(QpackEncodeRequiredInsertCount(
+          required_insert_count, header_table_.max_entries())),
+      &encoded_headers);
 
-  instruction_encoder.Encode(QpackPrefixInstruction(), values,
-                             &encoded_headers);
+  const uint64_t base = required_insert_count;
 
   for (auto& instruction : instructions) {
     // Dynamic table references must be transformed from absolute to relative
     // indices.
-    if ((instruction.instruction == QpackIndexedHeaderFieldInstruction() ||
-         instruction.instruction ==
+    if ((instruction.instruction() == QpackIndexedHeaderFieldInstruction() ||
+         instruction.instruction() ==
              QpackLiteralHeaderFieldNameReferenceInstruction()) &&
-        !instruction.values.s_bit) {
-      instruction.values.varint =
-          QpackAbsoluteIndexToRequestStreamRelativeIndex(
-              instruction.values.varint, base);
+        !instruction.s_bit()) {
+      instruction.set_varint(QpackAbsoluteIndexToRequestStreamRelativeIndex(
+          instruction.varint(), base));
     }
-    instruction_encoder.Encode(instruction.instruction, instruction.values,
-                               &encoded_headers);
+    instruction_encoder.Encode(instruction, &encoded_headers);
   }
 
   return encoded_headers;
diff --git a/quic/core/qpack/qpack_encoder.h b/quic/core/qpack/qpack_encoder.h
index 22232e6..0e40ddf 100644
--- a/quic/core/qpack/qpack_encoder.h
+++ b/quic/core/qpack/qpack_encoder.h
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_blocking_manager.h"
+#include "net/third_party/quiche/src/quic/core/qpack/qpack_constants.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_receiver.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h"
 #include "net/third_party/quiche/src/quic/core/qpack/qpack_header_table.h"
@@ -90,36 +91,27 @@
  private:
   friend class test::QpackEncoderPeer;
 
-  // TODO(bnc): Consider moving this class to QpackInstructionEncoder or
-  // qpack_constants, adding factory methods, one for each instruction, and
-  // changing QpackInstructionEncoder::Encoder() to take an
-  // InstructionWithValues struct instead of separate |instruction| and |values|
-  // arguments.
-  struct QUIC_EXPORT_PRIVATE InstructionWithValues {
-    // |instruction| is not owned.
-    const QpackInstruction* instruction;
-    QpackInstructionEncoder::Values values;
-  };
-  using Instructions = std::vector<InstructionWithValues>;
+  using Instructions = std::vector<QpackInstructionWithValues>;
 
   // Generate indexed header field instruction
   // and optionally update |*referred_indices|.
-  static InstructionWithValues EncodeIndexedHeaderField(
+  static QpackInstructionWithValues EncodeIndexedHeaderField(
       bool is_static,
       uint64_t index,
       QpackBlockingManager::IndexSet* referred_indices);
 
   // Generate literal header field with name reference instruction
   // and optionally update |*referred_indices|.
-  static InstructionWithValues EncodeLiteralHeaderFieldWithNameReference(
+  static QpackInstructionWithValues EncodeLiteralHeaderFieldWithNameReference(
       bool is_static,
       uint64_t index,
       QuicStringPiece value,
       QpackBlockingManager::IndexSet* referred_indices);
 
   // Generate literal header field instruction.
-  static InstructionWithValues EncodeLiteralHeaderField(QuicStringPiece name,
-                                                        QuicStringPiece value);
+  static QpackInstructionWithValues EncodeLiteralHeaderField(
+      QuicStringPiece name,
+      QuicStringPiece value);
 
   // Performs first pass of two-pass encoding: represent each header field in
   // |*header_list| as a reference to an existing entry, the name of an existing
diff --git a/quic/core/qpack/qpack_encoder_stream_sender.cc b/quic/core/qpack/qpack_encoder_stream_sender.cc
index 4a7f12c..fc7c8fd 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender.cc
+++ b/quic/core/qpack/qpack_encoder_stream_sender.cc
@@ -19,35 +19,28 @@
     bool is_static,
     uint64_t name_index,
     QuicStringPiece value) {
-  values_.s_bit = is_static;
-  values_.varint = name_index;
-  values_.value = value;
-
-  instruction_encoder_.Encode(InsertWithNameReferenceInstruction(), values_,
-                              &buffer_);
+  instruction_encoder_.Encode(
+      QpackInstructionWithValues::InsertWithNameReference(is_static, name_index,
+                                                          value),
+      &buffer_);
 }
 
 void QpackEncoderStreamSender::SendInsertWithoutNameReference(
     QuicStringPiece name,
     QuicStringPiece value) {
-  values_.name = name;
-  values_.value = value;
-
-  instruction_encoder_.Encode(InsertWithoutNameReferenceInstruction(), values_,
-                              &buffer_);
+  instruction_encoder_.Encode(
+      QpackInstructionWithValues::InsertWithoutNameReference(name, value),
+      &buffer_);
 }
 
 void QpackEncoderStreamSender::SendDuplicate(uint64_t index) {
-  values_.varint = index;
-
-  instruction_encoder_.Encode(DuplicateInstruction(), values_, &buffer_);
+  instruction_encoder_.Encode(QpackInstructionWithValues::Duplicate(index),
+                              &buffer_);
 }
 
 void QpackEncoderStreamSender::SendSetDynamicTableCapacity(uint64_t capacity) {
-  values_.varint = capacity;
-
-  instruction_encoder_.Encode(SetDynamicTableCapacityInstruction(), values_,
-                              &buffer_);
+  instruction_encoder_.Encode(
+      QpackInstructionWithValues::SetDynamicTableCapacity(capacity), &buffer_);
 }
 
 QuicByteCount QpackEncoderStreamSender::Flush() {
diff --git a/quic/core/qpack/qpack_encoder_stream_sender.h b/quic/core/qpack/qpack_encoder_stream_sender.h
index efbfbc6..de9e8f1 100644
--- a/quic/core/qpack/qpack_encoder_stream_sender.h
+++ b/quic/core/qpack/qpack_encoder_stream_sender.h
@@ -50,7 +50,6 @@
  private:
   QpackStreamSenderDelegate* delegate_;
   QpackInstructionEncoder instruction_encoder_;
-  QpackInstructionEncoder::Values values_;
   std::string buffer_;
 };
 
diff --git a/quic/core/qpack/qpack_instruction_encoder.cc b/quic/core/qpack/qpack_instruction_encoder.cc
index 5845a74..a87489d 100644
--- a/quic/core/qpack/qpack_instruction_encoder.cc
+++ b/quic/core/qpack/qpack_instruction_encoder.cc
@@ -16,13 +16,13 @@
 QpackInstructionEncoder::QpackInstructionEncoder()
     : byte_(0), state_(State::kOpcode), instruction_(nullptr) {}
 
-void QpackInstructionEncoder::Encode(const QpackInstruction* instruction,
-                                     const Values& values,
-                                     std::string* output) {
-  DCHECK(instruction);
+void QpackInstructionEncoder::Encode(
+    const QpackInstructionWithValues& instruction_with_values,
+    std::string* output) {
+  DCHECK(instruction_with_values.instruction());
 
   state_ = State::kOpcode;
-  instruction_ = instruction;
+  instruction_ = instruction_with_values.instruction();
   field_ = instruction_->fields.begin();
 
   // Field list must not be empty.
@@ -37,13 +37,15 @@
         DoStartField();
         break;
       case State::kSbit:
-        DoSBit(values.s_bit);
+        DoSBit(instruction_with_values.s_bit());
         break;
       case State::kVarintEncode:
-        DoVarintEncode(values.varint, values.varint2, output);
+        DoVarintEncode(instruction_with_values.varint(),
+                       instruction_with_values.varint2(), output);
         break;
       case State::kStartString:
-        DoStartString(values.name, values.value);
+        DoStartString(instruction_with_values.name(),
+                      instruction_with_values.value());
         break;
       case State::kWriteString:
         DoWriteString(output);
diff --git a/quic/core/qpack/qpack_instruction_encoder.h b/quic/core/qpack/qpack_instruction_encoder.h
index 4f1392a..2a59953 100644
--- a/quic/core/qpack/qpack_instruction_encoder.h
+++ b/quic/core/qpack/qpack_instruction_encoder.h
@@ -19,23 +19,12 @@
 // fields that follow each instruction.
 class QUIC_EXPORT_PRIVATE QpackInstructionEncoder {
  public:
-  // Storage for field values to be encoded.
-  // The encoded instruction determines which values are actually used.
-  struct QUIC_EXPORT_PRIVATE Values {
-    bool s_bit;
-    uint64_t varint;
-    uint64_t varint2;
-    QuicStringPiece name;
-    QuicStringPiece value;
-  };
-
   QpackInstructionEncoder();
   QpackInstructionEncoder(const QpackInstructionEncoder&) = delete;
   QpackInstructionEncoder& operator=(const QpackInstructionEncoder&) = delete;
 
   // Append encoded instruction to |output|.
-  void Encode(const QpackInstruction* instruction,
-              const Values& values,
+  void Encode(const QpackInstructionWithValues& instruction_with_values,
               std::string* output);
 
  private:
diff --git a/quic/core/qpack/qpack_instruction_encoder_test.cc b/quic/core/qpack/qpack_instruction_encoder_test.cc
index abd1353..79dfe2a 100644
--- a/quic/core/qpack/qpack_instruction_encoder_test.cc
+++ b/quic/core/qpack/qpack_instruction_encoder_test.cc
@@ -10,6 +10,42 @@
 
 namespace quic {
 namespace test {
+
+class QpackInstructionWithValuesPeer {
+ public:
+  static QpackInstructionWithValues CreateQpackInstructionWithValues(
+      const QpackInstruction* instruction) {
+    QpackInstructionWithValues instruction_with_values;
+    instruction_with_values.instruction_ = instruction;
+    return instruction_with_values;
+  }
+
+  static void set_s_bit(QpackInstructionWithValues* instruction_with_values,
+                        bool s_bit) {
+    instruction_with_values->s_bit_ = s_bit;
+  }
+
+  static void set_varint(QpackInstructionWithValues* instruction_with_values,
+                         uint64_t varint) {
+    instruction_with_values->varint_ = varint;
+  }
+
+  static void set_varint2(QpackInstructionWithValues* instruction_with_values,
+                          uint64_t varint2) {
+    instruction_with_values->varint2_ = varint2;
+  }
+
+  static void set_name(QpackInstructionWithValues* instruction_with_values,
+                       QuicStringPiece name) {
+    instruction_with_values->name_ = name;
+  }
+
+  static void set_value(QpackInstructionWithValues* instruction_with_values,
+                        QuicStringPiece value) {
+    instruction_with_values->value_ = value;
+  }
+};
+
 namespace {
 
 class QpackInstructionEncoderTest : public QuicTest {
@@ -18,9 +54,9 @@
   ~QpackInstructionEncoderTest() override = default;
 
   // Append encoded |instruction| to |output_|.
-  void EncodeInstruction(const QpackInstruction* instruction,
-                         const QpackInstructionEncoder::Values& values) {
-    encoder_.Encode(instruction, values, &output_);
+  void EncodeInstruction(
+      const QpackInstructionWithValues& instruction_with_values) {
+    encoder_.Encode(instruction_with_values, &output_);
   }
 
   // Compare substring appended to |output_| since last EncodedSegmentMatches()
@@ -42,13 +78,15 @@
   const QpackInstruction instruction{QpackInstructionOpcode{0x00, 0x80},
                                      {{QpackInstructionFieldType::kVarint, 7}}};
 
-  QpackInstructionEncoder::Values values;
-  values.varint = 5;
-  EncodeInstruction(&instruction, values);
+  auto instruction_with_values =
+      QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+          &instruction);
+  QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 5);
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("05"));
 
-  values.varint = 127;
-  EncodeInstruction(&instruction, values);
+  QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 127);
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("7f00"));
 }
 
@@ -59,17 +97,19 @@
        {QpackInstructionFieldType::kVarint, 5},
        {QpackInstructionFieldType::kVarint2, 8}}};
 
-  QpackInstructionEncoder::Values values;
-  values.s_bit = true;
-  values.varint = 5;
-  values.varint2 = 200;
-  EncodeInstruction(&instruction, values);
+  auto instruction_with_values =
+      QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+          &instruction);
+  QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true);
+  QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 5);
+  QpackInstructionWithValuesPeer::set_varint2(&instruction_with_values, 200);
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("a5c8"));
 
-  values.s_bit = false;
-  values.varint = 31;
-  values.varint2 = 356;
-  EncodeInstruction(&instruction, values);
+  QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false);
+  QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 31);
+  QpackInstructionWithValuesPeer::set_varint2(&instruction_with_values, 356);
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("9f00ff65"));
 }
 
@@ -79,17 +119,19 @@
                                       {QpackInstructionFieldType::kVarint, 5},
                                       {QpackInstructionFieldType::kValue, 7}}};
 
-  QpackInstructionEncoder::Values values;
-  values.s_bit = true;
-  values.varint = 100;
-  values.value = "foo";
-  EncodeInstruction(&instruction, values);
+  auto instruction_with_values =
+      QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+          &instruction);
+  QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true);
+  QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 100);
+  QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "foo");
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("ff458294e7"));
 
-  values.s_bit = false;
-  values.varint = 3;
-  values.value = "bar";
-  EncodeInstruction(&instruction, values);
+  QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false);
+  QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 3);
+  QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar");
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("c303626172"));
 }
 
@@ -97,17 +139,19 @@
   const QpackInstruction instruction{QpackInstructionOpcode{0xe0, 0xe0},
                                      {{QpackInstructionFieldType::kName, 4}}};
 
-  QpackInstructionEncoder::Values values;
-  values.name = "";
-  EncodeInstruction(&instruction, values);
+  auto instruction_with_values =
+      QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+          &instruction);
+  QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "");
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("e0"));
 
-  values.name = "foo";
-  EncodeInstruction(&instruction, values);
+  QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "foo");
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("f294e7"));
 
-  values.name = "bar";
-  EncodeInstruction(&instruction, values);
+  QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "bar");
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("e3626172"));
 }
 
@@ -115,17 +159,19 @@
   const QpackInstruction instruction{QpackInstructionOpcode{0xf0, 0xf0},
                                      {{QpackInstructionFieldType::kValue, 3}}};
 
-  QpackInstructionEncoder::Values values;
-  values.value = "";
-  EncodeInstruction(&instruction, values);
+  auto instruction_with_values =
+      QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+          &instruction);
+  QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "");
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("f0"));
 
-  values.value = "foo";
-  EncodeInstruction(&instruction, values);
+  QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "foo");
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("fa94e7"));
 
-  values.value = "bar";
-  EncodeInstruction(&instruction, values);
+  QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar");
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("f3626172"));
 }
 
@@ -135,17 +181,19 @@
                                       {QpackInstructionFieldType::kName, 2},
                                       {QpackInstructionFieldType::kValue, 7}}};
 
-  QpackInstructionEncoder::Values values;
-  values.s_bit = false;
-  values.name = "";
-  values.value = "";
-  EncodeInstruction(&instruction, values);
+  auto instruction_with_values =
+      QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
+          &instruction);
+  QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false);
+  QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "");
+  QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "");
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("f000"));
 
-  values.s_bit = true;
-  values.name = "foo";
-  values.value = "bar";
-  EncodeInstruction(&instruction, values);
+  QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true);
+  QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "foo");
+  QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar");
+  EncodeInstruction(instruction_with_values);
   EXPECT_TRUE(EncodedSegmentMatches("fe94e703626172"));
 }