cranpose-core 0.0.59

Core runtime for a Jetpack Compose inspired UI framework in Rust
Documentation
use super::*;

#[cfg(all(debug_assertions, not(target_arch = "wasm32")))]
fn debug_scope_label_env_enabled() -> bool {
    use std::sync::OnceLock;
    static DEBUG_SCOPE_TRACKING: OnceLock<bool> = OnceLock::new();
    *DEBUG_SCOPE_TRACKING.get_or_init(|| std::env::var_os("CRANPOSE_DEBUG_SCOPE_LABELS").is_some())
}

#[cfg(all(debug_assertions, not(target_arch = "wasm32")))]
fn debug_scope_tracking_enabled() -> bool {
    #[cfg(test)]
    if let Some(enabled) = DEBUG_SCOPE_TRACKING_OVERRIDE.with(Cell::get) {
        return enabled;
    }
    debug_scope_label_env_enabled()
        || log::log_enabled!(target: "cranpose::compose::recompose", log::Level::Trace)
        || log::log_enabled!(target: "cranpose::compose::emit", log::Level::Trace)
        || log::log_enabled!(target: "cranpose::compose::parent", log::Level::Trace)
}

#[cfg(any(not(debug_assertions), target_arch = "wasm32"))]
fn debug_scope_tracking_enabled() -> bool {
    false
}

#[doc(hidden)]
pub fn debug_label_current_scope(name: &'static str) {
    if !debug_scope_tracking_enabled() {
        let _ = name;
        return;
    }
    #[cfg(debug_assertions)]
    with_current_composer(|composer| {
        if let Some(scope) = composer.current_recranpose_scope() {
            DEBUG_SCOPE_LABELS.with(|labels| {
                labels.borrow_mut().insert(scope.id(), name);
            });
        }
    });
}

pub(crate) fn debug_record_scope_invalidation<T: 'static>(
    scope_id: usize,
    state_id: Option<StateId>,
) {
    if !debug_scope_tracking_enabled() {
        let _ = scope_id;
        let _ = state_id;
        return;
    }
    #[cfg(debug_assertions)]
    {
        let source = match state_id {
            Some(id) => format!(
                "slot={} gen={} {}",
                id.slot(),
                id.generation(),
                std::any::type_name::<T>()
            ),
            None => std::any::type_name::<T>().to_string(),
        };
        DEBUG_SCOPE_INVALIDATION_SOURCES.with(|sources| {
            sources
                .borrow_mut()
                .entry(scope_id)
                .or_default()
                .insert(source);
        });
    }
}

#[doc(hidden)]
pub fn debug_scope_label(scope_id: usize) -> Option<&'static str> {
    if !debug_scope_tracking_enabled() {
        let _ = scope_id;
        return None;
    }
    #[cfg(debug_assertions)]
    {
        return DEBUG_SCOPE_LABELS.with(|labels| labels.borrow().get(&scope_id).copied());
    }
    #[allow(unreachable_code)]
    None
}

#[doc(hidden)]
pub fn debug_scope_invalidation_sources(scope_id: usize) -> Vec<String> {
    if !debug_scope_tracking_enabled() {
        let _ = scope_id;
        return Vec::new();
    }
    #[cfg(debug_assertions)]
    {
        return DEBUG_SCOPE_INVALIDATION_SOURCES.with(|sources| {
            let Some(entries) = sources.borrow().get(&scope_id).cloned() else {
                return Vec::new();
            };
            let mut entries: Vec<_> = entries.into_iter().collect();
            entries.sort();
            entries
        });
    }
    #[allow(unreachable_code)]
    Vec::new()
}

#[cfg(test)]
pub(crate) fn set_debug_scope_tracking_override_for_tests(enabled: Option<bool>) {
    DEBUG_SCOPE_TRACKING_OVERRIDE.with(|override_flag| override_flag.set(enabled));
}

#[doc(hidden)]
pub fn debug_live_recompose_scope_count() -> usize {
    LIVE_RECOMPOSE_SCOPE_COUNT.load(Ordering::Relaxed)
}

#[doc(hidden)]
pub fn debug_recompose_scope_registry_stats() -> RecomposeScopeRegistryDebugStats {
    let live = LIVE_RECOMPOSE_SCOPE_COUNT.load(Ordering::Relaxed);
    RecomposeScopeRegistryDebugStats {
        len: live,
        capacity: live,
    }
}