Documentation
/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--

SJ

Copyright (C) 2019-2025  Anonymous

There are several releases over multiple years,
they are listed as ranges, such as: "2019-2025".

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/

use {
    core::{
        borrow::Borrow,
        hash::Hash,
    },
    alloc::boxed::Box,
    crate::{Json, MapKind, ObjectKey},
};

/// # B-tree map
pub type BTreeMap = alloc::collections::BTreeMap<ObjectKey, Json>;

/// # Hash map
#[cfg(feature="std")]
#[doc(cfg(feature="std"))]
pub type HashMap = std::collections::HashMap<ObjectKey, Json>;

/// # Map
#[derive(Debug, Clone)]
pub enum Map {

    /// # BTreeMap
    BTreeMap(BTreeMap),

    /// # HashMap
    #[cfg(feature="std")]
    #[doc(cfg(feature="std"))]
    HashMap(HashMap),

}

impl Map {

    /// # Makes new instance
    pub fn new(kind: MapKind) -> Self {
        match kind {
            MapKind::BTreeMap => Self::BTreeMap(BTreeMap::new()),
            #[cfg(feature="std")]
            MapKind::HashMap => Self::HashMap(HashMap::new()),
        }
    }

    /// # Makes new instance
    pub fn with_capacity(kind: MapKind, capacity: usize) -> Self {
        match kind {
            MapKind::BTreeMap => {
                let _ = capacity;
                Self::BTreeMap(BTreeMap::new())
            },
            #[cfg(feature="std")]
            MapKind::HashMap => Self::HashMap(HashMap::with_capacity(capacity)),
        }
    }

    /// # Checks if the map is empty
    pub fn is_empty(&self) -> bool {
        match self {
            Self::BTreeMap(map) => map.is_empty(),
            #[cfg(feature="std")]
            Self::HashMap(map) => map.is_empty(),
        }
    }

    /// # Length
    pub fn len(&self) -> usize {
        match self {
            Self::BTreeMap(map) => map.len(),
            #[cfg(feature="std")]
            Self::HashMap(map) => map.len(),
        }
    }

    /// # Inserts new item
    ///
    /// Result: last value of the key, if existed.
    pub fn insert<K, V>(&mut self, key: K, value: V) -> Option<Json> where K: Into<ObjectKey>, V: Into<Json> {
        let key = key.into();
        let value = value.into();
        match self {
            Self::BTreeMap(map) => map.insert(key, value),
            #[cfg(feature="std")]
            Self::HashMap(map) => map.insert(key, value),
        }
    }

    /// # Gets an item
    pub (crate) fn get<K>(&self, key: &K) -> Option<&Json> where ObjectKey: Borrow<K>, K: Ord + Hash + Eq + ?Sized {
        match self {
            Self::BTreeMap(map) => map.get(key),
            #[cfg(feature="std")]
            Self::HashMap(map) => map.get(key),
        }
    }

    /// # Gets a mutbale item
    pub (crate) fn get_mut<K>(&mut self, key: &K) -> Option<&mut Json> where ObjectKey: Borrow<K>, K: Ord + Hash + Eq + ?Sized {
        match self {
            Self::BTreeMap(map) => map.get_mut(key),
            #[cfg(feature="std")]
            Self::HashMap(map) => map.get_mut(key),
        }
    }

    /// # Removes an item
    pub (crate) fn remove<K>(&mut self, key: &K) -> Option<Json> where ObjectKey: Borrow<K>, K: Ord + Hash + Eq + ?Sized {
        match self {
            Self::BTreeMap(map) => map.remove(key),
            #[cfg(feature="std")]
            Self::HashMap(map) => map.remove(key),
        }
    }

    /// # Makes new iterator
    pub fn iter(&self) -> Box<dyn Iterator<Item=(&ObjectKey, &Json)> + '_> {
        match self {
            Self::BTreeMap(map) => Box::new(map.iter()),
            #[cfg(feature="std")]
            Self::HashMap(map) => Box::new(map.iter()),
        }
    }

    /// # Converts to an iterator
    pub fn into_iter(self) -> Box<dyn Iterator<Item=(ObjectKey, Json)>> {
        match self {
            Self::BTreeMap(map) => Box::new(map.into_iter()),
            #[cfg(feature="std")]
            Self::HashMap(map) => Box::new(map.into_iter()),
        }
    }

}

impl From<BTreeMap> for Map {

    fn from(map: BTreeMap) -> Self {
        Self::BTreeMap(map)
    }

}

#[cfg(feature="std")]
#[doc(cfg(feature="std"))]
impl From<HashMap> for Map {

    fn from(map: HashMap) -> Self {
        Self::HashMap(map)
    }

}

impl From<Map> for BTreeMap {

    fn from(map: Map) -> Self {
        match map {
            Map::BTreeMap(map) => map,
            #[cfg(feature="std")]
            Map::HashMap(map) => map.into_iter().collect(),
        }
    }

}

#[cfg(feature="std")]
#[doc(cfg(feature="std"))]
impl From<Map> for HashMap {

    fn from(map: Map) -> Self {
        match map {
            Map::BTreeMap(map) => map.into_iter().collect(),
            Map::HashMap(map) => map,
        }
    }

}