AZ_NODISCARD static az_result _az_json_reader_process_number()

in sdk/src/azure/core/az_json_reader.c [497:697]


AZ_NODISCARD static az_result _az_json_reader_process_number(az_json_reader* ref_json_reader)
{
  az_span token = _get_remaining_json(ref_json_reader);

  int32_t total_consumed = 0;
  int32_t current_consumed = 0;

  uint8_t next_byte = az_span_ptr(token)[0];
  if (next_byte == '-')
  {
    total_consumed++;
    current_consumed++;

    // A negative sign must be followed by at least one digit.
    _az_RETURN_IF_FAILED(
        _az_validate_next_byte_is_digit(ref_json_reader, &token, &current_consumed));

    next_byte = az_span_ptr(token)[current_consumed];
  }

  if (next_byte == '0')
  {
    total_consumed++;
    current_consumed++;

    if (current_consumed >= az_span_size(token))
    {
      if (az_result_failed(_az_json_reader_get_next_buffer(ref_json_reader, &token, false)))
      {
        // If there is no more JSON, this is a valid end state only when the JSON payload contains a
        // single value: "[-]0"
        // Otherwise, the payload is incomplete and ending too early.
        return _az_json_reader_update_number_state_if_single_value(
            ref_json_reader,
            az_span_slice(token, 0, current_consumed),
            current_consumed,
            total_consumed);
      }
      current_consumed = 0;
    }

    next_byte = az_span_ptr(token)[current_consumed];
    az_result result = AZ_OK;
    if (_az_finished_consuming_json_number(next_byte, AZ_SPAN_FROM_STR(".eE"), &result))
    {
      if (az_result_succeeded(result))
      {
        _az_json_reader_update_state(
            ref_json_reader,
            AZ_JSON_TOKEN_NUMBER,
            az_span_slice(token, 0, current_consumed),
            current_consumed,
            total_consumed);
      }
      return result;
    }
  }
  else
  {
    _az_PRECONDITION(isdigit(next_byte));

    // Integer part before decimal
    _az_json_reader_consume_digits(ref_json_reader, &token, &current_consumed, &total_consumed);

    if (current_consumed >= az_span_size(token))
    {
      if (az_result_failed(_az_json_reader_get_next_buffer(ref_json_reader, &token, false)))
      {
        // If there is no more JSON, this is a valid end state only when the JSON payload contains a
        // single value: "[-][digits]"
        // Otherwise, the payload is incomplete and ending too early.
        return _az_json_reader_update_number_state_if_single_value(
            ref_json_reader,
            az_span_slice(token, 0, current_consumed),
            current_consumed,
            total_consumed);
      }
      current_consumed = 0;
    }

    next_byte = az_span_ptr(token)[current_consumed];
    az_result result = AZ_OK;
    if (_az_finished_consuming_json_number(next_byte, AZ_SPAN_FROM_STR(".eE"), &result))
    {
      if (az_result_succeeded(result))
      {
        _az_json_reader_update_state(
            ref_json_reader,
            AZ_JSON_TOKEN_NUMBER,
            az_span_slice(token, 0, current_consumed),
            current_consumed,
            total_consumed);
      }
      return result;
    }
  }

  if (next_byte == '.')
  {
    total_consumed++;
    current_consumed++;

    // A decimal point must be followed by at least one digit.
    _az_RETURN_IF_FAILED(
        _az_validate_next_byte_is_digit(ref_json_reader, &token, &current_consumed));

    // Integer part after decimal
    _az_json_reader_consume_digits(ref_json_reader, &token, &current_consumed, &total_consumed);

    if (current_consumed >= az_span_size(token))
    {
      if (az_result_failed(_az_json_reader_get_next_buffer(ref_json_reader, &token, false)))
      {
        // If there is no more JSON, this is a valid end state only when the JSON payload contains a
        // single value: "[-][digits].[digits]"
        // Otherwise, the payload is incomplete and ending too early.
        return _az_json_reader_update_number_state_if_single_value(
            ref_json_reader,
            az_span_slice(token, 0, current_consumed),
            current_consumed,
            total_consumed);
      }
      current_consumed = 0;
    }

    next_byte = az_span_ptr(token)[current_consumed];
    az_result result = AZ_OK;
    if (_az_finished_consuming_json_number(next_byte, AZ_SPAN_FROM_STR("eE"), &result))
    {
      if (az_result_succeeded(result))
      {
        _az_json_reader_update_state(
            ref_json_reader,
            AZ_JSON_TOKEN_NUMBER,
            az_span_slice(token, 0, current_consumed),
            current_consumed,
            total_consumed);
      }
      return result;
    }
  }

  // Move past 'e'/'E'
  total_consumed++;
  current_consumed++;

  // The 'e'/'E' character must be followed by a sign or at least one digit.
  if (current_consumed >= az_span_size(token))
  {
    _az_RETURN_IF_FAILED(_az_json_reader_get_next_buffer(ref_json_reader, &token, false));
    current_consumed = 0;
  }

  next_byte = az_span_ptr(token)[current_consumed];
  if (next_byte == '-' || next_byte == '+')
  {
    total_consumed++;
    current_consumed++;

    // A sign must be followed by at least one digit.
    _az_RETURN_IF_FAILED(
        _az_validate_next_byte_is_digit(ref_json_reader, &token, &current_consumed));
  }

  // Integer part after the 'e'/'E'
  _az_json_reader_consume_digits(ref_json_reader, &token, &current_consumed, &total_consumed);

  if (current_consumed >= az_span_size(token))
  {
    if (az_result_failed(_az_json_reader_get_next_buffer(ref_json_reader, &token, false)))
    {

      // If there is no more JSON, this is a valid end state only when the JSON payload contains a
      // single value: "[-][digits].[digits]e[+|-][digits]"
      // Otherwise, the payload is incomplete and ending too early.
      return _az_json_reader_update_number_state_if_single_value(
          ref_json_reader,
          az_span_slice(token, 0, current_consumed),
          current_consumed,
          total_consumed);
    }
    current_consumed = 0;
  }

  // Checking if we are done processing a JSON number
  next_byte = az_span_ptr(token)[current_consumed];
  int32_t index = az_span_find(json_delimiters, az_span_create(&next_byte, 1));
  if (index == -1)
  {
    return AZ_ERROR_UNEXPECTED_CHAR;
  }

  _az_json_reader_update_state(
      ref_json_reader,
      AZ_JSON_TOKEN_NUMBER,
      az_span_slice(token, 0, current_consumed),
      current_consumed,
      total_consumed);

  return AZ_OK;
}