Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/nornir

src/mimir_lens/room_feed/fixture/clones.rs

//! The fixture of the clone signals: one repo `clo` (crate clo@0.1.0) whose
//! source is real text on disk and whose dump carries the edges signal 2
//! reads (params, the `->` part, USES_TYPE, READS_FIELD, CALLS).
//!
//! ```text
//! src/lib.rs
//!   MapLayout { repos, plates }
//!   tally      ─┐ the SAME logic under unrelated names (a consistent rename,
//!   summarize  ─┘ another layout, other comments): exact + structural
//!   tally_more    tally with one statement changed: a near copy
//!   place      ─┐ unrelated names, DIFFERENT bodies, the same rare return
//!   arrange    ─┘ type and fields read: structural only
//!   kill / delete  name-alike, nothing alike in what they do: no signal
//!   now_ms / now_unix_ms  "milliseconds since the epoch" written twice (one-liners)
//!   workspace_root / repo_root  "where is the root", written twice, touching
//!                 other things: a Type-4 twin
//!   sum_lanes_avx2 / sum_lanes_scalar  one algorithm per CPU feature: deliberate
//!   bump_alpha / bump_beta  ONE body on two types (other params, other callees):
//!                 structure 0, but the same normalised body — a copy, never a twin
//!   flag_a / flag_b  two-feature accessors (`-> Option<bool>`, one field): too
//!                 little structure to be a structural or role pair
//!   checksum      a lone utility
//!   step0..step29 the common case: `fn(&str) -> Result<(), Error>`
//! ```
//!
//! [`Clo::second_commit`]: `summarize` gets another body (seq 2).
//! [`Clo::commit_v`] `2`: … and `checksum` also calls `rotate_right` (its
//! features move); `3`: … and a new function `fold_bytes` (the population moves).

use std::collections::BTreeSet;
use std::path::{Path, PathBuf};

use mimir_ingest::CommitDump;
use mimir_schema::{EdgeKind, EdgeRow, Level, moniker};

use super::vectors::{Source, callable, consume_next, stubs_into};
use super::{N, Workspace, e, n, unit};
use crate::code_room::CodeRoom;
use crate::warehouse::iceberg::IcebergWarehouse;

pub const CLO: &str = "clo";

pub fn clo(d: &str) -> String {
    moniker::moniker("clo", "0.1.0", d)
}

pub const TALLY: &str = "/// Sum the plates above the floor, and count the repos.
pub fn tally(layout: &MapLayout, floor: u32) -> u32 {
    let mut total = 0;
    for plate in &layout.plates {
        if *plate > floor {
            total += *plate;
        }
    }
    let mut seen = 0;
    for repo in &layout.repos {
        if !repo.is_empty() {
            seen += 1;
        }
    }
    total + seen
}";

/// TALLY consistently renamed, laid out and commented otherwise.
pub const SUMMARIZE: &str = "pub fn summarize(map: &MapLayout, min: u32) -> u32 {
    // accumulate
    let mut acc = 0;
    for p in &map.plates { if *p > min { acc += *p; } }
    let mut n = 0;
    for r in &map.repos { if !r.is_empty() { n += 1; } }
    acc + n
}";

const SUMMARIZE_2: &str = "pub fn summarize(map: &MapLayout, min: u32) -> u32 {
    map.plates.iter().filter(|p| **p > min).sum::<u32>() + map.repos.len() as u32
}";

pub const TALLY_MORE: &str = "pub fn tally_more(layout: &MapLayout, floor: u32) -> u32 {
    let mut total = 0;
    for plate in &layout.plates {
        if *plate > floor {
            total += *plate;
        }
    }
    let mut seen = 0;
    for repo in &layout.repos {
        if !repo.is_empty() {
            seen += 1;
        }
    }
    total + seen + 1
}";

const PLACE: &str = "pub fn place(seed: &MapLayout, extra: u32) -> MapLayout {
    let mut repos = seed.repos.clone();
    repos.sort();
    MapLayout { repos, plates: seed.plates.iter().map(|p| p + extra).collect() }
}";

const ARRANGE: &str = "pub fn arrange(base: &MapLayout, names: &[String]) -> MapLayout {
    let plates: Vec<u32> = base.plates.iter().rev().copied().collect();
    let mut repos: Vec<String> = names.to_vec();
    repos.extend(base.repos.iter().cloned());
    MapLayout { repos, plates }
}";

pub const KILL: &str = "pub fn kill(pid: u32, table: &mut Vec<u32>) -> bool {
    let before = table.len();
    table.retain(|p| *p != pid);
    before != table.len()
}";

pub const DELETE: &str = "pub fn delete(path: &str, cache: &mut String) -> usize {
    let mut removed = 0;
    while let Some(at) = cache.find(path) {
        cache.replace_range(at..at + path.len(), \"\");
        removed += 1;
    }
    removed
}";

/// "Seconds since the epoch", written twice (v1's nine-way twin): the same
/// role and meaning, another body.
pub const NOW_MS: &str = "pub fn now_ms() -> u64 {
    SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_millis() as u64).unwrap_or(0)
}";

pub const NOW_UNIX_MS: &str = "pub fn now_unix_ms() -> u64 {
    let now = SystemTime::now();
    match now.duration_since(UNIX_EPOCH) {
        Ok(elapsed) => elapsed.as_millis() as u64,
        Err(_) => 0,
    }
}";

/// "Where is the repository root", written twice (v1's seven-way twin): the
/// same idea, other calls — little structure in common.
pub const WORKSPACE_ROOT: &str = "pub fn workspace_root() -> PathBuf {
    // the directory above this crate's manifest is the root
    let here = PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"));
    let root = here.parent().map(Path::to_path_buf);
    root.unwrap_or(here)
}";

pub const REPO_ROOT: &str = "pub fn repo_root() -> PathBuf {
    // climb from here until the directory that holds the root
    let mut here = std::env::current_dir().unwrap_or_default();
    while !here.join(\".git\").exists() && here.pop() {}
    here
}";

/// One algorithm written per CPU feature: the same body, deliberate.
fn sum_lanes(variant: &str) -> String {
    let attr = if variant == "avx2" { "#[target_feature(enable = \"avx2\")]\n" } else { "" };
    format!(
        "{attr}pub unsafe fn sum_lanes_{variant}(xs: &[u32], floor: u32) -> u32 {{
    let mut total = 0u32;
    let mut i = 0;
    while i + 8 <= xs.len() {{
        for x in &xs[i..i + 8] {{
            if *x > floor {{
                total = total.wrapping_add(*x);
            }}
        }}
        i += 8;
    }}
    for x in &xs[i..] {{
        if *x > floor {{
            total = total.wrapping_add(*x);
        }}
    }}
    total
}}"
    )
}

/// One body written on two types (`DatePicker::next_month` / `Calendar::next_month`
/// on the live forge): the same normalised text, other params and callees.
fn bump(ty: &str) -> String {
    format!(
        "pub fn bump_{ty}(xs: &mut Lanes, by: u32) -> u32 {{
    let mut moved = 0;
    for x in xs.iter_mut() {{
        *x = x.wrapping_add(by);
        moved += 1;
    }}
    xs.settle();
    moved
}}"
    )
}

/// A two-feature accessor.
fn flag(n: &str) -> String {
    format!("pub fn flag_{n}() -> Option<bool> {{\n    STATE.plates.first().map(|p| *p > 0)\n}}")
}

const CHECKSUM: &str = "pub fn checksum(bytes: &[u8]) -> u32 {
    let mut acc = 17u32;
    for b in bytes {
        acc = acc.rotate_left(5) ^ u32::from(*b);
    }
    acc
}";

/// `checksum` at variant 2: one call more (`rotate_right`) — its features move.
const CHECKSUM_2: &str = "pub fn checksum(bytes: &[u8]) -> u32 {
    let mut acc = 17u32;
    for b in bytes {
        acc = acc.rotate_left(5) ^ u32::from(*b);
    }
    acc.rotate_right(3)
}";

/// A function that appears at variant 3: the population moves.
const FOLD_BYTES: &str = "pub fn fold_bytes(bytes: &[u8], seed: u32) -> u32 {
    let mut h = seed;
    for b in bytes {
        h = h.wrapping_mul(31).wrapping_add(u32::from(*b));
    }
    h
}";

/// One function: its text, params, the printed return type, and what it touches.
struct Fun {
    name: &'static str,
    text: String,
    params: Vec<(&'static str, &'static str)>,
    ret: Option<&'static str>,
    uses: bool,
    reads: Vec<&'static str>,
    calls: Vec<String>,
}

fn funs(v: u8) -> Vec<Fun> {
    let second = v >= 1;
    let ml = |name, text: &str, params: Vec<(&'static str, &'static str)>, ret, reads: Vec<&'static str>| Fun { name, text: text.to_string(), params, ret, uses: true, reads, calls: Vec::new() };
    let mut out = vec![
        ml("tally", TALLY, vec![("layout", "&MapLayout"), ("floor", "u32")], Some("u32"), vec!["plates", "repos"]),
        ml("summarize", if second { SUMMARIZE_2 } else { SUMMARIZE }, vec![("map", "&MapLayout"), ("min", "u32")], Some("u32"), vec!["plates", "repos"]),
        ml("tally_more", TALLY_MORE, vec![("layout", "&MapLayout"), ("floor", "u32")], Some("u32"), vec!["plates", "repos"]),
        ml("place", PLACE, vec![("seed", "&MapLayout"), ("extra", "u32")], Some("MapLayout"), vec!["repos", "plates"]),
        ml("arrange", ARRANGE, vec![("base", "&MapLayout"), ("names", "&[String]")], Some("MapLayout"), vec!["plates", "repos"]),
        Fun { name: "kill", text: KILL.into(), params: vec![("pid", "u32"), ("table", "&mut Vec<u32>")], ret: Some("bool"), uses: false, reads: vec![], calls: vec!["retain".into()] },
        Fun { name: "delete", text: DELETE.into(), params: vec![("path", "&str"), ("cache", "&mut String")], ret: Some("usize"), uses: false, reads: vec![], calls: vec!["find".into(), "replace_range".into()] },
        Fun { name: "now_ms", text: NOW_MS.into(), params: vec![], ret: Some("u64"), uses: false, reads: vec![], calls: vec!["now".into(), "duration_since".into(), "as_millis".into()] },
        Fun { name: "now_unix_ms", text: NOW_UNIX_MS.into(), params: vec![], ret: Some("u64"), uses: false, reads: vec![], calls: vec!["now".into(), "duration_since".into(), "as_millis".into()] },
        Fun { name: "workspace_root", text: WORKSPACE_ROOT.into(), params: vec![], ret: Some("PathBuf"), uses: false, reads: vec![], calls: vec!["from".into(), "parent".into(), "map".into(), "unwrap_or".into()] },
        Fun { name: "repo_root", text: REPO_ROOT.into(), params: vec![], ret: Some("PathBuf"), uses: false, reads: vec![], calls: vec!["current_dir".into(), "unwrap_or_default".into(), "join".into(), "exists".into(), "pop".into()] },
        Fun { name: "sum_lanes_avx2", text: sum_lanes("avx2"), params: vec![("xs", "&[u32]"), ("floor", "u32")], ret: Some("u32"), uses: false, reads: vec![], calls: vec!["len".into(), "wrapping_add".into()] },
        Fun { name: "sum_lanes_scalar", text: sum_lanes("scalar"), params: vec![("xs", "&[u32]"), ("floor", "u32")], ret: Some("u32"), uses: false, reads: vec![], calls: vec!["len".into(), "wrapping_add".into()] },
        Fun { name: "bump_alpha", text: bump("alpha"), params: vec![("xs", "&mut AlphaLanes"), ("by", "u16")], ret: Some("usize"), uses: false, reads: vec![], calls: vec!["alpha_iter".into(), "alpha_settle".into()] },
        Fun { name: "bump_beta", text: bump("beta"), params: vec![("xs", "&mut BetaLanes"), ("by", "u8")], ret: Some("isize"), uses: false, reads: vec![], calls: vec!["beta_iter".into(), "beta_settle".into()] },
        Fun { name: "flag_a", text: flag("a"), params: vec![], ret: Some("Option<bool>"), uses: false, reads: vec!["plates"], calls: vec![] },
        Fun { name: "flag_b", text: flag("b"), params: vec![], ret: Some("Option<bool>"), uses: false, reads: vec!["plates"], calls: vec![] },
        if v >= 2 {
            Fun { name: "checksum", text: CHECKSUM_2.into(), params: vec![("bytes", "&[u8]")], ret: Some("u32"), uses: false, reads: vec![], calls: vec!["rotate_left".into(), "rotate_right".into()] }
        } else {
            Fun { name: "checksum", text: CHECKSUM.into(), params: vec![("bytes", "&[u8]")], ret: Some("u32"), uses: false, reads: vec![], calls: vec!["rotate_left".into()] }
        },
    ];
    if v >= 3 {
        out.push(Fun { name: "fold_bytes", text: FOLD_BYTES.into(), params: vec![("bytes", "&[u8]"), ("seed", "u32")], ret: Some("u32"), uses: false, reads: vec![], calls: vec!["wrapping_mul".into(), "wrapping_add".into()] });
    }
    for i in 0..30 {
        out.push(Fun {
            name: Box::leak(format!("step{i}").into_boxed_str()),
            text: format!("pub fn step{i}(name: &str) -> Result<(), Error> {{\n    check{i}(name)?;\n    Ok(())\n}}"),
            params: vec![("name", "&str")],
            ret: Some("Result<(), Error>"),
            uses: false,
            reads: vec![],
            calls: vec![format!("check{i}")],
        });
    }
    out
}

fn commit(root: &Path, v: u8) -> CommitDump {
    let krate = clo("crate/");
    let strukt = clo("MapLayout#");
    let field = |f: &str| clo(&format!("MapLayout#{f}."));
    let mut src = Source::default();
    src.plain("//! clo\n\npub struct MapLayout {\n    pub repos: Vec<String>,\n    pub plates: Vec<u32>,\n}\n");
    let fs = funs(v);
    for f in &fs {
        src.item(&clo(&format!("{}().", f.name)), 0, &f.text);
    }
    let spans = src.write(root, "src/lib.rs");
    let mut nodes: Vec<N> = vec![
        n(krate.clone(), "crate", Level::Crate, "clo", None),
        n(strukt.clone(), "struct", Level::Item, "MapLayout", Some(krate.clone())),
        n(field("repos"), "field", Level::Part, "repos", Some(strukt.clone())),
        n(field("plates"), "field", Level::Part, "plates", Some(strukt.clone())),
    ];
    let mut edges: Vec<EdgeRow> = vec![e(&krate, &strukt, EdgeKind::Contains, 1), e(&strukt, &field("repos"), EdgeKind::Contains, 1), e(&strukt, &field("plates"), EdgeKind::Contains, 1)];
    let mut stubs = BTreeSet::new();
    for f in &fs {
        let id = clo(&format!("{}().", f.name));
        let calls: Vec<&str> = f.calls.iter().map(String::as_str).collect();
        callable(&mut nodes, &mut edges, &mut stubs, n(id.clone(), "fn", Level::Item, f.name, Some(krate.clone())), &krate, &f.params, &calls);
        if let Some(ty) = f.ret {
            let rid = format!("{id}`->`");
            nodes.push(n(rid.clone(), "ret", Level::Part, "->", Some(id.clone())).ty(ty));
            edges.push(e(&id, &rid, EdgeKind::Contains, 1));
        }
        if f.uses {
            edges.push(e(&id, &strukt, EdgeKind::UsesType, 1));
        }
        for r in &f.reads {
            edges.push(e(&id, &field(r), EdgeKind::ReadsField, 1));
        }
    }
    stubs_into(&mut nodes, &stubs);
    CommitDump {
        toolchain: "nightly-fixture".into(),
        workspace_crates: ["clo@0.1.0:lib".to_string()].into(),
        workspace_targets: ["clo:lib".to_string()].into(),
        failed_units: BTreeSet::new(),
        owner_disambiguations: 0,
        crates: vec![unit("clo@0.1.0:lib", nodes, edges, spans)],
        binary: false,
        binaries: vec![],
    }
}

/// The workspace and its checkout.
pub struct Clo {
    pub ws: Workspace,
    root: PathBuf,
}

impl Clo {
    pub fn checkout(&self) -> PathBuf {
        self.root.join("src-clo")
    }

    pub fn at(&self) -> (i64, String) {
        let log = self.ws.room.log().unwrap();
        let o = log.block_on(log.offsets()).unwrap().remove(CLO).expect("clo is consumed");
        (o.seq, o.sha)
    }

    /// The `clone_shapes` feed for `clo`, as the consumer runs it.
    pub fn shapes(&self) -> crate::clone_signals::feed::ShapeRun {
        let (seq, sha) = self.at();
        let log = self.ws.room.log().unwrap();
        crate::clone_signals::feed::shapes_member(&self.ws.warehouse, &log, CLO, &self.checkout(), seq, &sha).unwrap()
    }

    /// The raw vectors (the `embeddings` feed's function half) and the
    /// normalised ones (`clone_shapes`' deferred half), both through `bag`.
    pub fn embed(&self, bag: &super::vectors::Bag) -> crate::clone_signals::feed::NormRun {
        let (seq, sha) = self.at();
        let log = self.ws.room.log().unwrap();
        let mut embedding = crate::vector::fnvec::Loaded { embedder: bag, backend: "test bag (cpu)" };
        crate::vector::fnvec::room::embed_member_with(&self.ws.warehouse, &log, CLO, &self.checkout(), seq, &sha, &mut embedding).unwrap();
        let chunks = crate::clone_signals::feed::read_chunks(&log, CLO, &self.checkout(), seq).unwrap();
        crate::clone_signals::feed::embed_normalised(&self.ws.warehouse, &chunks, &mut embedding).unwrap()
    }

    /// Consume `clo`'s second commit: `summarize` gets another body.
    pub fn second_commit(&self) {
        self.commit_v(1);
    }

    /// Consume the next commit of `clo` at fixture variant `v` (module docs).
    pub fn commit_v(&self, v: u8) {
        let dir = self.checkout();
        let dump = commit(&dir, v);
        nornir_git::gitio::commit_all(&dir, &format!("variant {v}")).unwrap();
        consume_next(&self.ws.room, &dir, CLO, dump);
    }
}

/// `clo` consumed at its first commit; no shape, no vector yet.
pub fn build() -> Clo {
    let tmp = tempfile::tempdir().unwrap();
    let root = tmp.path().to_path_buf();
    let builds = root.join("builds");
    std::fs::create_dir_all(&builds).unwrap();
    let warehouse = IcebergWarehouse::open(&builds).unwrap();
    let room = CodeRoom::new("clones", &builds);
    let dir = root.join("src-clo");
    nornir_git::gitio::init(&dir).unwrap();
    let dump = commit(&dir, 0);
    nornir_git::gitio::commit_all(&dir, "first").unwrap();
    consume_next(&room, &dir, CLO, dump);
    Clo { ws: Workspace { room, warehouse, builds, _tmp: tmp }, root }
}