cranpose-core 0.0.60

Core runtime for a Jetpack Compose inspired UI framework in Rust
Documentation
use super::{
    checked_usize_to_i64,
    segments::{
        extract_subtree_segment, group_segment_len, group_segment_range_at, group_segment_start,
        group_segment_subrange_at, insert_group_segment_item,
        move_subtree_segment_to_earlier_group, remove_group_segment_range, restore_subtree_segment,
        NodeSegment,
    },
    GroupNodeRange, GroupRecord, NodeLifecycle, NodeRange, NodeRecord, NodeSlotUpdate, SlotTable,
};
use crate::{AnchorId, NodeId};
use std::mem;

impl SlotTable {
    fn group_node_start_at(&self, group_index: usize) -> usize {
        group_segment_start::<NodeSegment>(&self.groups, group_index)
    }

    pub(in crate::slot) fn group_node_len_at(&self, group_index: usize) -> usize {
        group_segment_len::<NodeSegment>(&self.groups, group_index)
    }

    fn group_node_range_at(&self, group_index: usize) -> NodeRange {
        group_segment_range_at::<NodeSegment>(&self.groups, self.nodes.len(), group_index)
    }

    pub(in crate::slot) fn group_node_tail_range_at(
        &self,
        group_index: usize,
        start: usize,
    ) -> GroupNodeRange {
        let node_len = self.group_node_len_at(group_index);
        let start = start.min(node_len);
        group_segment_subrange_at::<NodeSegment>(
            &self.groups,
            self.nodes.len(),
            group_index,
            start,
            node_len,
        )
    }

    fn insert_group_node(&mut self, group_index: usize, node_index: usize, node: NodeRecord) {
        // Node insertion/removal uses the same segment recipe as payloads, with
        // ancestor node counts adjusted by the public cursor-level operations.
        self.record_segment_range_update_from(group_index);
        insert_group_segment_item::<NodeSegment, _>(
            &mut self.groups,
            &mut self.nodes,
            group_index,
            node_index,
            node,
        );
    }

    fn remove_node_range(&mut self, node_range: GroupNodeRange) -> Vec<NodeRecord> {
        // The caller owns lifecycle side effects for removed node records after
        // this function restores coherent node segment ranges.
        if !node_range.is_empty() {
            self.record_segment_range_update_from(node_range.group_index());
        }
        remove_group_segment_range::<NodeSegment, _>(&mut self.groups, &mut self.nodes, node_range)
    }

    fn extract_node_segment_for_groups(
        &mut self,
        removed_group_index: usize,
        removed_groups: &mut [GroupRecord],
    ) -> Vec<NodeRecord> {
        if removed_groups.iter().any(|group| group.node_len > 0) {
            let active_span = self.groups.len().saturating_sub(removed_group_index);
            self.record_segment_range_update_span(active_span + removed_groups.len());
        }
        extract_subtree_segment::<NodeSegment, _>(
            &mut self.groups,
            &mut self.nodes,
            removed_group_index,
            removed_groups,
        )
    }

    fn restore_node_segment_for_groups(
        &mut self,
        insert_group_index: usize,
        groups: &mut [GroupRecord],
        nodes: Vec<NodeRecord>,
    ) {
        if !nodes.is_empty() {
            let active_span = self.groups.len().saturating_sub(insert_group_index);
            self.record_segment_range_update_span(active_span + groups.len());
        }
        restore_subtree_segment::<NodeSegment, _>(
            &mut self.groups,
            &mut self.nodes,
            insert_group_index,
            groups,
            nodes,
        );
    }

    pub(in crate::slot) fn group_node_records_at(&self, group_index: usize) -> &[NodeRecord] {
        let range = self.group_node_range_at(group_index);
        &self.nodes[range.as_range()]
    }

    pub(in crate::slot) fn group_node_record_at(
        &self,
        group_index: usize,
        node_index: usize,
    ) -> &NodeRecord {
        self.group_node_records_at(group_index)
            .get(node_index)
            .expect("node index should resolve")
    }

    pub(in crate::slot) fn group_node_record_at_mut(
        &mut self,
        group_index: usize,
        node_index: usize,
    ) -> &mut NodeRecord {
        let node_start = self.group_node_start_at(group_index);
        self.nodes
            .get_mut(node_start + node_index)
            .expect("node index should resolve")
    }

    pub(in crate::slot) fn total_node_count(&self) -> usize {
        self.nodes.len()
    }

    pub(super) fn node_heap_bytes(&self) -> usize {
        self.nodes.capacity() * mem::size_of::<NodeRecord>()
    }

    pub(super) fn node_debug_capacity(&self) -> usize {
        self.nodes.capacity()
    }

    fn record_group_node(
        &mut self,
        group_index: usize,
        node_index: usize,
        owner: AnchorId,
        id: NodeId,
        parent_id: Option<NodeId>,
        generation: u32,
    ) -> NodeSlotUpdate {
        if node_index < self.group_node_len_at(group_index) {
            let existing = *self.group_node_record_at(group_index, node_index);
            *self.group_node_record_at_mut(group_index, node_index) = NodeRecord {
                owner,
                id,
                parent_id,
                generation,
                lifecycle: NodeLifecycle::Active,
            };
            if existing.id == id && existing.generation == generation {
                NodeSlotUpdate::Reused { id, generation }
            } else {
                NodeSlotUpdate::Replaced {
                    old_id: existing.id,
                    old_generation: existing.generation,
                    new_id: id,
                    new_generation: generation,
                }
            }
        } else {
            self.insert_group_node(
                group_index,
                node_index,
                NodeRecord {
                    owner,
                    id,
                    parent_id,
                    generation,
                    lifecycle: NodeLifecycle::Active,
                },
            );
            NodeSlotUpdate::Inserted { id, generation }
        }
    }

    pub(super) fn record_node_at_cursor(
        &mut self,
        owner: AnchorId,
        node_index: usize,
        id: NodeId,
        parent_id: Option<NodeId>,
        generation: u32,
    ) -> NodeSlotUpdate {
        let group_index = self.current_group_index(owner);
        let update =
            self.record_group_node(group_index, node_index, owner, id, parent_id, generation);
        if matches!(update, NodeSlotUpdate::Inserted { .. }) {
            self.adjust_ancestor_node_counts(owner, 1);
        }

        update
    }

    pub(super) fn node_identity_at_cursor(
        &self,
        owner: AnchorId,
        node_index: usize,
    ) -> Option<(NodeId, u32)> {
        let group_index = self.current_group_index(owner);
        if node_index >= self.group_node_len_at(group_index) {
            return None;
        }
        let node = self.group_node_record_at(group_index, node_index);
        Some((node.id, node.generation))
    }

    pub(super) fn remove_group_node_range(
        &mut self,
        node_range: GroupNodeRange,
    ) -> Vec<NodeRecord> {
        if node_range.is_empty() {
            return Vec::new();
        }
        self.remove_node_range(node_range)
    }

    pub(super) fn remove_group_node_tail_at_cursor(
        &mut self,
        owner: AnchorId,
        node_cursor: usize,
    ) -> Vec<NodeRecord> {
        let group_index = self.current_group_index(owner);
        let node_range = self.group_node_tail_range_at(group_index, node_cursor);
        let removed = self.remove_group_node_range(node_range);
        if !removed.is_empty() {
            let removed_len = checked_usize_to_i64(removed.len(), "removed node count");
            self.adjust_ancestor_node_counts(owner, -removed_len);
        }
        removed
    }

    pub(super) fn detach_nodes_for_groups(
        &mut self,
        removed_group_index: usize,
        removed_groups: &mut [GroupRecord],
    ) -> Vec<NodeRecord> {
        self.extract_node_segment_for_groups(removed_group_index, removed_groups)
    }

    pub(super) fn move_nodes_to_earlier_group(
        &mut self,
        insert_group_index: usize,
        moving_group_index: usize,
        moving_group_len: usize,
    ) -> usize {
        let moved_node_count = move_subtree_segment_to_earlier_group::<NodeSegment, _>(
            &mut self.groups,
            &mut self.nodes,
            insert_group_index,
            moving_group_index,
            moving_group_len,
        );
        if moved_node_count > 0 {
            self.record_segment_range_update_span(
                moving_group_index + moving_group_len - insert_group_index,
            );
        }
        moved_node_count
    }

    pub(super) fn restore_nodes_for_groups(
        &mut self,
        insert_group_index: usize,
        groups: &mut [GroupRecord],
        nodes: Vec<NodeRecord>,
    ) {
        self.restore_node_segment_for_groups(insert_group_index, groups, nodes);
    }
}