const ParseState *
ParseState::find_next_state(Packet *pkt, const char *data,
                            size_t *bytes_parsed) const {
  // execute parser ops
  PHV *phv = pkt->get_phv();

  register_sync.lock_registers();

  for (auto &parser_op : parser_ops)
    (*parser_op)(pkt, data + *bytes_parsed, bytes_parsed);

  register_sync.unlock_registers();

  if (!has_switch) {
    BMLOG_DEBUG_PKT(
      *pkt,
      "Parser state '{}' has no switch, going to default next state",
      get_name());
    return default_next_state;
  }

  // build key
  static thread_local ByteContainer key;
  key.clear();
  key_builder(*phv, data + *bytes_parsed, &key);

  BMLOG_DEBUG_PKT(*pkt, "Parser state '{}': key is {}",
                  get_name(), key.to_hex());

  // try the matches in order
  const ParseState *next_state = NULL;
  for (const auto &switch_case : parser_switch)
    if (switch_case.match(key, &next_state)) return next_state;

  return default_next_state;
}