/*
 * Copyright (c) 2026-present, the Ladybird developers.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

/* Generated with cbindgen:0.29.2 */

#include <stdint.h>
#include <stddef.h>

/// Opaque regex handle.
struct RustRegex;

/// Flags passed from C++.
struct RustRegexFlags {
    bool global;
    bool ignore_case;
    bool multiline;
    bool dot_all;
    bool unicode;
    bool unicode_sets;
    bool sticky;
    bool has_indices;
};

/// A named group entry returned across FFI.
struct RustRegexNamedGroup {
    /// The group name as a UTF-8 string (pointer to Rust-owned memory).
    const uint8_t *name;
    /// Length of the name in bytes.
    size_t name_len;
    /// The 1-based capture group index.
    uint32_t index;
};

extern "C" {

extern uint8_t *ladybird_rust_alloc(size_t size, size_t alignment);

extern uint8_t *ladybird_rust_alloc_zeroed(size_t size, size_t alignment);

extern void ladybird_rust_dealloc(uint8_t *ptr, size_t alignment);

extern uint8_t *ladybird_rust_realloc(uint8_t *ptr, size_t old_size, size_t new_size, size_t alignment);

/// Compile a regex pattern. Returns an opaque handle, or null on error.
/// On error, writes the error message to `error_out` and `error_len_out`.
/// The caller must free the error string with `rust_regex_free_error`.
///
/// # Safety
/// `pattern` must be a valid pointer to `pattern_len` bytes of UTF-8.
/// `error_out` and `error_len_out` must be valid pointers.
RustRegex *rust_regex_compile(const uint8_t *pattern,
                              size_t pattern_len,
                              RustRegexFlags flags,
                              const uint8_t **error_out,
                              size_t *error_len_out);

/// Free an error string returned by `rust_regex_compile`.
///
/// # Safety
/// `error` must be a pointer returned via `rust_regex_compile`'s error_out, or null.
void rust_regex_free_error(uint8_t *error, size_t len);

/// Free a compiled regex.
///
/// # Safety
/// `regex` must be a valid pointer returned by `rust_regex_compile`, or null.
void rust_regex_free(RustRegex *regex);

/// Execute a regex, writing captures into a caller-provided buffer.
/// Returns 1 on match, 0 on no match, -1 on step limit exceeded.
///
/// # Safety
/// - `regex` must be a valid pointer from `rust_regex_compile`.
/// - `input` must point to `input_len` u16 code units.
/// - `out_captures` must point to a buffer of at least `capture_count * 2` i32s,
///   where `capture_count` is `rust_regex_capture_count(regex) + 1`.
int32_t rust_regex_exec_into(const RustRegex *regex,
                             const uint16_t *input,
                             size_t input_len,
                             size_t start_pos,
                             int32_t *out_captures,
                             uint32_t out_capture_slots);

/// Execute a regex against ASCII input, writing captures into a caller-provided buffer.
///
/// # Safety
/// - `regex` must be a valid pointer from `rust_regex_compile`.
/// - `input` must point to `input_len` ASCII code units.
/// - `out_captures` must point to a buffer of at least `capture_count * 2` i32s.
int32_t rust_regex_exec_into_ascii(const RustRegex *regex,
                                   const uint8_t *input,
                                   size_t input_len,
                                   size_t start_pos,
                                   int32_t *out_captures,
                                   uint32_t out_capture_slots);

/// Test whether a regex matches anywhere in the input.
/// Returns 1 on match, 0 on no match, -1 on step limit exceeded.
///
/// # Safety
/// Same requirements as `rust_regex_exec`.
int32_t rust_regex_test(const RustRegex *regex, const uint16_t *input, size_t input_len, size_t start_pos);

/// Test whether a regex matches anywhere in ASCII input.
///
/// # Safety
/// Same requirements as `rust_regex_test`.
int32_t rust_regex_test_ascii(const RustRegex *regex, const uint8_t *input, size_t input_len, size_t start_pos);

/// Get the number of capture groups (not counting group 0).
///
/// # Safety
/// `regex` must be a valid pointer from `rust_regex_compile`.
uint32_t rust_regex_capture_count(const RustRegex *regex);

/// Return whether this regex is a whole-pattern literal for a single non-BMP
/// code point in unicode mode.
///
/// # Safety
/// `regex` must be a valid pointer from `rust_regex_compile`.
bool rust_regex_is_single_non_bmp_literal(const RustRegex *regex);

/// Find all non-overlapping matches and return a flat array of (start, end) i32 pairs.
/// Returns the number of matches (NOT the number of i32s). The output buffer must have
/// space for at least `max_matches * 2` i32s. Returns -1 if the buffer is too small.
///
/// # Safety
/// - `regex` must be a valid pointer from `rust_regex_compile`.
/// - `input` must point to `input_len` u16 code units.
/// - `out` must point to at least `out_capacity` i32s.
int32_t rust_regex_find_all(const RustRegex *regex,
                            const uint16_t *input,
                            size_t input_len,
                            size_t start_pos,
                            int32_t *out,
                            uint32_t out_capacity);

/// Find all non-overlapping matches in ASCII input.
///
/// # Safety
/// - `regex` must be a valid pointer from `rust_regex_compile`.
/// - `input` must point to `input_len` ASCII code units.
/// - `out` must point to at least `out_capacity` i32s.
int32_t rust_regex_find_all_ascii(const RustRegex *regex,
                                  const uint8_t *input,
                                  size_t input_len,
                                  size_t start_pos,
                                  int32_t *out,
                                  uint32_t out_capacity);

/// Get the named capture groups. Returns an array of RustRegexNamedGroup.
/// The caller must free the array (but NOT the name pointers) with `rust_regex_free_named_groups`.
///
/// # Safety
/// `regex` must be a valid pointer from `rust_regex_compile`.
/// `out_count` will be set to the number of named groups.
RustRegexNamedGroup *rust_regex_get_named_groups(const RustRegex *regex, uint32_t *out_count);

/// Free the named groups array returned by `rust_regex_get_named_groups`.
///
/// # Safety
/// `groups` must be a pointer returned by `rust_regex_get_named_groups`, or null.
void rust_regex_free_named_groups(RustRegexNamedGroup *groups, uint32_t count);

}  // extern "C"
