fixed-map 0.9.5

A fixed map where storage layout is calculated by a procedural macro.
Documentation
use super::{NoneBucket, OptionBucket, SomeBucket};

struct OccupiedEntry<'a, T> {
    inner: SomeBucket<'a, T>,
}

struct VacantEntry<'a, T> {
    inner: NoneBucket<'a, T>,
}

enum Entry<'a, T> {
    Vacant(VacantEntry<'a, T>),
    Occupied(OccupiedEntry<'a, T>),
}

impl<'a, T> VacantEntry<'a, T> {
    fn insert(self, value: T) -> &'a mut T {
        self.inner.insert(value)
    }
}

impl<'a, T> OccupiedEntry<'a, T> {
    fn get(&self) -> &T {
        self.inner.as_ref()
    }

    fn get_mut(&mut self) -> &mut T {
        self.inner.as_mut()
    }

    fn into_mut(self) -> &'a mut T {
        self.inner.into_mut()
    }

    fn insert(&mut self, value: T) -> T {
        self.inner.replace(value)
    }

    fn remove(self) -> T {
        self.inner.take()
    }
}

impl<'a, T> Entry<'a, T> {
    fn or_insert(self, default: T) -> &'a mut T {
        match self {
            Entry::Occupied(entry) => entry.into_mut(),
            Entry::Vacant(entry) => entry.insert(default),
        }
    }

    fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T {
        match self {
            Entry::Occupied(entry) => entry.into_mut(),
            Entry::Vacant(entry) => entry.insert(default()),
        }
    }

    fn and_modify<F: FnOnce(&mut T)>(self, f: F) -> Self {
        match self {
            Entry::Occupied(mut entry) => {
                f(entry.get_mut());
                Entry::Occupied(entry)
            }
            Entry::Vacant(entry) => Entry::Vacant(entry),
        }
    }

    fn or_default(self) -> &'a mut T
    where
        T: Default,
    {
        match self {
            Entry::Occupied(entry) => entry.into_mut(),
            Entry::Vacant(entry) => entry.insert(Default::default()),
        }
    }
}

trait OptionEntry {
    type Entry<'this>
    where
        Self: 'this;

    fn entry(&mut self) -> Self::Entry<'_>;
}

impl<T> OptionEntry for Option<T> {
    type Entry<'this> = Entry<'this, T> where T: 'this;

    fn entry(&mut self) -> Self::Entry<'_> {
        match OptionBucket::new(self) {
            OptionBucket::Some(inner) => Entry::Occupied(OccupiedEntry { inner }),
            OptionBucket::None(inner) => Entry::Vacant(VacantEntry { inner }),
        }
    }
}

#[test]
fn test() {
    let mut even: Option<i32> = None;

    for n in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] {
        if n % 2 == 0 {
            even.entry().and_modify(|x| *x += 1).or_insert(1);
        }
    }

    match even.entry() {
        Entry::Occupied(mut entry) => {
            assert_eq!(entry.get(), &5);
            assert_eq!(entry.insert(-3), 5);
            assert_eq!(entry.remove(), -3);
        }
        Entry::Vacant(_) => unreachable!(),
    }
    assert!(even.is_none());

    let day_hours = 24;

    let mut x = None;
    x.entry().or_insert_with(|| day_hours * 60 * 60 * 1000);
    assert_eq!(x, Some(86_400_000));

    let mut y: Option<u32> = None;
    y.entry().or_default();
    assert_eq!(y, Some(0));
}