#pragma once

/*
 * This file contains macros related to machine dependent
 * things like alignment and type juggling
*/

// ========================================================== //
//                           ENDIANNESS                       //
// ========================================================== //

// Used by GCC/Clang/WASM/ESP32/RP2040 and most compilers
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__)
    #define SPIDER_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
    #define SPIDER_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)

// Fallbacks (For older/constrained compilers)
#else
    #if defined(__AVR_ATmega328P__) || defined(__AVR__) // Arduino Uno/ATmega
        #define SPIDER_LITTLE_ENDIAN 1
        #define SPIDER_BIG_ENDIAN    0
    #elif defined(__wasm__) || defined(__wasm32__)      // WebAssembly
        #define SPIDER_LITTLE_ENDIAN 1
        #define SPIDER_BIG_ENDIAN    0
    #elif defined(__arm__) || defined(__thumb__)        // RP2040, STM32, etc.
        #if defined(__ARMEB__)
            #define SPIDER_LITTLE_ENDIAN 0
            #define SPIDER_BIG_ENDIAN    1
        #else
            #define SPIDER_LITTLE_ENDIAN 1
            #define SPIDER_BIG_ENDIAN    0
        #endif
    #elif defined(__xtensa__) || defined(__ESP32__)     // ESP32
        #define SPIDER_LITTLE_ENDIAN 1
        #define SPIDER_BIG_ENDIAN    0
    // Likely will never use this clause
    // ...but keeps compatibility with the one (1)
    // guy who uses MSVC.
    #elif defined(_WIN32) || defined(_M_IX86) || defined(_M_X64)
        #define SPIDER_LITTLE_ENDIAN 1
        #define SPIDER_BIG_ENDIAN    0
    #else
        #error "[Spider Machine] Unsupported or unknown architecture endianness!"
    #endif
#endif

// Safety checks
#if !defined(SPIDER_LITTLE_ENDIAN) || !defined(SPIDER_BIG_ENDIAN)
    #error "[Spider Machine] Missed at least one little/big endian macros"
#endif
#if SPIDER_LITTLE_ENDIAN == 1 && SPIDER_BIG_ENDIAN == 1
    #warning "[Spider Machine] Mixed endian machine detected, unsupported! Be cautious adventurer!"
#endif


// ========================================================== //
//                           PACKING                          //
//                        (not used now)                      //
// ========================================================== //

// Find out what compiler the user is using
#if defined(__clang__)
    #define SPIDER_COMPILER_CLANG
    #define SPIDER_COMPILER_GCC_LIKE
#elif defined(__GNUC__)
    #define SPIDER_COMPILER_GCC
    #define SPIDER_COMPILER_GCC_LIKE
#elif defined(_MSC_VER)
    #define SPIDER_COMPILER_MSVC
#else
    #define SPIDER_COMPILER_UNKNOWN
#endif

// Macros...
#if defined(SPIDER_COMPILER_GCC_LIKE)
    #define SPIDER_PACK_BEGIN
    #define SPIDER_PACK_END
    #define SPIDER_PACK_STRUCT __attribute__((packed))

#elif defined(SPIDER_COMPILER_MSVC)
    #define SPIDER_BEGIN_PACKED __pragma(pack(push, 1))
    #define SPIDER_END_PACKED   __pragma(pack(pop))
    #define SPIDER_PACKED_STRUCT(decl) SPIDER_BEGIN_PACKED decl SPIDER_END_PACKED

#else
    #define SPIDER_ATTRIBUTE_PACKED
    #define SPIDER_BEGIN_PACKED
    #define SPIDER_END_PACKED
    #define SPIDER_PACKED_STRUCT(decl) decl
    #warning "[Spider Machine] Compiler packing not supported. Memory layout may be unstable!"
#endif

namespace spider {}
