serde_describe 0.2.5

Make non-self-describing serde formats behave like they're self-describing.
Documentation
use indexmap::IndexSet;
use serde::{Deserialize, Serialize};
use std::{borrow::Borrow, hash::Hash, marker::PhantomData};

use crate::indices::{IndexIsEmpty, IsEmpty};

#[derive(Clone)]
pub(crate) struct Pool<ValueT, ValueIndexT> {
    inner: IndexSet<ValueT>,
    _dummy: PhantomData<ValueIndexT>,
}

impl<ValueT, ValueIndexT> Default for Pool<ValueT, ValueIndexT> {
    #[inline]
    fn default() -> Self {
        Self {
            inner: Default::default(),
            _dummy: PhantomData,
        }
    }
}

impl<ValueT, ValueIndexT> Pool<ValueT, ValueIndexT>
where
    ValueT: Hash + Eq + IsEmpty,
    ValueIndexT: TryFrom<usize> + IndexIsEmpty,
{
    pub(crate) fn intern(&mut self, value: ValueT) -> Result<ValueIndexT, ValueIndexT::Error> {
        if value.is_empty() {
            Ok(ValueIndexT::EMPTY)
        } else {
            ValueIndexT::try_from(self.inner.insert_full(value).0 + 1)
        }
    }

    pub(crate) fn intern_from<FromT>(
        &mut self,
        value: FromT,
    ) -> Result<ValueIndexT, ValueIndexT::Error>
    where
        ValueT: From<FromT>,
        FromT: IsEmpty,
    {
        if value.is_empty() {
            Ok(ValueIndexT::EMPTY)
        } else {
            ValueIndexT::try_from(self.inner.insert_full(value.into()).0 + 1)
        }
    }
}

#[derive(Debug, Clone)]
pub(crate) struct NonEmptyPool<ValueT, ValueIndexT> {
    inner: IndexSet<ValueT>,
    _dummy: PhantomData<ValueIndexT>,
}

impl<ValueT, ValueIndexT> Default for NonEmptyPool<ValueT, ValueIndexT> {
    #[inline]
    fn default() -> Self {
        Self {
            inner: Default::default(),
            _dummy: PhantomData,
        }
    }
}

impl<ValueT, ValueIndexT> NonEmptyPool<ValueT, ValueIndexT>
where
    ValueT: Hash + Eq,
    ValueIndexT: TryFrom<usize>,
{
    pub(crate) fn intern(&mut self, value: ValueT) -> Result<ValueIndexT, ValueIndexT::Error> {
        ValueIndexT::try_from(self.inner.insert_full(value).0)
    }

    pub(crate) fn intern_from<FromT>(
        &mut self,
        value: FromT,
    ) -> Result<ValueIndexT, ValueIndexT::Error>
    where
        ValueT: From<FromT>,
    {
        ValueIndexT::try_from(self.inner.insert_full(value.into()).0)
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub(crate) struct ReadonlyPool<ValueT, ValueIndexT> {
    values: Box<[ValueT]>,

    #[serde(skip)]
    _dummy: PhantomData<ValueIndexT>,
}

impl<ValueT, ValueIndexT> ReadonlyPool<ValueT, ValueIndexT>
where
    ValueT: IsEmpty,
    ValueIndexT: IsEmpty + Into<usize>,
{
    #[inline]
    pub(crate) fn get(&self, index: ValueIndexT) -> Option<&ValueT::Borrowed> {
        if index.is_empty() {
            Some(ValueT::BORROWED_EMPTY)
        } else {
            self.values.get(index.into() - 1).map(Borrow::borrow)
        }
    }
}

impl<FromT, IntoT, ValueIndexT> From<Pool<FromT, ValueIndexT>> for ReadonlyPool<IntoT, ValueIndexT>
where
    FromT: Into<IntoT>,
{
    #[inline]
    fn from(value: Pool<FromT, ValueIndexT>) -> Self {
        Self {
            values: value.inner.into_iter().map(Into::into).collect(),
            _dummy: PhantomData,
        }
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub(crate) struct ReadonlyNonEmptyPool<ValueT, ValueIndexT> {
    values: Box<[ValueT]>,

    #[serde(skip)]
    _dummy: PhantomData<ValueIndexT>,
}

impl<ValueT, ValueIndexT> ReadonlyNonEmptyPool<ValueT, ValueIndexT>
where
    ValueIndexT: Into<usize>,
{
    #[inline]
    pub(crate) fn get(&self, index: ValueIndexT) -> Option<&ValueT> {
        self.values.get(index.into())
    }
}

impl<FromT, IntoT, ValueIndexT> From<NonEmptyPool<FromT, ValueIndexT>>
    for ReadonlyNonEmptyPool<IntoT, ValueIndexT>
where
    FromT: Into<IntoT>,
{
    #[inline]
    fn from(value: NonEmptyPool<FromT, ValueIndexT>) -> Self {
        Self {
            values: value.inner.into_iter().map(Into::into).collect(),
            _dummy: PhantomData,
        }
    }
}