//! Module defining all known symbols required by the rest of rust-analyzer.
#![allow(non_upper_case_globals)]

use std::{
    hash::{BuildHasher, BuildHasherDefault},
    ptr::NonNull,
};

use arrayvec::ArrayString;
use dashmap::{DashMap, SharedValue};
use rustc_hash::FxHasher;

use crate::{Symbol, symbol::TaggedArcPtr};

macro_rules! last {
    ( $($elems:literal,)+ ) => {
        *[ $($elems,)* ].last().unwrap()
    };
}

impl Integer {
    #[inline]
    pub fn as_uint(sym: &Symbol) -> Option<usize> {
        if !sym.repr.is_arc() {
            let elem_ref = sym.repr.pointer();
            // SAFETY: The types have the same layout.
            let elem_ref = unsafe { std::mem::transmute::<NonNull<*const str>, &&str>(elem_ref) };
            Self::LIST.element_offset(elem_ref)
        } else {
            Self::as_uint_cold(sym)
        }
    }

    #[cold]
    fn as_uint_cold(sym: &Symbol) -> Option<usize> {
        sym.as_str().parse().ok()
    }
}

macro_rules! define_symbols {
    (
        @LISTS: $($list_type_name:ident = $list_prefix:literal + [ $($list_idx:literal,)+ ],)*
        @WITH_NAME: $($alias:ident = $value:literal,)*
        @PLAIN: $($name:ident,)*
    ) => {
        $(
            pub enum $list_type_name {}
            impl $list_type_name {
                // Ensure we covered all numbers.
                const LIST: &[&str; last!($($list_idx,)+) + 1] = {
                    static LIST: [&str; last!($($list_idx,)+) + 1] = [ $( concat!($list_prefix, $list_idx), )* ];
                    &LIST
                };

                #[cold]
                #[inline(never)]
                fn create(idx: usize) -> Symbol {
                    use std::fmt::Write;
                    const MAX_LEN: usize = $list_prefix.len() + u64::MAX.ilog10() as usize + 1;
                    let mut s = ArrayString::<MAX_LEN>::new();
                    s.push_str($list_prefix);
                    _ = write!(s, "{idx}");
                    Symbol::intern(&s)
                }

                #[inline]
                pub fn get(idx: usize) -> Symbol {
                    match Self::LIST.get(idx) {
                        Option::Some(s) => Symbol { repr: TaggedArcPtr::non_arc(s) },
                        Option::None => Self::create(idx),
                    }
                }
            }
        )*

        // The strings should be in `static`s so that symbol equality holds.
        $(
            pub const $name: Symbol = {
                static SYMBOL_STR: &str = stringify!($name);
                Symbol { repr: TaggedArcPtr::non_arc(&SYMBOL_STR) }
            };
        )*
        $(
            pub const $alias: Symbol = {
                static SYMBOL_STR: &str = $value;
                Symbol { repr: TaggedArcPtr::non_arc(&SYMBOL_STR) }
            };
        )*


        pub(super) fn prefill() -> DashMap<Symbol, (), BuildHasherDefault<FxHasher>> {
            let mut dashmap_ = <DashMap<Symbol, (), BuildHasherDefault<FxHasher>>>::with_hasher(BuildHasherDefault::default());

            let hasher_ = dashmap_.hasher().clone();
            let hash_one = |it_: &str| hasher_.hash_one(it_);
            {
                $(
                    for s in $list_type_name::LIST {
                        let hash_ = hash_one(s);
                        let shard_idx_ = dashmap_.determine_shard(hash_ as usize);
                        let symbol = Symbol { repr: TaggedArcPtr::non_arc(s) };
                        dashmap_.shards_mut()[shard_idx_].get_mut().insert(hash_, (symbol, SharedValue::new(())), |(x, _)| hash_one(x.as_str()));
                    }
                )*
                $(
                    let s = stringify!($name);
                    let hash_ = hash_one(s);
                    let shard_idx_ = dashmap_.determine_shard(hash_ as usize);
                    dashmap_.shards_mut()[shard_idx_].get_mut().insert(hash_, ($name, SharedValue::new(())), |(x, _)| hash_one(x.as_str()));
                )*
                $(
                    let s = $value;
                    let hash_ = hash_one(s);
                    let shard_idx_ = dashmap_.determine_shard(hash_ as usize);
                    dashmap_.shards_mut()[shard_idx_].get_mut().insert(hash_, ($alias, SharedValue::new(())), |(x, _)| hash_one(x.as_str()));
                )*
            }
            dashmap_
        }
    };
}
define_symbols! {
    @LISTS:
    Integer = "" + [
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
        26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
        51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
        76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
        101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125,
        126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,
        151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
        176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
        201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
        226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250,
        251, 252, 253, 254, 255,
    ],
    RaGeneratedName = "<ra@gennew>" + [
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
        26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
        51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
        76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
        101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125,
        126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,
        151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
        176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
        201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
        226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250,
        251, 252, 253, 254, 255,
    ],

    @WITH_NAME:

    dotdotdot = "...",
    __empty = "",
    unsafe_ = "unsafe",
    in_ = "in",
    super_ = "super",
    self_ = "self",
    Self_ = "Self",
    tick_static = "'static",
    tick_underscore = "'_",
    dollar_crate = "$crate",
    MISSING_NAME = "[missing name]",
    fn_ = "fn",
    crate_ = "crate",
    underscore = "_",
    true_ = "true",
    false_ = "false",
    let_ = "let",
    const_ = "const",
    kw_impl = "impl",
    proc_dash_macro = "proc-macro",
    aapcs_dash_unwind = "aapcs-unwind",
    avr_dash_interrupt = "avr-interrupt",
    avr_dash_non_dash_blocking_dash_interrupt = "avr-non-blocking-interrupt",
    C_dash_cmse_dash_nonsecure_dash_call = "C-cmse-nonsecure-call",
    C_dash_cmse_dash_nonsecure_dash_entry = "C-cmse-nonsecure-entry",
    C_dash_unwind = "C-unwind",
    cdecl_dash_unwind = "cdecl-unwind",
    fastcall_dash_unwind = "fastcall-unwind",
    msp430_dash_interrupt = "msp430-interrupt",
    ptx_dash_kernel = "ptx-kernel",
    riscv_dash_interrupt_dash_m = "riscv-interrupt-m",
    riscv_dash_interrupt_dash_s = "riscv-interrupt-s",
    rust_dash_call = "rust-call",
    rust_dash_cold = "rust-cold",
    rust_dash_intrinsic = "rust-intrinsic",
    stdcall_dash_unwind = "stdcall-unwind",
    system_dash_unwind = "system-unwind",
    sysv64_dash_unwind = "sysv64-unwind",
    thiscall_dash_unwind = "thiscall-unwind",
    vectorcall_dash_unwind = "vectorcall-unwind",
    win64_dash_unwind = "win64-unwind",
    x86_dash_interrupt = "x86-interrupt",
    rust_dash_preserve_dash_none = "preserve-none",
    _0_u8 = "0_u8",

    @PLAIN:
    __ra_fixup,
    aapcs,
    add_assign,
    add,
    alias,
    align_offset,
    align,
    all,
    alloc_layout,
    alloc,
    allow,
    any,
    as_str,
    asm,
    assert,
    async_iter,
    async_iterator,
    AsyncIterator,
    attr,
    attributes,
    begin_panic,
    bench,
    bitand_assign,
    bitand,
    bitor_assign,
    bitor,
    bitxor_assign,
    bitxor,
    bool,
    bootstrap,
    box_free,
    Box,
    boxed,
    branch,
    Break,
    c_void,
    C,
    call_mut,
    call_once,
    async_call_once,
    async_call_mut,
    async_call,
    call,
    cdecl,
    Center,
    cfg_accessible,
    cfg_attr,
    cfg_eval,
    cfg,
    cfg_select,
    char,
    clone,
    trivial_clone,
    Clone,
    coerce_unsized,
    column,
    completion,
    compile_error,
    concat_bytes,
    concat,
    const_format_args,
    const_panic_fmt,
    const_param_ty,
    Context,
    Continue,
    convert,
    copy,
    use_cloned,
    Copy,
    core_panic,
    core,
    coroutine_state,
    coroutine,
    coroutine_return,
    coroutine_yield,
    count,
    crate_type,
    CStr,
    debug_assertions,
    Debug,
    default,
    Default,
    deprecated,
    deref_mut,
    deref_pure,
    deref_target,
    deref,
    derive_const,
    derive,
    discriminant_kind,
    discriminant_type,
    dispatch_from_dyn,
    destruct,
    bikeshed_guaranteed_no_drop,
    div_assign,
    div,
    doc,
    drop_in_place,
    drop,
    dyn_metadata,
    efiapi,
    eh_catch_typeinfo,
    eh_personality,
    env,
    eq,
    Eq,
    Err,
    exchange_malloc,
    exhaustive_patterns,
    export_name,
    f128,
    f16,
    f32,
    f64,
    fastcall,
    feature,
    file,
    filter_map,
    fmt,
    fn_mut,
    fn_once_output,
    fn_once,
    async_fn_once,
    async_fn_once_output,
    async_fn_mut,
    async_fn,
    async_fn_kind_helper,
    async_fn_kind_upvars,
    call_ref_future,
    call_once_future,
    fn_ptr_addr,
    fn_ptr_trait,
    format_alignment,
    format_args_nl,
    format_args,
    format_argument,
    format_arguments,
    format_count,
    format_placeholder,
    format_unsafe_arg,
    format,
    freeze,
    from,
    From,
    FromStr,
    from_str,
    from_output,
    from_residual,
    from_usize,
    from_yeet,
    fundamental,
    future_trait,
    future,
    future_output,
    Future,
    ge,
    generic_associated_type_extended,
    get_context,
    global_allocator,
    global_asm,
    gt,
    Hash,
    hidden,
    html_root_url,
    i128,
    i16,
    i32,
    i64,
    i8,
    ignore,
    Implied,
    include_bytes,
    include_str,
    include,
    index_mut,
    index,
    Index,
    into,
    Into,
    into_future,
    into_iter,
    into_try_type,
    IntoFuture,
    IntoIter,
    IntoIterator,
    is_empty,
    Is,
    isize,
    Item,
    iter_mut,
    iter,
    Iterator,
    iterator,
    fused_iterator,
    keyword,
    lang,
    lang_items,
    le,
    Left,
    len,
    line,
    llvm_asm,
    local_inner_macros,
    log_syntax,
    lt,
    macro_export,
    macro_rules,
    macro_use,
    main,
    manually_drop,
    may_dangle,
    maybe_uninit,
    metadata_type,
    min_exhaustive_patterns,
    miri,
    missing,
    module_path,
    mul_assign,
    mul,
    must_use,
    naked_asm,
    ne,
    neg,
    Neg,
    new_binary,
    new_debug,
    new_display,
    new_lower_exp,
    new_lower_hex,
    new_octal,
    new_pointer,
    new_unchecked,
    new_upper_exp,
    new_upper_hex,
    new_v1_formatted,
    new,
    next,
    no_core,
    no_mangle,
    no_std,
    non_exhaustive,
    none,
    None,
    not,
    Not,
    notable_trait,
    Ok,
    opaque,
    ops,
    option_env,
    option,
    Option,
    Ord,
    Ordering,
    Output,
    CallRefFuture,
    CallOnceFuture,
    owned_box,
    packed,
    panic_2015,
    panic_2021,
    panic_bounds_check,
    panic_cannot_unwind,
    panic_display,
    panic_fmt,
    panic_impl,
    panic_info,
    panic_location,
    panic_misaligned_pointer_dereference,
    panic_nounwind,
    panic_null_pointer_dereference,
    panic,
    Param,
    parse,
    partial_ord,
    PartialEq,
    PartialOrd,
    CoercePointee,
    path,
    pattern_type,
    Pending,
    phantom_data,
    pieces,
    pin,
    pointee_trait,
    pointer_like,
    poll,
    Poll,
    prelude_import,
    prelude,
    proc_macro_attribute,
    proc_macro_derive,
    proc_macro,
    quote,
    range_inclusive_new,
    Range,
    RangeFrom,
    RangeFull,
    RangeInclusive,
    RangeTo,
    RangeToInclusive,
    Ready,
    receiver,
    receiver_target,
    recursion_limit,
    register_attr,
    register_tool,
    rem_assign,
    rem,
    repr,
    result,
    Result,
    ResumeTy,
    Right,
    rust_2015,
    rust_2018,
    rust_2021,
    rust_2024,
    rust_analyzer,
    Rust,
    rustc_allocator_zeroed,
    rustc_allocator,
    rustc_allow_incoherent_impl,
    rustc_builtin_macro,
    rustc_coherence_is_core,
    rustc_coinductive,
    rustc_const_panic_str,
    rustc_deallocator,
    rustc_deprecated_safe_2024,
    rustc_has_incoherent_inherent_impls,
    rustc_intrinsic_must_be_overridden,
    rustc_intrinsic,
    rustc_layout_scalar_valid_range_end,
    rustc_layout_scalar_valid_range_start,
    rustc_legacy_const_generics,
    rustc_macro_transparency,
    rustc_paren_sugar,
    rustc_reallocator,
    rustc_reservation_impl,
    rustc_safe_intrinsic,
    rustc_skip_array_during_method_dispatch,
    rustc_skip_during_method_dispatch,
    rustc_force_inline,
    shl_assign,
    shl,
    shr_assign,
    shr,
    simd,
    sized,
    meta_sized,
    pointee_sized,
    skip,
    slice_len_fn,
    Some,
    start,
    std_panic,
    std,
    stdcall,
    str,
    string,
    String,
    stringify,
    structural_peq,
    structural_teq,
    sub_assign,
    sub,
    sync,
    system,
    sysv64,
    Target,
    target_feature,
    enable,
    termination,
    test_case,
    test,
    then,
    thiscall,
    to_string,
    trace_macros,
    transmute_opts,
    transmute_trait,
    transparent,
    try_into,
    Try,
    TryFrom,
    try_from,
    tuple_trait,
    u128,
    u16,
    u32,
    u64,
    u8,
    unadjusted,
    unknown,
    Unknown,
    unpin,
    unreachable_2015,
    unreachable_2021,
    unreachable,
    unsafe_cell,
    unsafe_pinned,
    unsize,
    unstable,
    usize,
    v1,
    va_list,
    vectorcall,
    wasm,
    win64,
    args,
    array,
    boxed_slice,
    completions,
    ignore_flyimport,
    ignore_flyimport_methods,
    ignore_methods,
    position,
    flags,
    precision,
    width,
    never_type_fallback,
    specialization,
    min_specialization,
    arbitrary_self_types,
    arbitrary_self_types_pointers,
    supertrait_item_shadowing,
    new_range,
    range,
    RangeCopy,
    RangeFromCopy,
    RangeInclusiveCopy,
    RangeToInclusiveCopy,
    hash,
    partial_cmp,
    cmp,
    CoerceUnsized,
    DispatchFromDyn,
    define_opaque,
    marker,
    abi_unadjusted,
    allocator_internals,
    allow_internal_unsafe,
    allow_internal_unstable,
    cfg_emscripten_wasm_eh,
    cfg_target_has_reliable_f16_f128,
    compiler_builtins,
    custom_mir,
    eii_internals,
    field_representing_type_raw,
    intrinsics,
    link_cfg,
    more_maybe_bounds,
    negative_bounds,
    pattern_complexity_limit,
    profiler_runtime,
    rustc_attrs,
    staged_api,
    test_unstable_lint,
    builtin_syntax,
    link_llvm_intrinsics,
    needs_panic_runtime,
    panic_runtime,
    pattern_types,
    rustdoc_internals,
    contracts_internals,
    freeze_impls,
    unsized_fn_params,
    field,
    field_base,
    field_type,
    ref_pat_eat_one_layer_2024,
    ref_pat_eat_one_layer_2024_structural,
    deref_patterns,
    mut_ref,
    type_changing_struct_update,
    RangeMin,
    RangeMax,
    RangeSub,
}
