diffs-rs 0.1.1

Fast terminal diff viewer and embeddable Rust diff engine
Documentation
use std::{iter, ops::Range};

use ratatui::style::Color;
use serde::Serialize;

use super::{Cache, LineStyle, Token};

pub(super) fn side(side: &super::Side) -> serde_json::Value {
    serde_json::json!({
        "parse_heap_bytes": side.parse.owned_heap_bytes(),
        "highlight_heap_bytes": side.highlight.owned_heap_bytes(),
    })
}

pub(super) fn worker(
    continuation: &Option<super::Continuation>,
    full: &super::full_source::Replay,
    checkpoints: &super::Checkpoints,
) -> serde_json::Value {
    serde_json::json!({
        "schema": 1,
        "patch": {
            "inline_size_bytes": size_of::<Option<super::Continuation>>(),
            "state": continuation.as_ref().map(|state| serde_json::json!({
                "next": state.next, "old": side(&state.old), "new": side(&state.new),
            })),
        },
        "full_source": full.census(), "checkpoints": checkpoints.census(),
    })
}

#[derive(Default, Serialize)]
struct Vectors {
    count: usize,
    length: usize,
    capacity: usize,
    max_length: usize,
    max_capacity: usize,
}

impl Vectors {
    fn observe(&mut self, length: usize, capacity: usize) {
        self.count += 1;
        self.length += length;
        self.capacity += capacity;
        self.max_length = self.max_length.max(length);
        self.max_capacity = self.max_capacity.max(capacity);
    }
}

#[derive(Default, Serialize)]
struct Tokens {
    vectors: Vectors,
    empty_ranges: usize,
    invalid_vectors: usize,
    eligible_nonempty_tokens: usize,
    hypothetical_merged_tokens: usize,
}

impl Tokens {
    fn observe(&mut self, tokens: &[Token], capacity: usize) -> bool {
        self.vectors.observe(tokens.len(), capacity);
        let empty = tokens
            .iter()
            .filter(|t| t.range.start == t.range.end)
            .count();
        self.empty_ranges += empty;
        let valid = ordered(tokens);
        if valid {
            self.eligible_nonempty_tokens += tokens.len() - empty;
            self.hypothetical_merged_tokens += runs(tokens).count();
        } else {
            self.invalid_vectors += 1;
        }
        valid
    }
}

fn ordered(tokens: &[Token]) -> bool {
    tokens.iter().all(|t| t.range.start <= t.range.end)
        && tokens
            .windows(2)
            .all(|pair| pair[0].range.end <= pair[1].range.start)
}

fn runs(tokens: &[Token]) -> impl Iterator<Item = (Range<usize>, Color)> + '_ {
    let mut tokens = tokens.iter().filter(|t| !t.range.is_empty()).peekable();
    iter::from_fn(move || {
        let first = tokens.next()?;
        let mut range = first.range.clone();
        while let Some(next) = tokens.peek()
            && next.range.start == range.end
            && next.color == first.color
        {
            range.end = next.range.end;
            tokens.next();
        }
        Some((range, first.color))
    })
}

#[derive(Default)]
struct Storage {
    primary: Tokens,
    old: Tokens,
    changed: Vectors,
    old_comparison_ineligible: usize,
    equivalent_old_vectors: usize,
    equivalent_old_capacity_bytes: usize,
    identical_old_vectors: usize,
}

impl Cache {
    pub(crate) fn census(&self) -> serde_json::Value {
        let mut storage = Storage::default();
        for style in self.lines.values() {
            let primary_valid = storage
                .primary
                .observe(&style.tokens, style.tokens.capacity());
            if let Some(old) = &style.old_tokens {
                let old_valid = storage.old.observe(old, old.capacity());
                if primary_valid && old_valid {
                    if runs(old).eq(runs(&style.tokens)) {
                        storage.equivalent_old_vectors += 1;
                        storage.equivalent_old_capacity_bytes +=
                            old.capacity() * size_of::<Token>();
                    }
                    storage.identical_old_vectors += usize::from(*old == style.tokens);
                } else {
                    storage.old_comparison_ineligible += 1;
                }
            }
            storage
                .changed
                .observe(style.changed.len(), style.changed.capacity());
        }
        let inline = self.lines.len() * size_of::<LineStyle>();
        let dynamic_capacity = (storage.primary.vectors.capacity + storage.old.vectors.capacity)
            * size_of::<Token>()
            + storage.changed.capacity * size_of::<Range<usize>>();
        let dynamic_used = (storage.primary.vectors.length + storage.old.vectors.length)
            * size_of::<Token>()
            + storage.changed.length * size_of::<Range<usize>>();
        let table_allocation = self.lines.allocation_size();
        let fifo_capacity = self.order.capacity() * size_of::<super::LineId>();
        let visible_capacity = self.visible.capacity() * size_of::<super::LineId>();
        let visible_bytes: usize = self
            .visible
            .iter()
            .filter_map(|id| self.lines.get(id))
            .map(LineStyle::cache_weight)
            .sum();
        let reported_heap = table_allocation + dynamic_capacity + fifo_capacity + visible_capacity;
        serde_json::json!({
            "entries": self.lines.len(), "payload_counter_bytes": self.bytes,
            "key_size_bytes": size_of::<super::LineId>(),
            "occupied_key_bytes": self.lines.len() * size_of::<super::LineId>(),
            "recomputed_payload_bytes": inline + dynamic_capacity, "map_capacity": self.lines.capacity(),
            "fifo_length": self.order.len(), "fifo_capacity": self.order.capacity(),
            "fifo_accounting": "recomputed-from-styles",
            "fifo_element_size_bytes": size_of::<super::LineId>(),
            "fifo_capacity_bytes": self.order.capacity() * size_of::<super::LineId>(),
            "fifo_accounted_bytes": self.order.iter().map(|id| {
                self.lines.get(id).expect("Queued style is missing").cache_weight()
            }).sum::<usize>(),
            "visible_protection": {
                "schema": 1, "retained_target_bytes": 32 * 1024 * 1024,
                "ids": self.visible.len(), "capacity": self.visible.capacity(),
                "capacity_bytes": visible_capacity,
                "cached_entries": self.visible.iter().filter(|id| self.lines.contains_key(*id)).count(),
                "payload_bytes": visible_bytes,
            },
            "activity": {
                "schema": 3, "scope": "current-cache-instance",
                "counter_storage_bytes": size_of::<super::cache_activity::Activity>(),
                "observations": self.activity,
            },
            "container_storage": {
                "schema": 2,
                "scope": "retained-requested-storage-excluding-allocator-overhead",
                "table_provider": "hashbrown-0.16.1-allocation_size",
                "table_allocation_bytes": table_allocation,
                "vector_capacity_bytes": dynamic_capacity,
                "fifo_capacity_bytes": fifo_capacity,
                "visible_capacity_bytes": visible_capacity,
                "reported_heap_bytes": reported_heap,
                "inline_scope": "observed-owner-census-build",
                "inline_cache_bytes": size_of::<Cache>(),
                "diagnostic_inline_bytes": size_of::<super::cache_activity::Activity>(),
                "reported_value_and_heap_bytes": reported_heap + size_of::<Cache>(),
            },
            "style_storage": {
                "schema": 1, "line_style_size_bytes": size_of::<LineStyle>(),
                "token_size_bytes": size_of::<Token>(), "changed_range_size_bytes": size_of::<Range<usize>>(),
                "inline_value_bytes": inline, "dynamic_capacity_bytes": dynamic_capacity,
                "dynamic_used_bytes": dynamic_used, "dynamic_spare_bytes": dynamic_capacity - dynamic_used,
                "primary": storage.primary, "old": storage.old, "changed": storage.changed,
                "old_comparison_ineligible": storage.old_comparison_ineligible,
                "equivalent_old_vectors": storage.equivalent_old_vectors,
                "equivalent_old_capacity_bytes": storage.equivalent_old_capacity_bytes,
                "identical_old_vectors": storage.identical_old_vectors,
            },
        })
    }
}

#[cfg(test)]
mod tests;