cranpose-core 0.9.0

Core runtime for a Jetpack Compose inspired UI framework in Rust
Documentation
use std::mem;

use super::{
    GroupRecord, SlotDebugAnchor, SlotDebugEntry, SlotDebugEntryKind, SlotDebugGroup,
    SlotDebugScope, SlotDebugSnapshot, SlotTable, SlotTableLocalDebugStats,
    SlotTableMutationDebugStats,
};
use crate::{Key, RecomposeScope, ScopeId};

impl SlotTable {
    fn group_heap_bytes(&self) -> usize {
        self.groups.capacity() * mem::size_of::<GroupRecord>()
    }

    pub fn heap_bytes(&self) -> usize {
        self.group_heap_bytes()
            + self.payloads.heap_bytes()
            + self.node_heap_bytes()
            + self.anchors.heap_bytes()
            + self.payload_anchors.heap_bytes()
    }

    pub fn debug_stats(&self) -> SlotTableLocalDebugStats {
        SlotTableLocalDebugStats {
            group_count: self.groups.len(),
            group_capacity: self.groups.capacity(),
            group_record_size: mem::size_of::<GroupRecord>(),
            group_heap_bytes: self.group_heap_bytes(),
            payload_count: self.total_payload_count(),
            payload_capacity: self.payloads.capacity(),
            active_payload_anchor_count: self.payload_anchors.active_len(),
            payload_anchor_slot_count: self.payload_anchors.slot_len(),
            detached_payload_anchor_count: self.payload_anchors.detached_len(),
            invalidated_payload_anchor_count: self.payload_anchors.invalidated_len(),
            free_payload_anchor_count: self.payload_anchors.free_len(),
            payload_anchor_capacity: self.payload_anchors.capacity(),
            payload_anchor_heap_bytes: self.payload_anchors.heap_bytes(),
            node_count: self.total_node_count(),
            node_capacity: self.node_debug_capacity(),
            active_anchor_count: self.anchors.active_len(),
            anchor_slot_count: self.anchors.slot_len(),
            anchor_sparse_count: self.anchors.sparse_slot_len(),
            detached_anchor_count: self.anchors.detached_len(),
            invalidated_anchor_count: self.anchors.invalidated_len(),
            free_anchor_count: self.anchors.free_len(),
            anchor_capacity: self.anchors.capacity(),
            anchor_heap_bytes: self.anchors.heap_bytes(),
            mutation: SlotTableMutationDebugStats {
                payload_shift_bytes: self.payloads.shift_bytes(),
                ..self.diagnostics.mutation()
            },
        }
    }

    pub fn debug_dump_groups(&self) -> Vec<(usize, Key, Option<ScopeId>, usize)> {
        self.groups
            .iter()
            .enumerate()
            .map(|(index, group)| {
                (
                    index,
                    group.key.static_key,
                    group.scope.as_ref().map(RecomposeScope::id),
                    group.subtree_len as usize,
                )
            })
            .collect()
    }

    pub fn debug_snapshot(&self) -> SlotDebugSnapshot {
        let active_groups = self
            .groups
            .iter()
            .enumerate()
            .map(|(index, group)| SlotDebugGroup {
                index,
                anchor: group.anchor,
                parent_anchor: group.parent_anchor,
                static_key: group.key.static_key,
                explicit_key: group.key.explicit_key,
                ordinal: group.key.ordinal,
                scope_id: group.scope.as_ref().map(RecomposeScope::id),
                depth: group.depth,
                subtree_len: group.subtree_len,
                payload_len: self.group_payload_len_at(index),
                node_len: self.group_node_len_at(index),
                subtree_node_count: group.subtree_node_count,
            })
            .collect::<Vec<_>>();
        let mut anchors = self
            .anchors
            .active_entries()
            .map(|(anchor, group_index)| SlotDebugAnchor {
                anchor,
                group_index,
            })
            .collect::<Vec<_>>();
        anchors.sort_by_key(|entry| entry.group_index);

        let mut scopes = self
            .groups
            .iter()
            .enumerate()
            .filter_map(|(group_index, group)| {
                group.scope.as_ref().map(|scope| SlotDebugScope {
                    scope_id: scope.id(),
                    anchor: group.anchor,
                    group_index,
                })
            })
            .collect::<Vec<_>>();
        scopes.sort_by_key(|entry| entry.scope_id);

        SlotDebugSnapshot {
            active_payload_count: self.total_payload_count(),
            active_node_count: self.total_node_count(),
            active_scope_count: scopes.len(),
            active_groups,
            anchors,
            scopes,
            retained_subtree_count: 0,
            retained_group_count: 0,
            retained_payload_count: 0,
            retained_node_count: 0,
            retained_scope_count: 0,
        }
    }

    pub fn debug_dump_slot_entries(&self) -> Vec<SlotDebugEntry> {
        let mut rows = Vec::new();
        for (index, group) in self.groups.iter().enumerate() {
            rows.push(SlotDebugEntry {
                kind: SlotDebugEntryKind::Group,
                path: format!("group[{index}]"),
                line: format!(
                    "Group(key={:?}, scope={:?}, subtree_len={}, payload_len={}, node_len={})",
                    group.key,
                    group.scope.as_ref().map(RecomposeScope::id),
                    group.subtree_len,
                    self.group_payload_len_at(index),
                    self.group_node_len_at(index)
                ),
            });
        }
        for (group_index, group) in self.groups.iter().enumerate() {
            for (payload_index, payload) in self.group_payload_records_at(group_index).enumerate() {
                rows.push(SlotDebugEntry {
                    kind: SlotDebugEntryKind::Payload,
                    path: format!("group[{group_index}].payload[{payload_index}]"),
                    line: format!(
                        "Payload(owner={:?}, kind={}, type={})",
                        group.anchor,
                        payload.kind.label(),
                        (payload.payload_type.type_name)()
                    ),
                });
            }
        }
        for (group_index, _) in self.groups.iter().enumerate() {
            for (node_index, node) in self.group_node_records_at(group_index).iter().enumerate() {
                rows.push(SlotDebugEntry {
                    kind: SlotDebugEntryKind::Node,
                    path: format!("group[{group_index}].node[{node_index}]"),
                    line: format!(
                        "Node(owner={:?}, parent={:?}, id={}, gen={}, lifecycle={:?})",
                        node.owner, node.parent_id, node.id, node.generation, node.lifecycle
                    ),
                });
            }
        }
        rows
    }
}