

#ifndef EverParse_H
#define EverParse_H

#if defined(__cplusplus)
extern "C" {
#endif

#include "EverParseEndianness.h"

static inline uint8_t EverParseGetBitfield8(uint8_t Value, uint32_t BitsFrom, uint32_t BitsTo)
{
  uint8_t op1 = (uint32_t)Value << (8U - BitsTo);
  return (uint32_t)op1 >> (8U - BitsTo + BitsFrom);
}

static inline uint16_t
EverParseGetBitfield16(uint16_t Value, uint32_t BitsFrom, uint32_t BitsTo)
{
  uint16_t bf = (uint32_t)Value << (16U - BitsTo);
  return (uint32_t)bf >> (16U - BitsTo + BitsFrom);
}

static inline uint32_t
EverParseGetBitfield32(uint32_t Value, uint32_t BitsFrom, uint32_t BitsTo)
{
  return Value << (32U - BitsTo) >> (32U - BitsTo + BitsFrom);
}

static inline uint64_t
EverParseGetBitfield64(uint64_t Value, uint32_t BitsFrom, uint32_t BitsTo)
{
  return Value << (64U - BitsTo) >> (64U - BitsTo + BitsFrom);
}

static inline uint8_t
EverParseGetBitfield8MsbFirst(uint8_t Value, uint32_t BitsFrom, uint32_t BitsTo)
{
  return EverParseGetBitfield8(Value, 8U - BitsTo, 8U - BitsFrom);
}

static inline uint16_t
EverParseGetBitfield16MsbFirst(uint16_t Value, uint32_t BitsFrom, uint32_t BitsTo)
{
  return EverParseGetBitfield16(Value, 16U - BitsTo, 16U - BitsFrom);
}

static inline uint32_t
EverParseGetBitfield32MsbFirst(uint32_t Value, uint32_t BitsFrom, uint32_t BitsTo)
{
  return EverParseGetBitfield32(Value, 32U - BitsTo, 32U - BitsFrom);
}

static inline uint64_t
EverParseGetBitfield64MsbFirst(uint64_t Value, uint32_t BitsFrom, uint32_t BitsTo)
{
  return EverParseGetBitfield64(Value, 64U - BitsTo, 64U - BitsFrom);
}

#define EVERPARSE_VALIDATOR_MAX_LENGTH (1152921504606846975ULL)

static inline BOOLEAN EverParseIsError(uint64_t PositionOrError)
{
  return PositionOrError > EVERPARSE_VALIDATOR_MAX_LENGTH;
}

static inline BOOLEAN EverParseIsSuccess(uint64_t PositionOrError)
{
  return PositionOrError <= EVERPARSE_VALIDATOR_MAX_LENGTH;
}

static inline uint64_t EverParseSetValidatorErrorPos(uint64_t Error, uint64_t Position)
{
  return (Error & 17293822569102704640ULL) | Position << 0U;
}

static inline uint64_t EverParseGetValidatorErrorPos(uint64_t X)
{
  return (X & 1152921504606846975ULL) >> 0U;
}

static inline uint64_t EverParseSetValidatorErrorKind(uint64_t Error, uint64_t Code)
{
  return (Error & 1152921504606846975ULL) | Code << 60U;
}

static inline uint64_t EverParseGetValidatorErrorKind(uint64_t Error)
{
  return (Error & 17293822569102704640ULL) >> 60U;
}

#define EVERPARSE_VALIDATOR_ERROR_GENERIC (1152921504606846976ULL)

#define EVERPARSE_VALIDATOR_ERROR_NOT_ENOUGH_DATA (2305843009213693952ULL)

#define EVERPARSE_VALIDATOR_ERROR_IMPOSSIBLE (3458764513820540928ULL)

#define EVERPARSE_VALIDATOR_ERROR_LIST_SIZE_NOT_MULTIPLE (4611686018427387904ULL)

#define EVERPARSE_VALIDATOR_ERROR_ACTION_FAILED (5764607523034234880ULL)

#define EVERPARSE_VALIDATOR_ERROR_CONSTRAINT_FAILED (6917529027641081856ULL)

#define EVERPARSE_VALIDATOR_ERROR_UNEXPECTED_PADDING (8070450532247928832ULL)

#define EVERPARSE_VALIDATOR_ERROR_PROBE_FAILED (9223372036854775808ULL)

static inline PRIMS_STRING EverParseErrorReasonOfResult(uint64_t Code)
{
  switch (EverParseGetValidatorErrorKind(Code))
  {
    case 1ULL:
      {
        return "generic error";
      }
    case 2ULL:
      {
        return "not enough data";
      }
    case 3ULL:
      {
        return "impossible";
      }
    case 4ULL:
      {
        return "list size not multiple of element size";
      }
    case 5ULL:
      {
        return "action failed";
      }
    case 6ULL:
      {
        return "constraint failed";
      }
    case 7ULL:
      {
        return "unexpected padding";
      }
    case 8ULL:
      {
        return "probe failed";
      }
    default:
      {
        return "unspecified";
      }
  }
}

static inline uint64_t EverParseCheckConstraintOk(BOOLEAN Ok, uint64_t Position)
{
  if (Ok)
  {
    return Position;
  }
  return EverParseSetValidatorErrorPos(EVERPARSE_VALIDATOR_ERROR_CONSTRAINT_FAILED, Position);
}

static inline BOOLEAN EverParseIsRangeOkay(uint32_t Size, uint32_t Offset, uint32_t AccessSize)
{
  return Size >= AccessSize && (Size - AccessSize) >= Offset;
}

typedef struct EVERPARSE_ERROR_FRAME_s
{
  BOOLEAN filled;
  uint64_t start_pos;
  PRIMS_STRING typename_s;
  PRIMS_STRING fieldname;
  PRIMS_STRING reason;
  uint64_t error_code;
}
EVERPARSE_ERROR_FRAME;

static inline BOOLEAN
EverParseHas(EVERPARSE_EXTRA_T _extra_t, EVERPARSE_INPUT_STREAM_BASE x, uint64_t n);

static uint8_t
*EverParseRead(
  EVERPARSE_EXTRA_T _extra_t,
  EVERPARSE_INPUT_STREAM_BASE x,
  uint64_t n,
  uint8_t *dst
);

static uint8_t
*EverParsePeep(EVERPARSE_EXTRA_T _extra_t, EVERPARSE_INPUT_STREAM_BASE x, uint64_t n);

static inline void
EverParseSkip(EVERPARSE_EXTRA_T _extra_t, EVERPARSE_INPUT_STREAM_BASE x, uint64_t n);

static inline uint64_t
EverParseEmpty(EVERPARSE_EXTRA_T _extra_t, EVERPARSE_INPUT_STREAM_BASE x);

typedef struct EVERPARSE_INPUT_BUFFER_s
{
  EVERPARSE_INPUT_STREAM_BASE base;
  BOOLEAN has_length;
  uint64_t length;
}
EVERPARSE_INPUT_BUFFER;

static inline EVERPARSE_INPUT_BUFFER EverParseMakeInputBuffer(EVERPARSE_INPUT_STREAM_BASE Base)
{
  return ((EVERPARSE_INPUT_BUFFER){ .base = Base, .has_length = FALSE, .length = 0ULL });
}

static inline EVERPARSE_INPUT_BUFFER
EverParseMakeInputBufferWithLength(EVERPARSE_INPUT_STREAM_BASE Base, uint64_t Length)
{
  return ((EVERPARSE_INPUT_BUFFER){ .base = Base, .has_length = TRUE, .length = Length });
}

static inline void
EverParseDefaultErrorHandler(
  PRIMS_STRING TypenameS,
  PRIMS_STRING Fieldname,
  PRIMS_STRING Reason,
  uint64_t ErrorCode,
  EVERPARSE_ERROR_FRAME *Context,
  EVERPARSE_INPUT_BUFFER Input,
  uint64_t StartPos
)
{
  KRML_MAYBE_UNUSED_VAR(Input);
  if (!(*Context).filled)
  {
    *Context =
      (
        (EVERPARSE_ERROR_FRAME){
          .filled = TRUE,
          .start_pos = StartPos,
          .typename_s = TypenameS,
          .fieldname = Fieldname,
          .reason = Reason,
          .error_code = ErrorCode
        }
      );
    return;
  }
}

extern EVERPARSE_INPUT_BUFFER EverParseStreamOf(EVERPARSE_COPY_BUFFER_T uu___);

typedef void *EVERPARSE_INV;

typedef void *EVERPARSE_LIVENESS_PRESERVED;

#if defined(__cplusplus)
}
#endif

#define EverParse_H_DEFINED
#endif /* EverParse_H */
