docs: def _unpack_response(response,
                       cursor_id=None,
                       codec_options=_UNICODE_REPLACE_CODEC_OPTIONS):
      """Unpack a response from the database.
  
      Check the response for errors and unpack, returning a dictionary
      containing the response data.
  
      Can raise CursorNotFound, NotMasterError, ExecutionTimeout, or
      OperationFailure.
  
      :Parameters:
        - `response`: byte string as returned from the database
        - `cursor_id` (optional): cursor_id we sent to get this response -
          used for raising an informative exception when we get cursor id not
          valid at server response
        - `codec_options` (optional): an instance of
          :class:`~bson.codec_options.CodecOptions`
      """
      response_flag = struct.unpack("<i", response[:4])[0]
      if response_flag & 1:
          # Shouldn't get this response if we aren't doing a getMore
          if cursor_id is None:
              raise ProtocolError("No cursor id for getMore operation")
  
          # Fake a getMore command response. OP_GET_MORE provides no document.
          msg = "Cursor not found, cursor id: %d" % (cursor_id,)
          errobj = {"ok": 0, "errmsg": msg, "code": 43}
          raise CursorNotFound(msg, 43, errobj)
      elif response_flag & 2:
          error_object = bson.BSON(response[20:]).decode()
          # Fake the ok field if it doesn't exist.
          error_object.setdefault("ok", 0)
          if error_object["$err"].startswith("not master"):
              raise NotMasterError(error_object["$err"], error_object)
          elif error_object.get("code") == 50:
              raise ExecutionTimeout(error_object.get("$err"),
                                     error_object.get("code"),
                                     error_object)
          raise OperationFailure("database error: %s" %
                                 error_object.get("$err"),
                                 error_object.get("code"),
                                 error_object)
  
      result = {"cursor_id": struct.unpack("<q", response[4:12])[0],
                "starting_from": struct.unpack("<i", response[12:16])[0],
                "number_returned": struct.unpack("<i", response[16:20])[0],
                "data": bson.decode_all(response[20:], codec_options)}
  
      assert len(result["data"]) == result["number_returned"]
      return result