/**
 * \file            lwrb.h
 * \brief           LwRB - Lightweight ring buffer
 */

/*
 * Copyright (c) 2024 Tilen MAJERLE
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * This file is part of LwRB - Lightweight ring buffer library.
 *
 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 * Version:         v3.1.0
 */
#ifndef LWRB_HDR_H
#define LWRB_HDR_H

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

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/**
 * \defgroup        LWRB Lightweight ring buffer manager
 * \brief           Lightweight ring buffer manager
 * \{
 */

#if !defined(LWRB_DISABLE_ATOMIC) || __DOXYGEN__
#include <stdatomic.h>

/**
 * \brief           Atomic type for size variable.
 * Default value is set to be `unsigned 32-bits` type
 *  * \brief           原子类型,用于大小变量。  
 * 默认值被设置为`无符号32位`类型  
 */ 
typedef atomic_ulong lwrb_sz_atomic_t;

/**
 * \brief           Size variable for all library operations.
 * Default value is set to be `unsigned 32-bits` type
 *  * \brief           所有库操作的大小变量。  
 * 默认值被设置为`无符号32位`类型
 */
typedef unsigned long lwrb_sz_t;
#else
typedef unsigned long lwrb_sz_atomic_t;
typedef unsigned long lwrb_sz_t;
#endif

/**
 * \brief           Event type for buffer operations
 *                  用于缓冲区操作的事件类型  
 */
typedef enum {
    LWRB_EVT_READ,  /*!< Read event */
    LWRB_EVT_WRITE, /*!< Write event */
    LWRB_EVT_RESET, /*!< Reset event */
} lwrb_evt_type_t;

/**
 * \brief           Buffer structure forward declaration环形缓冲区结构的前置声明
 */
struct lwrb;

/**
 * \brief           Event callback function type 事件回调函数类型
 * \param[in]       buff: Buffer handle for event 事件的缓冲区句柄
 * \param[in]       evt: Event type 事件类型
 * \param[in]       bp: Number of bytes written or read (when used), depends on event type 写入或读取的字节数(当使用时),取决于事件类型
 */
typedef void (*lwrb_evt_fn)(struct lwrb* buff, lwrb_evt_type_t evt, lwrb_sz_t bp);

/* List of flags */
#define LWRB_FLAG_READ_ALL  ((uint16_t)0x0001)
#define LWRB_FLAG_WRITE_ALL ((uint16_t)0x0001)

/**
 * \brief           Buffer structure
 */
typedef struct lwrb {
    uint8_t* buff;   // 指向缓冲区数据的指针。当buff != NULL且size > 0时,认为缓冲区已初始化 /
    lwrb_sz_t size; /*!<缓冲区数据的大小。实际缓冲区的大小比此值小1字节 */
    lwrb_sz_atomic_t r; /*!< 下一个读指针。当r == w时,认为缓冲区为空;当w == (r - 1 + size) % size时,认为缓冲区已满 */
    lwrb_sz_atomic_t w; /*!< 下一个写指针。当r == w时,认为缓冲区为空;当w == (r - 1 + size) % size时,认为缓冲区已满 */
    lwrb_evt_fn evt_fn; /*!< 事件回调函数指针 */
    void* arg;          /*!< 事件自定义用户参数t */
} lwrb_t;

uint8_t lwrb_init(lwrb_t* buff, void* buffdata, lwrb_sz_t size);
uint8_t lwrb_is_ready(lwrb_t* buff);
void lwrb_free(lwrb_t* buff);
void lwrb_reset(lwrb_t* buff);
void lwrb_set_evt_fn(lwrb_t* buff, lwrb_evt_fn fn);
void lwrb_set_arg(lwrb_t* buff, void* arg);
void* lwrb_get_arg(lwrb_t* buff);

/* Read/Write functions */
lwrb_sz_t lwrb_write(lwrb_t* buff, const void* data, lwrb_sz_t btw);
lwrb_sz_t lwrb_read(lwrb_t* buff, void* data, lwrb_sz_t btr);
lwrb_sz_t lwrb_peek(const lwrb_t* buff, lwrb_sz_t skip_count, void* data, lwrb_sz_t btp);

/* Extended read/write functions */
uint8_t lwrb_write_ex(lwrb_t* buff, const void* data, lwrb_sz_t btw, lwrb_sz_t* bw, uint16_t flags);
uint8_t lwrb_read_ex(lwrb_t* buff, void* data, lwrb_sz_t btr, lwrb_sz_t* br, uint16_t flags);

/* Buffer size information */
lwrb_sz_t lwrb_get_free(const lwrb_t* buff);
lwrb_sz_t lwrb_get_full(const lwrb_t* buff);

/* Read data block management */
void* lwrb_get_linear_block_read_address(const lwrb_t* buff);
lwrb_sz_t lwrb_get_linear_block_read_length(const lwrb_t* buff);
lwrb_sz_t lwrb_skip(lwrb_t* buff, lwrb_sz_t len);

/* Write data block management */
void* lwrb_get_linear_block_write_address(const lwrb_t* buff);
lwrb_sz_t lwrb_get_linear_block_write_length(const lwrb_t* buff);
lwrb_sz_t lwrb_advance(lwrb_t* buff, lwrb_sz_t len);

/* Search in buffer */
uint8_t lwrb_find(const lwrb_t* buff, const void* bts, lwrb_sz_t len, lwrb_sz_t start_offset, lwrb_sz_t* found_idx);
lwrb_sz_t lwrb_overwrite(lwrb_t* buff, const void* data, lwrb_sz_t btw);
lwrb_sz_t lwrb_move(lwrb_t* dest, lwrb_t* src);

/**
 * \}
 */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* LWRB_HDR_H */