# Fundamental C++ types.
#
# Author: Malte J. Ziebarth (malte.ziebarth@tum.de)
#
# Copyright (C) 2025-2026 Technische Universität München
#
# Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
# the European Commission - subsequent versions of the EUPL (the "Licence");
# You may not use this work except in compliance with the Licence.
# You may obtain a copy of the Licence at:
#
# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the Licence is distributed on an "AS IS" basis,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the Licence for the specific language governing permissions and
# limitations under the Licence.
#
# SPDX-FileCopyrightText: 2025-2026 Technical University of Munich
# SPDX-License-Identifier: EUPL-1.2
# SPDX-FileContributor: Malte J. Ziebarth <malte.ziebarth@tum.de>

from typing import Literal, get_args, Any, overload

FundamentalBaseType = Literal[
    "signed char",
    "unsigned char",
    "char",
    "short",
    "unsigned short",
    "int",
    "unsigned int",
    "long",
    "unsigned long",
    "long long",
    "unsigned long long",
    "uint8_t",
    "int8_t",
    "uint16_t",
    "int16_t",
    "uint32_t",
    "int32_t",
    "uint64_t",
    "int64_t",
    "size_t",
    "ssize_t",
    "void",
    "double",
    "float",
    "long double"
]


CTypeBaseType = Literal[
    "c_int8",
    "c_uint8",
    "c_char",
    "c_short",
    "c_ushort",
    "c_int",
    "c_uint",
    "c_long",
    "c_ulong",
    "c_longlong",
    "c_ulonglong",
    "c_uint8",
    "c_int8",
    "c_uint16",
    "c_int16",
    "c_uint32",
    "c_int32",
    "c_uint64",
    "c_int64",
    "c_size_t",
    "c_ssize_t",
    "c_double",
    "c_float",
    "c_longdouble",
    "c_char_p"
]


PythonBaseType = Literal[
    "str",
    "float",
    "int",
    "bytes"
]

FLOAT_TYPES: set[CTypeBaseType] = set(
    ("c_double", "c_float", "c_longdouble")
)

INT_TYPES: set[CTypeBaseType] = set(
    (
        "c_int8",
        "c_uint8",
        "c_char",
        "c_short",
        "c_ushort",
        "c_int",
        "c_uint",
        "c_long",
        "c_ulong",
        "c_longlong",
        "c_ulonglong",
        "c_uint8",
        "c_int8",
        "c_uint16",
        "c_int16",
        "c_uint32",
        "c_int32",
        "c_uint64",
        "c_int64",
        "c_size_t",
        "c_ssize_t"
    )
)

CTYPE_BASE_TYPES: set[CTypeBaseType] = set(get_args(CTypeBaseType))


FUNDAMENTAL_BASE_TYPES: set[FundamentalBaseType] \
    = set(get_args(FundamentalBaseType))

FBP_TO_FBP: dict[str,FundamentalBaseType] \
    = {s : s for s in get_args(FundamentalBaseType)}


PYTHON_BASE_TYPES: set[PythonBaseType] = set(get_args(PythonBaseType))



#
# Checks for type:
#
@overload
def try_fundamental_base_type(t: FundamentalBaseType) -> FundamentalBaseType:
    ...

@overload
def try_fundamental_base_type(t: Any) -> FundamentalBaseType | None:
    ...

def try_fundamental_base_type(t: Any) -> FundamentalBaseType | None:
    """
    Returns, if it is so, `t` as a FundamentalBaseType.
    """
    if isinstance(t, str):
        return FBP_TO_FBP.get(t, None)
    return None


def is_fundamental_base_type(t: Any) -> bool:
    if not isinstance(t, str):
        return False
    return t in FUNDAMENTAL_BASE_TYPES



def assert_fundamental_base_type(t: Any) -> FundamentalBaseType:
    if not isinstance(t, str) or (fbp := FBP_TO_FBP.get(t)) is None:
        raise TypeError(
            f"Value '{t}' is not a fundamental base type."
        )
    return fbp
