cranpose-core 0.0.60

Core runtime for a Jetpack Compose inspired UI framework in Rust
Documentation
#[cfg(any(test, debug_assertions))]
use super::AnchorState;
use super::{ActiveGroupId, ChildCursor, DirectChildRange, GroupKey, SlotTable, SubtreeRange};
use crate::{AnchorId, ScopeId};

pub(super) struct GroupRecord {
    pub(super) key: GroupKey,
    pub(super) parent_anchor: AnchorId,
    pub(super) depth: u32,
    pub(super) subtree_len: u32,
    pub(super) payload_start: u32,
    pub(super) payload_len: u32,
    pub(super) node_start: u32,
    pub(super) node_len: u32,
    pub(super) subtree_node_count: u32,
    pub(super) generation: u32,
    pub(super) anchor: AnchorId,
    pub(super) scope_id: Option<ScopeId>,
}

#[derive(Clone, Copy)]
pub(in crate::slot) struct GroupSiblingRecord {
    pub(in crate::slot) key: GroupKey,
    pub(in crate::slot) parent_anchor: AnchorId,
    pub(in crate::slot) anchor: AnchorId,
    pub(in crate::slot) subtree_len: usize,
}

impl SlotTable {
    pub(in crate::slot) fn group_count(&self) -> usize {
        self.groups.len()
    }

    pub(in crate::slot) fn active_group_index(&self, anchor: AnchorId) -> Option<usize> {
        self.anchors.active_index(anchor)
    }

    #[cfg(any(test, debug_assertions))]
    pub(in crate::slot) fn group_anchor_state(&self, anchor: AnchorId) -> Option<AnchorState> {
        self.anchors.state(anchor)
    }

    pub(in crate::slot) fn current_group_index(&self, anchor: AnchorId) -> usize {
        self.anchors
            .active_index(anchor)
            .expect("group anchor should resolve to an active group")
    }

    pub(in crate::slot) fn current_group(&self, anchor: AnchorId) -> &GroupRecord {
        &self.groups[self.current_group_index(anchor)]
    }

    #[cfg(test)]
    #[inline(always)]
    pub(in crate::slot) fn group_anchor_at_index(&self, group_index: usize) -> AnchorId {
        self.groups[group_index].anchor
    }

    #[cfg(any(test, debug_assertions))]
    pub(in crate::slot) fn group_parent_anchor_at_index(
        &self,
        group_index: usize,
    ) -> Option<AnchorId> {
        self.groups
            .get(group_index)
            .map(|group| group.parent_anchor)
    }

    #[inline(always)]
    pub(in crate::slot) fn group_scope_id_at_index(&self, group_index: usize) -> Option<ScopeId> {
        self.groups[group_index].scope_id
    }

    #[inline(always)]
    pub(in crate::slot) fn group_subtree_len_at_index(&self, group_index: usize) -> usize {
        self.groups[group_index].subtree_len as usize
    }

    #[inline(always)]
    pub(in crate::slot) fn group_subtree_end_at_index(&self, group_index: usize) -> usize {
        group_index + self.group_subtree_len_at_index(group_index)
    }

    #[inline(always)]
    pub(in crate::slot) fn group_subtree_range_at_index(&self, group_index: usize) -> SubtreeRange {
        SubtreeRange::from_root_len(group_index, self.group_subtree_len_at_index(group_index))
    }

    pub(in crate::slot) fn group_subtree_node_count_at_index(&self, group_index: usize) -> usize {
        self.groups[group_index].subtree_node_count as usize
    }

    #[cfg(any(test, debug_assertions))]
    pub(in crate::slot) fn group_depth_at_index(&self, group_index: usize) -> usize {
        self.groups[group_index].depth as usize
    }

    #[inline(always)]
    pub(in crate::slot) fn group_sibling_record_at_index(
        &self,
        group_index: usize,
    ) -> GroupSiblingRecord {
        let group = &self.groups[group_index];
        GroupSiblingRecord {
            key: group.key,
            parent_anchor: group.parent_anchor,
            anchor: group.anchor,
            subtree_len: group.subtree_len as usize,
        }
    }

    #[inline(always)]
    pub(in crate::slot) fn group_sibling_record_at_index_checked(
        &self,
        group_index: usize,
    ) -> Option<GroupSiblingRecord> {
        self.groups
            .get(group_index)
            .map(|group| GroupSiblingRecord {
                key: group.key,
                parent_anchor: group.parent_anchor,
                anchor: group.anchor,
                subtree_len: group.subtree_len as usize,
            })
    }

    pub(in crate::slot) fn checked_active_group_index(&self, group: ActiveGroupId) -> usize {
        let group_index = group.index();
        let record = self
            .groups
            .get(group_index)
            .expect("active group handle index missing");
        assert_eq!(
            record.generation,
            group.generation(),
            "active group handle generation mismatch"
        );
        group_index
    }

    pub(in crate::slot) fn active_group_id_at_index(&self, group_index: usize) -> ActiveGroupId {
        let record = self.groups.get(group_index).expect("group index missing");
        ActiveGroupId::new(group_index, record.generation)
    }

    pub(in crate::slot) fn active_group_anchor(&self, group: ActiveGroupId) -> AnchorId {
        let group_index = self.checked_active_group_index(group);
        self.groups[group_index].anchor
    }

    #[inline(always)]
    pub(in crate::slot) fn direct_child_range(&self, parent_anchor: AnchorId) -> DirectChildRange {
        if !parent_anchor.is_valid() {
            DirectChildRange::new(0, self.group_count())
        } else {
            let parent_index = self.current_group_index(parent_anchor);
            DirectChildRange::new(
                parent_index + 1,
                self.group_subtree_end_at_index(parent_index),
            )
        }
    }

    pub(in crate::slot) fn direct_child_anchor_at_cursor(
        &self,
        cursor: ChildCursor,
    ) -> Option<AnchorId> {
        self.direct_child_sibling_record_at_cursor(cursor)
            .map(|group| group.anchor)
    }

    pub(in crate::slot) fn direct_child_sibling_record_at_cursor(
        &self,
        cursor: ChildCursor,
    ) -> Option<GroupSiblingRecord> {
        self.direct_child_sibling_record_at(cursor.parent(), cursor.index())
    }

    fn direct_child_sibling_record_at(
        &self,
        parent_anchor: AnchorId,
        child_index: usize,
    ) -> Option<GroupSiblingRecord> {
        if !self
            .direct_child_range(parent_anchor)
            .contains_index(child_index)
        {
            return None;
        }
        let group = self.group_sibling_record_at_index_checked(child_index)?;
        (group.parent_anchor == parent_anchor).then_some(group)
    }

    pub(in crate::slot) fn assert_child_cursor_boundary(&self, cursor: ChildCursor) {
        let siblings = self.direct_child_range(cursor.parent());
        assert!(
            siblings.start() <= cursor.index() && cursor.index() <= siblings.end(),
            "child cursor must stay inside the parent child range"
        );
        if cursor.index() == siblings.end() {
            return;
        }

        let group = self.group_sibling_record_at_index(cursor.index());
        assert_eq!(
            group.parent_anchor,
            cursor.parent(),
            "child cursor must point at a direct child boundary"
        );
    }
}