dope-manifold 0.28.0

Owned application and service composition for dope
Documentation
use o3::depot::{capacity, queue::round::set};

use crate::service::{
    self, pool,
    pool::members::{Record, Records, queues},
};

enum Vacant<'a, 'h, I, A> {
    Free(set::Vacant<'a, Record<I, A>, pool::Member, { u32::MAX }, false, capacity::Domain<'h>>),
    Reuse(set::Reuse<'a, Record<I, A>, pool::Member, { u32::MAX }, false, capacity::Domain<'h>>),
}

enum Entry<'a, 'h, I, A> {
    Keep {
        entry: set::Occupied<
            'a,
            Record<I, A>,
            pool::Member,
            { u32::MAX },
            false,
            capacity::Domain<'h>,
        >,
        value: service::Endpoint<I, A>,
    },
    New {
        entry: Vacant<'a, 'h, I, A>,
        value: service::Endpoint<I, A>,
    },
}

pub(super) fn try_apply<'h, I: Eq, A, const N: usize>(
    records: &mut Records<'h, I, A>,
    snapshot: service::Snapshot<service::Endpoint<I, A>, N>,
    preserve: bool,
    queue: &mut queues::Queue<'h, '_>,
) -> Result<([Option<pool::MemberKey<'h>>; N], usize), service::Reconcile> {
    let (entries, retained) = {
        let mut keep = [const { None }; N];
        let mut spare: [Option<Vacant<'_, 'h, I, A>>; N] = [const { None }; N];
        let mut space = spare.iter_mut();
        let mut retained = 0;
        for entry in records.entries() {
            let free = match entry {
                set::Entry::Vacant(entry) => Vacant::Free(entry),
                set::Entry::Occupied(entry) => {
                    if entry.get().is_desired()
                        && let Some((_, target)) = snapshot
                            .endpoints()
                            .iter()
                            .zip(keep.iter_mut())
                            .find(|pair| &entry.get().id == pair.0.id())
                    {
                        retained += usize::from(target.replace(entry).is_none());
                        continue;
                    }
                    if preserve && entry.get().health.owners != 0 {
                        continue;
                    }
                    match set::Reuse::try_from(entry) {
                        Ok(entry) => Vacant::Reuse(entry),
                        Err(_) => continue,
                    }
                }
            };
            if let Some(target) = space.next() {
                *target = Some(free);
            }
        }
        let limit = retained + (N - space.len());
        let actual = snapshot.endpoints().len();
        let mut spare = spare.into_iter().flatten();
        let mut entries = [const { None }; N];
        for (target, (value, prior)) in entries.iter_mut().zip(snapshot.into_iter().zip(keep)) {
            *target = Some(match prior {
                Some(entry) => Entry::Keep { entry, value },
                None => Entry::New {
                    entry: spare
                        .next()
                        .ok_or(service::Reconcile::Capacity { actual, limit })?,
                    value,
                },
            });
        }
        (entries, retained)
    };
    Ok((
        entries.map(|entry| entry.map(|entry| entry.commit(queue))),
        retained,
    ))
}

impl<'h, I, A> Entry<'_, 'h, I, A> {
    pub(super) fn commit(self, queue: &mut queues::Queue<'h, '_>) -> pool::MemberKey<'h> {
        match self {
            Entry::Keep { mut entry, value } => {
                let key = pool::MemberKey(entry.key());
                let addr = value.into_parts().1;
                entry.get_mut().addr = addr;
                queues::Queue::reorder(entry);
                key
            }
            Entry::New { entry, value } => {
                let (id, addr) = value.into_parts();
                entry.insert(Record::new(id, addr), queue)
            }
        }
    }
}

impl<'h, I, A> Vacant<'_, 'h, I, A> {
    fn insert(self, value: Record<I, A>, queue: &mut queues::Queue<'h, '_>) -> pool::MemberKey<'h> {
        match self {
            Self::Free(entry) => {
                let entry = entry.insert(value);
                let member = pool::MemberKey(entry.key());
                entry.insert();
                member
            }
            Self::Reuse(entry) => {
                queue.retire(entry.key());
                let entry = entry.replace(value).0;
                let member = pool::MemberKey(entry.key());
                match entry.state() {
                    set::State::Idle(entry) => {
                        entry.insert();
                    }
                    set::State::Ready(entry) => {
                        entry.requeue();
                    }
                }
                member
            }
        }
    }
}