// SPDX-License-Identifier: BSD-3-Clause
// LittleFS freestanding configuration for Rumpk unikernel.
//
// Replaces lfs_util.h entirely via -DLFS_CONFIG=lfs_rumpk.h.
// Provides minimal stubs using kernel-provided malloc/free/memcpy/memset.
#ifndef LFS_RUMPK_H
#define LFS_RUMPK_H

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

#ifdef __cplusplus
extern "C" {
#endif

// --- NULL (freestanding stddef.h may not always provide it) ---
#ifndef NULL
#define NULL ((void *)0)
#endif

// --- Logging: all disabled in freestanding kernel ---
#define LFS_TRACE(...)
#define LFS_DEBUG(...)
#define LFS_WARN(...)
#define LFS_ERROR(...)

// --- Assertions: disabled ---
#define LFS_ASSERT(test) ((void)(test))

// --- Memory functions (provided by clib.c / libc_shim.zig) ---
extern void *malloc(unsigned long size);
extern void free(void *ptr);
extern void *memcpy(void *dest, const void *src, unsigned long n);
extern void *memset(void *s, int c, unsigned long n);
extern int memcmp(const void *s1, const void *s2, unsigned long n);
extern unsigned long strlen(const char *s);

// strchr — needed by lfs.c for path parsing
static inline char *strchr(const char *s, int c) {
    while (*s) {
        if (*s == (char)c) return (char *)s;
        s++;
    }
    return (c == '\0') ? (char *)s : NULL;
}

static inline void *lfs_malloc(unsigned long size) {
    return malloc(size);
}

static inline void lfs_free(void *p) {
    free(p);
}

// --- Builtins ---
static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
    return (a > b) ? a : b;
}

static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
    return (a < b) ? a : b;
}

static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
    return a - (a % alignment);
}

static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) {
    return lfs_aligndown(a + alignment - 1, alignment);
}

static inline uint32_t lfs_npw2(uint32_t a) {
#if defined(__GNUC__) || defined(__clang__)
    return 32 - __builtin_clz(a - 1);
#else
    uint32_t r = 0, s;
    a -= 1;
    s = (a > 0xffff) << 4; a >>= s; r |= s;
    s = (a > 0xff  ) << 3; a >>= s; r |= s;
    s = (a > 0xf   ) << 2; a >>= s; r |= s;
    s = (a > 0x3   ) << 1; a >>= s; r |= s;
    return (r | (a >> 1)) + 1;
#endif
}

static inline uint32_t lfs_ctz(uint32_t a) {
#if defined(__GNUC__) || defined(__clang__)
    return __builtin_ctz(a);
#else
    return lfs_npw2((a & -a) + 1) - 1;
#endif
}

static inline uint32_t lfs_popc(uint32_t a) {
#if defined(__GNUC__) || defined(__clang__)
    return __builtin_popcount(a);
#else
    a = a - ((a >> 1) & 0x55555555);
    a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
    return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
#endif
}

static inline int lfs_scmp(uint32_t a, uint32_t b) {
    return (int)(unsigned)(a - b);
}

// --- Endianness (RISC-V / ARM64 / x86_64 are all little-endian) ---
static inline uint32_t lfs_fromle32(uint32_t a) { return a; }
static inline uint32_t lfs_tole32(uint32_t a)   { return a; }

static inline uint32_t lfs_frombe32(uint32_t a) {
    return __builtin_bswap32(a);
}
static inline uint32_t lfs_tobe32(uint32_t a) {
    return __builtin_bswap32(a);
}

// --- CRC-32 (implementation in lfs.c) ---
uint32_t lfs_crc(uint32_t crc, const void *buffer, unsigned long size);

#ifdef __cplusplus
}
#endif

#endif // LFS_RUMPK_H
