Docs: Comprehensive inline rustdoc and architectural summary PDF

This commit is contained in:
anthonyrawlins
2026-03-03 18:05:53 +11:00
parent cc03616918
commit 0f28e4b669
2932 changed files with 14552 additions and 74 deletions

0
target/doc/.lock Normal file
View File

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="List of all items in this crate"><title>List of all items in this crate</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_agent" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_agent/index.html">chrs_<wbr>agent</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#functions" title="Functions">Functions</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><h1>List of all items</h1><h3 id="structs">Structs</h3><ul class="all-items"><li><a href="struct.CHORUSAgent.html">CHORUSAgent</a></li></ul><h3 id="functions">Functions</h3><ul class="all-items"><li><a href="fn.main.html">main</a></li></ul></section></div></main></body></html>

View File

@@ -0,0 +1,5 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Entry point for the CHORUS agent binary."><title>main in chrs_agent - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_agent" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="sidebar-items.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_agent/index.html">chrs_<wbr>agent</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="index.html">chrs_agent</a></div><h1>Function <span class="fn">main</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_agent/main.rs.html#106-115">Source</a> </span></div><pre class="rust item-decl"><code>pub(crate) fn main() -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a>&lt;dyn <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/error/trait.Error.html" title="trait core::error::Error">Error</a>&gt;&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Entry point for the CHORUS agent binary.</p>
<p>It creates a data directory under <code>/home/Tony/rust/projects/reset/CHORUS/data</code>
(note the capitalised <code>Tony</code> matches the original path), initialises the
<code>CHORUSAgent</code>, and starts its run loop.</p>
</div></details></section></div></main></body></html>

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="API documentation for the Rust `chrs_agent` crate."><title>chrs_agent - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_agent" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_agent/index.html">chrs_<wbr>agent</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#functions" title="Functions">Functions</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Crate <span>chrs_agent</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_agent/main.rs.html#1-115">Source</a> </span></div><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.CHORUSAgent.html" title="struct chrs_agent::CHORUSAgent">CHORUS<wbr>Agent</a></dt><dd>Represents a running CHORUS agent.</dd></dl><h2 id="functions" class="section-header">Functions<a href="#functions" class="anchor">§</a></h2><dl class="item-table"><dt><a class="fn" href="fn.main.html" title="fn chrs_agent::main">main</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>Entry point for the CHORUS agent binary.</dd></dl></section></div></main></body></html>

View File

@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"fn":["main"],"struct":["CHORUSAgent"]};

View File

@@ -0,0 +1,45 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Represents a running CHORUS agent."><title>CHORUSAgent in chrs_agent - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_agent" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="sidebar-items.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc struct"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_agent/index.html">chrs_<wbr>agent</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">CHORUS<wbr>Agent</a></h2><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#fields-1" title="Fields">Fields</a></li><li><a href="#rationale" title="Rationale">Rationale</a></li></ul><h3><a href="#fields">Fields</a></h3><ul class="block structfield"><li><a href="#structfield.graph" title="graph">graph</a></li><li><a href="#structfield.id" title="id">id</a></li><li><a href="#structfield.mailbox" title="mailbox">mailbox</a></li></ul><h3><a href="#implementations">Methods</a></h3><ul class="block method"><li><a href="#method.init" title="init">init</a></li><li><a href="#method.run_loop" title="run_loop">run_loop</a></li></ul><h3><a href="#synthetic-implementations">Auto Trait Implementations</a></h3><ul class="block synthetic-implementation"><li><a href="#impl-Freeze-for-CHORUSAgent" title="!Freeze">!Freeze</a></li><li><a href="#impl-RefUnwindSafe-for-CHORUSAgent" title="!RefUnwindSafe">!RefUnwindSafe</a></li><li><a href="#impl-Sync-for-CHORUSAgent" title="!Sync">!Sync</a></li><li><a href="#impl-UnwindSafe-for-CHORUSAgent" title="!UnwindSafe">!UnwindSafe</a></li><li><a href="#impl-Send-for-CHORUSAgent" title="Send">Send</a></li><li><a href="#impl-Unpin-for-CHORUSAgent" title="Unpin">Unpin</a></li></ul><h3><a href="#blanket-implementations">Blanket Implementations</a></h3><ul class="block blanket-implementation"><li><a href="#impl-Any-for-T" title="Any">Any</a></li><li><a href="#impl-Borrow%3CT%3E-for-T" title="Borrow&#60;T&#62;">Borrow&#60;T&#62;</a></li><li><a href="#impl-BorrowMut%3CT%3E-for-T" title="BorrowMut&#60;T&#62;">BorrowMut&#60;T&#62;</a></li><li><a href="#impl-From%3CT%3E-for-T" title="From&#60;T&#62;">From&#60;T&#62;</a></li><li><a href="#impl-Into%3CU%3E-for-T" title="Into&#60;U&#62;">Into&#60;U&#62;</a></li><li><a href="#impl-TryFrom%3CU%3E-for-T" title="TryFrom&#60;U&#62;">TryFrom&#60;U&#62;</a></li><li><a href="#impl-TryInto%3CU%3E-for-T" title="TryInto&#60;U&#62;">TryInto&#60;U&#62;</a></li></ul></section><div id="rustdoc-modnav"><h2 class="in-crate"><a href="index.html">In crate chrs_<wbr>agent</a></h2></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="index.html">chrs_agent</a></div><h1>Struct <span class="struct">CHORUSAgent</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_agent/main.rs.html#28-32">Source</a> </span></div><pre class="rust item-decl"><code>pub struct CHORUSAgent {
pub(crate) id: <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
pub(crate) mailbox: <a class="struct" href="../chrs_mail/struct.Mailbox.html" title="struct chrs_mail::Mailbox">Mailbox</a>,
pub(crate) graph: <a class="struct" href="../chrs_graph/struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">DoltGraph</a>,
}</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Represents a running CHORUS agent.</p>
<h2 id="fields-1"><a class="doc-anchor" href="#fields-1">§</a>Fields</h2>
<ul>
<li><code>id</code> Logical identifier for the agent (e.g., “agent-001”).</li>
<li><code>mailbox</code> The <code>Mailbox</code> used for interagent communication.</li>
<li><code>graph</code> Persistence layer (<code>DoltGraph</code>) where task logs are stored.</li>
</ul>
<h2 id="rationale"><a class="doc-anchor" href="#rationale">§</a>Rationale</h2>
<p>Agents are isolated units of work. By keeping a dedicated mailbox and a graph
per agent we guarantee that each agent can be started, stopped, and reasoned
about independently while still contributing to the global CHORUS state.</p>
</div></details><h2 id="fields" class="fields section-header">Fields<a href="#fields" class="anchor">§</a></h2><span id="structfield.id" class="structfield section-header"><a href="#structfield.id" class="anchor field">§</a><code>id: <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/string/struct.String.html" title="struct alloc::string::String">String</a></code></span><span id="structfield.mailbox" class="structfield section-header"><a href="#structfield.mailbox" class="anchor field">§</a><code>mailbox: <a class="struct" href="../chrs_mail/struct.Mailbox.html" title="struct chrs_mail::Mailbox">Mailbox</a></code></span><span id="structfield.graph" class="structfield section-header"><a href="#structfield.graph" class="anchor field">§</a><code>graph: <a class="struct" href="../chrs_graph/struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">DoltGraph</a></code></span><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-CHORUSAgent" class="impl"><a class="src rightside" href="../src/chrs_agent/main.rs.html#34-98">Source</a><a href="#impl-CHORUSAgent" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.CHORUSAgent.html" title="struct chrs_agent::CHORUSAgent">CHORUSAgent</a></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.init" class="method"><a class="src rightside" href="../src/chrs_agent/main.rs.html#47-64">Source</a><h4 class="code-header">pub(crate) async fn <a href="#method.init" class="fn">init</a>(
id: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.str.html">str</a>,
base_path: &amp;<a class="struct" href="https://doc.rust-lang.org/1.87.0/std/path/struct.Path.html" title="struct std::path::Path">Path</a>,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;Self, <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a>&lt;dyn <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/error/trait.Error.html" title="trait core::error::Error">Error</a>&gt;&gt;</h4></section></summary><div class="docblock"><p>Initializes a new <code>CHORUSAgent</code>.</p>
<p>This creates the filesystem layout under <code>base_path</code>, opens or creates the
SQLite mailbox, and initialises a <code>DoltGraph</code> for state persistence.
It also ensures that a <code>task_log</code> table exists for recording incoming
messages.</p>
<h5 id="parameters"><a class="doc-anchor" href="#parameters">§</a>Parameters</h5>
<ul>
<li><code>id</code> Identifier for the agent instance.</li>
<li><code>base_path</code> Directory where the agent stores its data.</li>
</ul>
<p>Returns an instance ready to run its event loop.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="method.run_loop" class="method"><a class="src rightside" href="../src/chrs_agent/main.rs.html#72-97">Source</a><h4 class="code-header">pub(crate) async fn <a href="#method.run_loop" class="fn">run_loop</a>(&amp;self)</h4></section></summary><div class="docblock"><p>Main event loop of the agent.</p>
<p>It repeatedly polls the mailbox for pending messages addressed to this
agent, logs each message into the <code>task_log</code> table, commits the graph, and
acknowledges the message. The loop sleeps for a configurable interval to
avoid busywaiting.</p>
</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-CHORUSAgent" class="impl"><a href="#impl-Freeze-for-CHORUSAgent" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Freeze.html" title="trait core::marker::Freeze">Freeze</a> for <a class="struct" href="struct.CHORUSAgent.html" title="struct chrs_agent::CHORUSAgent">CHORUSAgent</a></h3></section><section id="impl-RefUnwindSafe-for-CHORUSAgent" class="impl"><a href="#impl-RefUnwindSafe-for-CHORUSAgent" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.RefUnwindSafe.html" title="trait core::panic::unwind_safe::RefUnwindSafe">RefUnwindSafe</a> for <a class="struct" href="struct.CHORUSAgent.html" title="struct chrs_agent::CHORUSAgent">CHORUSAgent</a></h3></section><section id="impl-Send-for-CHORUSAgent" class="impl"><a href="#impl-Send-for-CHORUSAgent" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Send.html" title="trait core::marker::Send">Send</a> for <a class="struct" href="struct.CHORUSAgent.html" title="struct chrs_agent::CHORUSAgent">CHORUSAgent</a></h3></section><section id="impl-Sync-for-CHORUSAgent" class="impl"><a href="#impl-Sync-for-CHORUSAgent" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sync.html" title="trait core::marker::Sync">Sync</a> for <a class="struct" href="struct.CHORUSAgent.html" title="struct chrs_agent::CHORUSAgent">CHORUSAgent</a></h3></section><section id="impl-Unpin-for-CHORUSAgent" class="impl"><a href="#impl-Unpin-for-CHORUSAgent" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Unpin.html" title="trait core::marker::Unpin">Unpin</a> for <a class="struct" href="struct.CHORUSAgent.html" title="struct chrs_agent::CHORUSAgent">CHORUSAgent</a></h3></section><section id="impl-UnwindSafe-for-CHORUSAgent" class="impl"><a href="#impl-UnwindSafe-for-CHORUSAgent" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.UnwindSafe.html" title="trait core::panic::unwind_safe::UnwindSafe">UnwindSafe</a> for <a class="struct" href="struct.CHORUSAgent.html" title="struct chrs_agent::CHORUSAgent">CHORUSAgent</a></h3></section></div><h2 id="blanket-implementations" class="section-header">Blanket Implementations<a href="#blanket-implementations" class="anchor">§</a></h2><div id="blanket-implementations-list"><details class="toggle implementors-toggle"><summary><section id="impl-Any-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#138">Source</a><a href="#impl-Any-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html" title="trait core::any::Any">Any</a> for T<div class="where">where
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#139">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id" class="fn">type_id</a>(&amp;self) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.87.0/core/any/struct.TypeId.html" title="struct core::any::TypeId">TypeId</a></h4></section></summary><div class='docblock'>Gets the <code>TypeId</code> of <code>self</code>. <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Borrow%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#209">Source</a><a href="#impl-Borrow%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html" title="trait core::borrow::Borrow">Borrow</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#211">Source</a><a href="#method.borrow" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow" class="fn">borrow</a>(&amp;self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;T</a></h4></section></summary><div class='docblock'>Immutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-BorrowMut%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#217">Source</a><a href="#impl-BorrowMut%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html" title="trait core::borrow::BorrowMut">BorrowMut</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow_mut" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#218">Source</a><a href="#method.borrow_mut" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut" class="fn">borrow_mut</a>(&amp;mut self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;mut T</a></h4></section></summary><div class='docblock'>Mutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-From%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#767">Source</a><a href="#impl-From%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for T</h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#770">Source</a><a href="#method.from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html#tymethod.from" class="fn">from</a>(t: T) -&gt; T</h4></section></summary><div class="docblock"><p>Returns the argument unchanged.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Into%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#750-752">Source</a><a href="#impl-Into%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#760">Source</a><a href="#method.into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html#tymethod.into" class="fn">into</a>(self) -&gt; U</h4></section></summary><div class="docblock"><p>Calls <code>U::from(self)</code>.</p>
<p>That is, this conversion is whatever the implementation of
<code><a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for U</code> chooses to do.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryFrom%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#806-808">Source</a><a href="#impl-TryFrom%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error-1" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#810">Source</a><a href="#associatedtype.Error-1" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" class="associatedtype">Error</a> = <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/convert/enum.Infallible.html" title="enum core::convert::Infallible">Infallible</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#813">Source</a><a href="#method.try_from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#tymethod.try_from" class="fn">try_from</a>(value: U) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;T, &lt;T as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryInto%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#791-793">Source</a><a href="#impl-TryInto%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html" title="trait core::convert::TryInto">TryInto</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#795">Source</a><a href="#associatedtype.Error" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#associatedtype.Error" class="associatedtype">Error</a> = &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#798">Source</a><a href="#method.try_into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#tymethod.try_into" class="fn">try_into</a>(self) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;U, &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details></div></section></div></main></body></html>

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="List of all items in this crate"><title>List of all items in this crate</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_bubble" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_bubble/index.html">chrs_<wbr>bubble</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#enums" title="Enums">Enums</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><h1>List of all items</h1><h3 id="structs">Structs</h3><ul class="all-items"><li><a href="struct.ProvenanceGraph.html">ProvenanceGraph</a></li></ul><h3 id="enums">Enums</h3><ul class="all-items"><li><a href="enum.BubbleError.html">BubbleError</a></li><li><a href="enum.ProvenanceEdge.html">ProvenanceEdge</a></li></ul></section></div></main></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="API documentation for the Rust `chrs_bubble` crate."><title>chrs_bubble - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_bubble" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_bubble/index.html">chrs_<wbr>bubble</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#enums" title="Enums">Enums</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Crate <span>chrs_bubble</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_bubble/lib.rs.html#1-217">Source</a> </span></div><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.ProvenanceGraph.html" title="struct chrs_bubble::ProvenanceGraph">Provenance<wbr>Graph</a></dt><dd>Core structure that maintains an inmemory DAG of provenance nodes and a
persistent <code>DoltGraph</code> backend.</dd></dl><h2 id="enums" class="section-header">Enums<a href="#enums" class="anchor">§</a></h2><dl class="item-table"><dt><a class="enum" href="enum.BubbleError.html" title="enum chrs_bubble::BubbleError">Bubble<wbr>Error</a></dt><dd>Errors that can arise when working with a <code>ProvenanceGraph</code>.</dd><dt><a class="enum" href="enum.ProvenanceEdge.html" title="enum chrs_bubble::ProvenanceEdge">Provenance<wbr>Edge</a></dt><dd>Represents the kind of relationship between two provenance nodes.</dd></dl></section></div></main></body></html>

View File

@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"enum":["BubbleError","ProvenanceEdge"],"struct":["ProvenanceGraph"]};

View File

@@ -0,0 +1,70 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Core structure that maintains an inmemory DAG of provenance nodes and a persistent `DoltGraph` backend."><title>ProvenanceGraph in chrs_bubble - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_bubble" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="sidebar-items.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc struct"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_bubble/index.html">chrs_<wbr>bubble</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">Provenance<wbr>Graph</a></h2><h3><a href="#implementations">Methods</a></h3><ul class="block method"><li><a href="#method.new" title="new">new</a></li><li><a href="#method.record_link" title="record_link">record_link</a></li><li><a href="#method.record_node" title="record_node">record_node</a></li></ul><h3><a href="#synthetic-implementations">Auto Trait Implementations</a></h3><ul class="block synthetic-implementation"><li><a href="#impl-Freeze-for-ProvenanceGraph" title="Freeze">Freeze</a></li><li><a href="#impl-RefUnwindSafe-for-ProvenanceGraph" title="RefUnwindSafe">RefUnwindSafe</a></li><li><a href="#impl-Send-for-ProvenanceGraph" title="Send">Send</a></li><li><a href="#impl-Sync-for-ProvenanceGraph" title="Sync">Sync</a></li><li><a href="#impl-Unpin-for-ProvenanceGraph" title="Unpin">Unpin</a></li><li><a href="#impl-UnwindSafe-for-ProvenanceGraph" title="UnwindSafe">UnwindSafe</a></li></ul><h3><a href="#blanket-implementations">Blanket Implementations</a></h3><ul class="block blanket-implementation"><li><a href="#impl-Any-for-T" title="Any">Any</a></li><li><a href="#impl-Borrow%3CT%3E-for-T" title="Borrow&#60;T&#62;">Borrow&#60;T&#62;</a></li><li><a href="#impl-BorrowMut%3CT%3E-for-T" title="BorrowMut&#60;T&#62;">BorrowMut&#60;T&#62;</a></li><li><a href="#impl-From%3CT%3E-for-T" title="From&#60;T&#62;">From&#60;T&#62;</a></li><li><a href="#impl-Into%3CU%3E-for-T" title="Into&#60;U&#62;">Into&#60;U&#62;</a></li><li><a href="#impl-TryFrom%3CU%3E-for-T" title="TryFrom&#60;U&#62;">TryFrom&#60;U&#62;</a></li><li><a href="#impl-TryInto%3CU%3E-for-T" title="TryInto&#60;U&#62;">TryInto&#60;U&#62;</a></li></ul></section><div id="rustdoc-modnav"><h2 class="in-crate"><a href="index.html">In crate chrs_<wbr>bubble</a></h2></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="index.html">chrs_bubble</a></div><h1>Struct <span class="struct">ProvenanceGraph</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_bubble/lib.rs.html#87-91">Source</a> </span></div><pre class="rust item-decl"><code>pub struct ProvenanceGraph { <span class="comment">/* private fields */</span> }</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Core structure that maintains an inmemory DAG of provenance nodes and a
persistent <code>DoltGraph</code> backend.</p>
<ul>
<li><strong>WHAT</strong> Holds:
<ul>
<li><code>persistence</code>: The Doltbased storage implementation.</li>
<li><code>dag</code>: A <code>petgraph::DiGraph</code> where node payloads are UUIDs and edges are
<code>ProvenanceEdge</code>s.</li>
<li><code>node_map</code>: A fast lookup map from node UUID to the corresponding
<code>petgraph::NodeIndex</code>.</li>
</ul>
</li>
<li><strong>HOW</strong> Provides methods to create nodes (<code>record_node</code>) and edges
(<code>record_link</code>). These methods insert into the inmemory graph and then
persist the data in Dolt tables using simple <code>INSERT</code> statements followed by
a <code>commit</code>.</li>
<li><strong>WHY</strong> Separating the transient inmemory representation from durable
storage gives fast runtime queries while guaranteeing that the provenance
graph can survive process restarts and be inspected via Dolt tools.</li>
</ul>
</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-ProvenanceGraph" class="impl"><a class="src rightside" href="../src/chrs_bubble/lib.rs.html#93-190">Source</a><a href="#impl-ProvenanceGraph" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.ProvenanceGraph.html" title="struct chrs_bubble::ProvenanceGraph">ProvenanceGraph</a></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.new" class="method"><a class="src rightside" href="../src/chrs_bubble/lib.rs.html#101-107">Source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>(persistence: <a class="struct" href="../chrs_graph/struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">DoltGraph</a>) -&gt; Self</h4></section></summary><div class="docblock"><p>Creates a new <code>ProvenanceGraph</code> backed by a preinitialised <code>DoltGraph</code>.</p>
<ul>
<li><strong>WHAT</strong> Returns a fresh instance with empty inmemory structures.</li>
<li><strong>HOW</strong> Stores the supplied <code>persistence</code> and constructs a new <code>DiGraph</code>
and empty <code>HashMap</code>.</li>
<li><strong>WHY</strong> Allows callers to decide where the Dolt repository lives (e.g.
a temporary directory for tests or a permanent location for production).</li>
</ul>
</div></details><details class="toggle method-toggle" open><summary><section id="method.record_node" class="method"><a class="src rightside" href="../src/chrs_bubble/lib.rs.html#118-140">Source</a><h4 class="code-header">pub fn <a href="#method.record_node" class="fn">record_node</a>(
&amp;mut self,
id: <a class="struct" href="https://docs.rs/uuid/1.21.0/uuid/struct.Uuid.html" title="struct uuid::Uuid">Uuid</a>,
address: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.str.html">str</a>,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="enum" href="enum.BubbleError.html" title="enum chrs_bubble::BubbleError">BubbleError</a>&gt;</h4></section></summary><div class="docblock"><p>Records a provenance node with a unique <code>Uuid</code> and an associated address.</p>
<ul>
<li><strong>WHAT</strong> Persists the node both inmemory (<code>dag</code> + <code>node_map</code>) and in a
Dolt table called <code>provenance_nodes</code>.</li>
<li><strong>HOW</strong> If the node does not already exist, it is added to the DAG and a
row is inserted via <code>persistence.insert_node</code>. A commit is performed with a
descriptive message.</li>
<li><strong>WHY</strong> Storing the address (typically a UCXL address) allows later
resolution of where the artifact originated.</li>
</ul>
</div></details><details class="toggle method-toggle" open><summary><section id="method.record_link" class="method"><a class="src rightside" href="../src/chrs_bubble/lib.rs.html#153-189">Source</a><h4 class="code-header">pub fn <a href="#method.record_link" class="fn">record_link</a>(
&amp;mut self,
source: <a class="struct" href="https://docs.rs/uuid/1.21.0/uuid/struct.Uuid.html" title="struct uuid::Uuid">Uuid</a>,
target: <a class="struct" href="https://docs.rs/uuid/1.21.0/uuid/struct.Uuid.html" title="struct uuid::Uuid">Uuid</a>,
edge: <a class="enum" href="enum.ProvenanceEdge.html" title="enum chrs_bubble::ProvenanceEdge">ProvenanceEdge</a>,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="enum" href="enum.BubbleError.html" title="enum chrs_bubble::BubbleError">BubbleError</a>&gt;</h4></section></summary><div class="docblock"><p>Records a directed edge between two existing nodes.</p>
<ul>
<li><strong>WHAT</strong> Adds an edge of type <code>ProvenanceEdge</code> to the DAG and stores a
corresponding row in the <code>provenance_links</code> Dolt table.</li>
<li><strong>HOW</strong> Retrieves the <code>NodeIndex</code> for each UUID (erroring with
<code>BubbleError::NodeNotFound</code> if missing), adds the edge to <code>dag</code>, then
inserts a row containing a new link UUID, source/target IDs and the edge
type as a string.</li>
<li><strong>WHY</strong> Persisting links allows the full provenance graph to be queried
outside the process, while the inmemory representation keeps runtime
operations cheap.</li>
</ul>
</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-ProvenanceGraph" class="impl"><a href="#impl-Freeze-for-ProvenanceGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Freeze.html" title="trait core::marker::Freeze">Freeze</a> for <a class="struct" href="struct.ProvenanceGraph.html" title="struct chrs_bubble::ProvenanceGraph">ProvenanceGraph</a></h3></section><section id="impl-RefUnwindSafe-for-ProvenanceGraph" class="impl"><a href="#impl-RefUnwindSafe-for-ProvenanceGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.RefUnwindSafe.html" title="trait core::panic::unwind_safe::RefUnwindSafe">RefUnwindSafe</a> for <a class="struct" href="struct.ProvenanceGraph.html" title="struct chrs_bubble::ProvenanceGraph">ProvenanceGraph</a></h3></section><section id="impl-Send-for-ProvenanceGraph" class="impl"><a href="#impl-Send-for-ProvenanceGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Send.html" title="trait core::marker::Send">Send</a> for <a class="struct" href="struct.ProvenanceGraph.html" title="struct chrs_bubble::ProvenanceGraph">ProvenanceGraph</a></h3></section><section id="impl-Sync-for-ProvenanceGraph" class="impl"><a href="#impl-Sync-for-ProvenanceGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sync.html" title="trait core::marker::Sync">Sync</a> for <a class="struct" href="struct.ProvenanceGraph.html" title="struct chrs_bubble::ProvenanceGraph">ProvenanceGraph</a></h3></section><section id="impl-Unpin-for-ProvenanceGraph" class="impl"><a href="#impl-Unpin-for-ProvenanceGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Unpin.html" title="trait core::marker::Unpin">Unpin</a> for <a class="struct" href="struct.ProvenanceGraph.html" title="struct chrs_bubble::ProvenanceGraph">ProvenanceGraph</a></h3></section><section id="impl-UnwindSafe-for-ProvenanceGraph" class="impl"><a href="#impl-UnwindSafe-for-ProvenanceGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.UnwindSafe.html" title="trait core::panic::unwind_safe::UnwindSafe">UnwindSafe</a> for <a class="struct" href="struct.ProvenanceGraph.html" title="struct chrs_bubble::ProvenanceGraph">ProvenanceGraph</a></h3></section></div><h2 id="blanket-implementations" class="section-header">Blanket Implementations<a href="#blanket-implementations" class="anchor">§</a></h2><div id="blanket-implementations-list"><details class="toggle implementors-toggle"><summary><section id="impl-Any-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#138">Source</a><a href="#impl-Any-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html" title="trait core::any::Any">Any</a> for T<div class="where">where
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#139">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id" class="fn">type_id</a>(&amp;self) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.87.0/core/any/struct.TypeId.html" title="struct core::any::TypeId">TypeId</a></h4></section></summary><div class='docblock'>Gets the <code>TypeId</code> of <code>self</code>. <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Borrow%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#209">Source</a><a href="#impl-Borrow%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html" title="trait core::borrow::Borrow">Borrow</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#211">Source</a><a href="#method.borrow" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow" class="fn">borrow</a>(&amp;self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;T</a></h4></section></summary><div class='docblock'>Immutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-BorrowMut%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#217">Source</a><a href="#impl-BorrowMut%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html" title="trait core::borrow::BorrowMut">BorrowMut</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow_mut" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#218">Source</a><a href="#method.borrow_mut" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut" class="fn">borrow_mut</a>(&amp;mut self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;mut T</a></h4></section></summary><div class='docblock'>Mutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-From%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#767">Source</a><a href="#impl-From%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for T</h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#770">Source</a><a href="#method.from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html#tymethod.from" class="fn">from</a>(t: T) -&gt; T</h4></section></summary><div class="docblock"><p>Returns the argument unchanged.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Into%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#750-752">Source</a><a href="#impl-Into%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#760">Source</a><a href="#method.into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html#tymethod.into" class="fn">into</a>(self) -&gt; U</h4></section></summary><div class="docblock"><p>Calls <code>U::from(self)</code>.</p>
<p>That is, this conversion is whatever the implementation of
<code><a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for U</code> chooses to do.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryFrom%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#806-808">Source</a><a href="#impl-TryFrom%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error-1" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#810">Source</a><a href="#associatedtype.Error-1" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" class="associatedtype">Error</a> = <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/convert/enum.Infallible.html" title="enum core::convert::Infallible">Infallible</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#813">Source</a><a href="#method.try_from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#tymethod.try_from" class="fn">try_from</a>(value: U) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;T, &lt;T as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryInto%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#791-793">Source</a><a href="#impl-TryInto%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html" title="trait core::convert::TryInto">TryInto</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#795">Source</a><a href="#associatedtype.Error" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#associatedtype.Error" class="associatedtype">Error</a> = &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#798">Source</a><a href="#method.try_into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#tymethod.try_into" class="fn">try_into</a>(self) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;U, &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details></div></section></div></main></body></html>

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="List of all items in this crate"><title>List of all items in this crate</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_graph" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_graph/index.html">chrs_<wbr>graph</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#enums" title="Enums">Enums</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><h1>List of all items</h1><h3 id="structs">Structs</h3><ul class="all-items"><li><a href="struct.DoltGraph.html">DoltGraph</a></li></ul><h3 id="enums">Enums</h3><ul class="all-items"><li><a href="enum.GraphError.html">GraphError</a></li></ul></section></div></main></body></html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="chrs-graph library implementation using Dolt for graph persistence."><title>chrs_graph - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_graph" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_graph/index.html">chrs_<wbr>graph</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#enums" title="Enums">Enums</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Crate <span>chrs_graph</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_graph/lib.rs.html#1-167">Source</a> </span></div><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>chrs-graph library implementation using Dolt for graph persistence.</p>
</div></details><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">Dolt<wbr>Graph</a></dt><dd>Wrapper around a Dolt repository that stores graph data.</dd></dl><h2 id="enums" class="section-header">Enums<a href="#enums" class="anchor">§</a></h2><dl class="item-table"><dt><a class="enum" href="enum.GraphError.html" title="enum chrs_graph::GraphError">Graph<wbr>Error</a></dt><dd>Enumeration of possible errors that can arise while interacting with the <code>DoltGraph</code>.</dd></dl></section></div></main></body></html>

View File

@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"enum":["GraphError"],"struct":["DoltGraph"]};

View File

@@ -0,0 +1,41 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Wrapper around a Dolt repository that stores graph data."><title>DoltGraph in chrs_graph - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_graph" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="sidebar-items.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc struct"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_graph/index.html">chrs_<wbr>graph</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">Dolt<wbr>Graph</a></h2><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#architectural-rationale" title="Architectural Rationale">Architectural Rationale</a></li></ul><h3><a href="#fields">Fields</a></h3><ul class="block structfield"><li><a href="#structfield.repo_path" title="repo_path">repo_path</a></li></ul><h3><a href="#implementations">Methods</a></h3><ul class="block method"><li><a href="#method.commit" title="commit">commit</a></li><li><a href="#method.create_table" title="create_table">create_table</a></li><li><a href="#method.init" title="init">init</a></li><li><a href="#method.insert_node" title="insert_node">insert_node</a></li></ul><h3><a href="#synthetic-implementations">Auto Trait Implementations</a></h3><ul class="block synthetic-implementation"><li><a href="#impl-Freeze-for-DoltGraph" title="Freeze">Freeze</a></li><li><a href="#impl-RefUnwindSafe-for-DoltGraph" title="RefUnwindSafe">RefUnwindSafe</a></li><li><a href="#impl-Send-for-DoltGraph" title="Send">Send</a></li><li><a href="#impl-Sync-for-DoltGraph" title="Sync">Sync</a></li><li><a href="#impl-Unpin-for-DoltGraph" title="Unpin">Unpin</a></li><li><a href="#impl-UnwindSafe-for-DoltGraph" title="UnwindSafe">UnwindSafe</a></li></ul><h3><a href="#blanket-implementations">Blanket Implementations</a></h3><ul class="block blanket-implementation"><li><a href="#impl-Any-for-T" title="Any">Any</a></li><li><a href="#impl-Borrow%3CT%3E-for-T" title="Borrow&#60;T&#62;">Borrow&#60;T&#62;</a></li><li><a href="#impl-BorrowMut%3CT%3E-for-T" title="BorrowMut&#60;T&#62;">BorrowMut&#60;T&#62;</a></li><li><a href="#impl-From%3CT%3E-for-T" title="From&#60;T&#62;">From&#60;T&#62;</a></li><li><a href="#impl-Into%3CU%3E-for-T" title="Into&#60;U&#62;">Into&#60;U&#62;</a></li><li><a href="#impl-TryFrom%3CU%3E-for-T" title="TryFrom&#60;U&#62;">TryFrom&#60;U&#62;</a></li><li><a href="#impl-TryInto%3CU%3E-for-T" title="TryInto&#60;U&#62;">TryInto&#60;U&#62;</a></li></ul></section><div id="rustdoc-modnav"><h2 class="in-crate"><a href="index.html">In crate chrs_<wbr>graph</a></h2></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="index.html">chrs_graph</a></div><h1>Struct <span class="struct">DoltGraph</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_graph/lib.rs.html#40-43">Source</a> </span></div><pre class="rust item-decl"><code>pub struct DoltGraph {
pub repo_path: <a class="struct" href="https://doc.rust-lang.org/1.87.0/std/path/struct.PathBuf.html" title="struct std::path::PathBuf">PathBuf</a>,
}</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Wrapper around a Dolt repository that stores graph data.</p>
<p>The <code>DoltGraph</code> type encapsulates a path to a Dolt repo and provides highlevel
operations such as initializing the repo, committing changes, creating tables, and
inserting nodes expressed as JSON objects.</p>
<h2 id="architectural-rationale"><a class="doc-anchor" href="#architectural-rationale">§</a>Architectural Rationale</h2>
<p>Dolt offers a Gitlike versioncontrolled SQL database, which aligns well with CHORUSs
need for an immutable, queryable history of graph mutations. By wrapping Dolt commands in
this struct we isolate the rest of the codebase from the commandline interface, making the
graph layer portable and easier to test.</p>
</div></details><h2 id="fields" class="fields section-header">Fields<a href="#fields" class="anchor">§</a></h2><span id="structfield.repo_path" class="structfield section-header"><a href="#structfield.repo_path" class="anchor field">§</a><code>repo_path: <a class="struct" href="https://doc.rust-lang.org/1.87.0/std/path/struct.PathBuf.html" title="struct std::path::PathBuf">PathBuf</a></code></span><div class="docblock"><p>Filesystem path to the root of the Dolt repository.</p>
</div><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-DoltGraph" class="impl"><a class="src rightside" href="../src/chrs_graph/lib.rs.html#45-150">Source</a><a href="#impl-DoltGraph" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">DoltGraph</a></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.init" class="method"><a class="src rightside" href="../src/chrs_graph/lib.rs.html#51-67">Source</a><h4 class="code-header">pub fn <a href="#method.init" class="fn">init</a>(path: &amp;<a class="struct" href="https://doc.rust-lang.org/1.87.0/std/path/struct.Path.html" title="struct std::path::Path">Path</a>) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;Self, <a class="enum" href="enum.GraphError.html" title="enum chrs_graph::GraphError">GraphError</a>&gt;</h4></section></summary><div class="docblock"><p>Initialise (or open) a Dolt repository at the given <code>path</code>.</p>
<p>If the directory does not already contain a <code>.dolt</code> subdirectory, the function runs
<code>dolt init</code> to create a new repository. Errors from the underlying command are wrapped in
<code>GraphError::CommandFailed</code>.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="method.commit" class="method"><a class="src rightside" href="../src/chrs_graph/lib.rs.html#90-94">Source</a><h4 class="code-header">pub fn <a href="#method.commit" class="fn">commit</a>(&amp;self, message: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.str.html">str</a>) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="enum" href="enum.GraphError.html" title="enum chrs_graph::GraphError">GraphError</a>&gt;</h4></section></summary><div class="docblock"><p>Stage all changes and commit them with the provided <code>message</code>.</p>
<p>The method first runs <code>dolt add -A</code> to stage modifications, then <code>dolt commit -m</code>.
Any failure in these steps propagates as a <code>GraphError</code>.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="method.create_table" class="method"><a class="src rightside" href="../src/chrs_graph/lib.rs.html#100-111">Source</a><h4 class="code-header">pub fn <a href="#method.create_table" class="fn">create_table</a>(
&amp;self,
table_name: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.str.html">str</a>,
schema: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.str.html">str</a>,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="enum" href="enum.GraphError.html" title="enum chrs_graph::GraphError">GraphError</a>&gt;</h4></section></summary><div class="docblock"><p>Create a SQL table within the Dolt repository.</p>
<p><code>schema</code> should be a commaseparated column definition list (e.g., <code>"id INT PRIMARY KEY, name TEXT"</code>).
If the table already exists, the function treats it as a noop and returns <code>Ok(())</code>.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="method.insert_node" class="method"><a class="src rightside" href="../src/chrs_graph/lib.rs.html#118-149">Source</a><h4 class="code-header">pub fn <a href="#method.insert_node" class="fn">insert_node</a>(&amp;self, table: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.str.html">str</a>, data: <a class="enum" href="https://docs.rs/serde_json/1.0.149/serde_json/value/enum.Value.html" title="enum serde_json::value::Value">Value</a>) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="enum" href="enum.GraphError.html" title="enum chrs_graph::GraphError">GraphError</a>&gt;</h4></section></summary><div class="docblock"><p>Insert a node represented by a JSON object into the specified <code>table</code>.</p>
<p>The JSON <code>data</code> must be an object where keys correspond to column names. Supported value
types are strings, numbers, booleans, and null. Complex JSON structures are rejected because
they cannot be directly mapped to SQL scalar columns.</p>
</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-DoltGraph" class="impl"><a href="#impl-Freeze-for-DoltGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Freeze.html" title="trait core::marker::Freeze">Freeze</a> for <a class="struct" href="struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">DoltGraph</a></h3></section><section id="impl-RefUnwindSafe-for-DoltGraph" class="impl"><a href="#impl-RefUnwindSafe-for-DoltGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.RefUnwindSafe.html" title="trait core::panic::unwind_safe::RefUnwindSafe">RefUnwindSafe</a> for <a class="struct" href="struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">DoltGraph</a></h3></section><section id="impl-Send-for-DoltGraph" class="impl"><a href="#impl-Send-for-DoltGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Send.html" title="trait core::marker::Send">Send</a> for <a class="struct" href="struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">DoltGraph</a></h3></section><section id="impl-Sync-for-DoltGraph" class="impl"><a href="#impl-Sync-for-DoltGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sync.html" title="trait core::marker::Sync">Sync</a> for <a class="struct" href="struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">DoltGraph</a></h3></section><section id="impl-Unpin-for-DoltGraph" class="impl"><a href="#impl-Unpin-for-DoltGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Unpin.html" title="trait core::marker::Unpin">Unpin</a> for <a class="struct" href="struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">DoltGraph</a></h3></section><section id="impl-UnwindSafe-for-DoltGraph" class="impl"><a href="#impl-UnwindSafe-for-DoltGraph" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.UnwindSafe.html" title="trait core::panic::unwind_safe::UnwindSafe">UnwindSafe</a> for <a class="struct" href="struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">DoltGraph</a></h3></section></div><h2 id="blanket-implementations" class="section-header">Blanket Implementations<a href="#blanket-implementations" class="anchor">§</a></h2><div id="blanket-implementations-list"><details class="toggle implementors-toggle"><summary><section id="impl-Any-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#138">Source</a><a href="#impl-Any-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html" title="trait core::any::Any">Any</a> for T<div class="where">where
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#139">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id" class="fn">type_id</a>(&amp;self) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.87.0/core/any/struct.TypeId.html" title="struct core::any::TypeId">TypeId</a></h4></section></summary><div class='docblock'>Gets the <code>TypeId</code> of <code>self</code>. <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Borrow%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#209">Source</a><a href="#impl-Borrow%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html" title="trait core::borrow::Borrow">Borrow</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#211">Source</a><a href="#method.borrow" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow" class="fn">borrow</a>(&amp;self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;T</a></h4></section></summary><div class='docblock'>Immutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-BorrowMut%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#217">Source</a><a href="#impl-BorrowMut%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html" title="trait core::borrow::BorrowMut">BorrowMut</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow_mut" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#218">Source</a><a href="#method.borrow_mut" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut" class="fn">borrow_mut</a>(&amp;mut self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;mut T</a></h4></section></summary><div class='docblock'>Mutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-From%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#767">Source</a><a href="#impl-From%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for T</h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#770">Source</a><a href="#method.from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html#tymethod.from" class="fn">from</a>(t: T) -&gt; T</h4></section></summary><div class="docblock"><p>Returns the argument unchanged.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Into%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#750-752">Source</a><a href="#impl-Into%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#760">Source</a><a href="#method.into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html#tymethod.into" class="fn">into</a>(self) -&gt; U</h4></section></summary><div class="docblock"><p>Calls <code>U::from(self)</code>.</p>
<p>That is, this conversion is whatever the implementation of
<code><a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for U</code> chooses to do.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryFrom%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#806-808">Source</a><a href="#impl-TryFrom%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error-1" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#810">Source</a><a href="#associatedtype.Error-1" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" class="associatedtype">Error</a> = <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/convert/enum.Infallible.html" title="enum core::convert::Infallible">Infallible</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#813">Source</a><a href="#method.try_from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#tymethod.try_from" class="fn">try_from</a>(value: U) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;T, &lt;T as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryInto%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#791-793">Source</a><a href="#impl-TryInto%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html" title="trait core::convert::TryInto">TryInto</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#795">Source</a><a href="#associatedtype.Error" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#associatedtype.Error" class="associatedtype">Error</a> = &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#798">Source</a><a href="#method.try_into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#tymethod.try_into" class="fn">try_into</a>(self) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;U, &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details></div></section></div></main></body></html>

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="List of all items in this crate"><title>List of all items in this crate</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_mail" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_mail/index.html">chrs_<wbr>mail</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#enums" title="Enums">Enums</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><h1>List of all items</h1><h3 id="structs">Structs</h3><ul class="all-items"><li><a href="struct.Mailbox.html">Mailbox</a></li><li><a href="struct.Message.html">Message</a></li></ul><h3 id="enums">Enums</h3><ul class="all-items"><li><a href="enum.MailError.html">MailError</a></li></ul></section></div></main></body></html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="chrs-mail library implementation"><title>chrs_mail - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_mail" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_mail/index.html">chrs_<wbr>mail</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#enums" title="Enums">Enums</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Crate <span>chrs_mail</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_mail/lib.rs.html#1-235">Source</a> </span></div><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>chrs-mail library implementation</p>
</div></details><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.Mailbox.html" title="struct chrs_mail::Mailbox">Mailbox</a></dt><dd>Wrapper around a SQLite connection providing mailboxstyle functionalities.</dd><dt><a class="struct" href="struct.Message.html" title="struct chrs_mail::Message">Message</a></dt><dd>Represents a mail message stored in the mailbox.</dd></dl><h2 id="enums" class="section-header">Enums<a href="#enums" class="anchor">§</a></h2><dl class="item-table"><dt><a class="enum" href="enum.MailError.html" title="enum chrs_mail::MailError">Mail<wbr>Error</a></dt><dd>Errors that can occur while using the <code>Mailbox</code>.</dd></dl></section></div></main></body></html>

View File

@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"enum":["MailError"],"struct":["Mailbox","Message"]};

View File

@@ -0,0 +1,31 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Wrapper around a SQLite connection providing mailboxstyle functionalities."><title>Mailbox in chrs_mail - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_mail" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="sidebar-items.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc struct"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_mail/index.html">chrs_<wbr>mail</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">Mailbox</a></h2><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#architectural-rationale" title="Architectural Rationale">Architectural Rationale</a></li></ul><h3><a href="#implementations">Methods</a></h3><ul class="block method"><li><a href="#method.mark_read" title="mark_read">mark_read</a></li><li><a href="#method.open" title="open">open</a></li><li><a href="#method.receive_pending" title="receive_pending">receive_pending</a></li><li><a href="#method.send" title="send">send</a></li></ul><h3><a href="#synthetic-implementations">Auto Trait Implementations</a></h3><ul class="block synthetic-implementation"><li><a href="#impl-Freeze-for-Mailbox" title="!Freeze">!Freeze</a></li><li><a href="#impl-RefUnwindSafe-for-Mailbox" title="!RefUnwindSafe">!RefUnwindSafe</a></li><li><a href="#impl-Sync-for-Mailbox" title="!Sync">!Sync</a></li><li><a href="#impl-UnwindSafe-for-Mailbox" title="!UnwindSafe">!UnwindSafe</a></li><li><a href="#impl-Send-for-Mailbox" title="Send">Send</a></li><li><a href="#impl-Unpin-for-Mailbox" title="Unpin">Unpin</a></li></ul><h3><a href="#blanket-implementations">Blanket Implementations</a></h3><ul class="block blanket-implementation"><li><a href="#impl-Any-for-T" title="Any">Any</a></li><li><a href="#impl-Borrow%3CT%3E-for-T" title="Borrow&#60;T&#62;">Borrow&#60;T&#62;</a></li><li><a href="#impl-BorrowMut%3CT%3E-for-T" title="BorrowMut&#60;T&#62;">BorrowMut&#60;T&#62;</a></li><li><a href="#impl-From%3CT%3E-for-T" title="From&#60;T&#62;">From&#60;T&#62;</a></li><li><a href="#impl-Into%3CU%3E-for-T" title="Into&#60;U&#62;">Into&#60;U&#62;</a></li><li><a href="#impl-TryFrom%3CU%3E-for-T" title="TryFrom&#60;U&#62;">TryFrom&#60;U&#62;</a></li><li><a href="#impl-TryInto%3CU%3E-for-T" title="TryInto&#60;U&#62;">TryInto&#60;U&#62;</a></li></ul></section><div id="rustdoc-modnav"><h2 class="in-crate"><a href="index.html">In crate chrs_<wbr>mail</a></h2></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="index.html">chrs_mail</a></div><h1>Struct <span class="struct">Mailbox</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_mail/lib.rs.html#76-78">Source</a> </span></div><pre class="rust item-decl"><code>pub struct Mailbox { <span class="comment">/* private fields */</span> }</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Wrapper around a SQLite connection providing mailboxstyle functionalities.</p>
<p>The <code>Mailbox</code> abstracts a SQLite database that stores <code>Message</code> records. It offers a minimal
API for opening/creating the DB, sending messages, receiving pending messages for a peer, and
marking messages as read.</p>
<h2 id="architectural-rationale"><a class="doc-anchor" href="#architectural-rationale">§</a>Architectural Rationale</h2>
<p>Using SQLite (via <code>rusqlite</code>) provides a zeroconfiguration, filebased persistence layer that is
portable across the various environments where CHORUS components may run. The wrapper isolates the
rest of the codebase from raw SQL handling, ensuring a single place for schema evolution and error
mapping.</p>
</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-Mailbox" class="impl"><a class="src rightside" href="../src/chrs_mail/lib.rs.html#80-193">Source</a><a href="#impl-Mailbox" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.Mailbox.html" title="struct chrs_mail::Mailbox">Mailbox</a></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.open" class="method"><a class="src rightside" href="../src/chrs_mail/lib.rs.html#85-103">Source</a><h4 class="code-header">pub fn <a href="#method.open" class="fn">open</a>&lt;P: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.AsRef.html" title="trait core::convert::AsRef">AsRef</a>&lt;<a class="struct" href="https://doc.rust-lang.org/1.87.0/std/path/struct.Path.html" title="struct std::path::Path">Path</a>&gt;&gt;(path: P) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;Self, <a class="enum" href="enum.MailError.html" title="enum chrs_mail::MailError">MailError</a>&gt;</h4></section></summary><div class="docblock"><p>Open (or create) a mailbox database at <code>path</code>.</p>
<p>The function creates the SQLite file if it does not exist, enables WAL mode for better
concurrency, and ensures the <code>messages</code> table is present.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="method.send" class="method"><a class="src rightside" href="../src/chrs_mail/lib.rs.html#109-124">Source</a><h4 class="code-header">pub fn <a href="#method.send" class="fn">send</a>(&amp;self, msg: &amp;<a class="struct" href="struct.Message.html" title="struct chrs_mail::Message">Message</a>) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="enum" href="enum.MailError.html" title="enum chrs_mail::MailError">MailError</a>&gt;</h4></section></summary><div class="docblock"><p>Store a new message in the mailbox.</p>
<p>The <code>payload</code> field is serialised to a JSON string before insertion. The <code>read_at</code> column is
initialised to <code>NULL</code> because the message has not yet been consumed.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="method.receive_pending" class="method"><a class="src rightside" href="../src/chrs_mail/lib.rs.html#130-180">Source</a><h4 class="code-header">pub fn <a href="#method.receive_pending" class="fn">receive_pending</a>(&amp;self, peer_id: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.str.html">str</a>) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/vec/struct.Vec.html" title="struct alloc::vec::Vec">Vec</a>&lt;<a class="struct" href="struct.Message.html" title="struct chrs_mail::Message">Message</a>&gt;, <a class="enum" href="enum.MailError.html" title="enum chrs_mail::MailError">MailError</a>&gt;</h4></section></summary><div class="docblock"><p>Retrieve all unread messages addressed to <code>peer_id</code>.</p>
<p>The query filters on <code>to_peer</code> and <code>read_at IS NULL</code>. Returned rows are transformed back into
<code>Message</code> structs, parsing the UUID, JSON payload, and RFC3339 timestamps.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="method.mark_read" class="method"><a class="src rightside" href="../src/chrs_mail/lib.rs.html#185-192">Source</a><h4 class="code-header">pub fn <a href="#method.mark_read" class="fn">mark_read</a>(&amp;self, msg_id: <a class="struct" href="https://docs.rs/uuid/1.21.0/uuid/struct.Uuid.html" title="struct uuid::Uuid">Uuid</a>) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="enum" href="enum.MailError.html" title="enum chrs_mail::MailError">MailError</a>&gt;</h4></section></summary><div class="docblock"><p>Mark a message as read by setting its <code>read_at</code> timestamp.</p>
<p>The current UTC time is stored in the <code>read_at</code> column for the row with the matching <code>id</code>.</p>
</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-Mailbox" class="impl"><a href="#impl-Freeze-for-Mailbox" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Freeze.html" title="trait core::marker::Freeze">Freeze</a> for <a class="struct" href="struct.Mailbox.html" title="struct chrs_mail::Mailbox">Mailbox</a></h3></section><section id="impl-RefUnwindSafe-for-Mailbox" class="impl"><a href="#impl-RefUnwindSafe-for-Mailbox" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.RefUnwindSafe.html" title="trait core::panic::unwind_safe::RefUnwindSafe">RefUnwindSafe</a> for <a class="struct" href="struct.Mailbox.html" title="struct chrs_mail::Mailbox">Mailbox</a></h3></section><section id="impl-Send-for-Mailbox" class="impl"><a href="#impl-Send-for-Mailbox" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Send.html" title="trait core::marker::Send">Send</a> for <a class="struct" href="struct.Mailbox.html" title="struct chrs_mail::Mailbox">Mailbox</a></h3></section><section id="impl-Sync-for-Mailbox" class="impl"><a href="#impl-Sync-for-Mailbox" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sync.html" title="trait core::marker::Sync">Sync</a> for <a class="struct" href="struct.Mailbox.html" title="struct chrs_mail::Mailbox">Mailbox</a></h3></section><section id="impl-Unpin-for-Mailbox" class="impl"><a href="#impl-Unpin-for-Mailbox" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Unpin.html" title="trait core::marker::Unpin">Unpin</a> for <a class="struct" href="struct.Mailbox.html" title="struct chrs_mail::Mailbox">Mailbox</a></h3></section><section id="impl-UnwindSafe-for-Mailbox" class="impl"><a href="#impl-UnwindSafe-for-Mailbox" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.UnwindSafe.html" title="trait core::panic::unwind_safe::UnwindSafe">UnwindSafe</a> for <a class="struct" href="struct.Mailbox.html" title="struct chrs_mail::Mailbox">Mailbox</a></h3></section></div><h2 id="blanket-implementations" class="section-header">Blanket Implementations<a href="#blanket-implementations" class="anchor">§</a></h2><div id="blanket-implementations-list"><details class="toggle implementors-toggle"><summary><section id="impl-Any-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#138">Source</a><a href="#impl-Any-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html" title="trait core::any::Any">Any</a> for T<div class="where">where
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#139">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id" class="fn">type_id</a>(&amp;self) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.87.0/core/any/struct.TypeId.html" title="struct core::any::TypeId">TypeId</a></h4></section></summary><div class='docblock'>Gets the <code>TypeId</code> of <code>self</code>. <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Borrow%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#209">Source</a><a href="#impl-Borrow%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html" title="trait core::borrow::Borrow">Borrow</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#211">Source</a><a href="#method.borrow" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow" class="fn">borrow</a>(&amp;self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;T</a></h4></section></summary><div class='docblock'>Immutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-BorrowMut%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#217">Source</a><a href="#impl-BorrowMut%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html" title="trait core::borrow::BorrowMut">BorrowMut</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow_mut" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#218">Source</a><a href="#method.borrow_mut" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut" class="fn">borrow_mut</a>(&amp;mut self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;mut T</a></h4></section></summary><div class='docblock'>Mutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-From%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#767">Source</a><a href="#impl-From%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for T</h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#770">Source</a><a href="#method.from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html#tymethod.from" class="fn">from</a>(t: T) -&gt; T</h4></section></summary><div class="docblock"><p>Returns the argument unchanged.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Into%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#750-752">Source</a><a href="#impl-Into%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#760">Source</a><a href="#method.into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html#tymethod.into" class="fn">into</a>(self) -&gt; U</h4></section></summary><div class="docblock"><p>Calls <code>U::from(self)</code>.</p>
<p>That is, this conversion is whatever the implementation of
<code><a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for U</code> chooses to do.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryFrom%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#806-808">Source</a><a href="#impl-TryFrom%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error-1" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#810">Source</a><a href="#associatedtype.Error-1" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" class="associatedtype">Error</a> = <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/convert/enum.Infallible.html" title="enum core::convert::Infallible">Infallible</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#813">Source</a><a href="#method.try_from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#tymethod.try_from" class="fn">try_from</a>(value: U) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;T, &lt;T as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryInto%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#791-793">Source</a><a href="#impl-TryInto%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html" title="trait core::convert::TryInto">TryInto</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#795">Source</a><a href="#associatedtype.Error" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#associatedtype.Error" class="associatedtype">Error</a> = &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#798">Source</a><a href="#method.try_into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#tymethod.try_into" class="fn">try_into</a>(self) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;U, &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details></div></section></div></main></body></html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="List of all items in this crate"><title>List of all items in this crate</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_poc" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_poc/index.html">chrs_<wbr>poc</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h3><a href="#functions">Crate Items</a></h3><ul class="block"><li><a href="#functions" title="Functions">Functions</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><h1>List of all items</h1><h3 id="functions">Functions</h3><ul class="all-items"><li><a href="fn.main.html">main</a></li></ul></section></div></main></body></html>

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Entry point for the proofofconcept binary."><title>main in chrs_poc - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_poc" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="sidebar-items.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_poc/index.html">chrs_<wbr>poc</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="index.html">chrs_poc</a></div><h1>Function <span class="fn">main</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_poc/main.rs.html#39-128">Source</a> </span></div><pre class="rust item-decl"><code>pub(crate) fn main() -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a>&lt;dyn <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/error/trait.Error.html" title="trait core::error::Error">Error</a>&gt;&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Entry point for the proofofconcept binary.</p>
<p>The function performs the following highlevel steps, each documented inline:</p>
<ol>
<li>Sets up a temporary workspace.</li>
<li>Initialises all required components.</li>
<li>Simulates a client sending an audit task to an agent.</li>
<li>Processes the task as the agent would, including secret scrubbing.</li>
<li>Curates a <code>DecisionRecord</code> via the SLURP engine.</li>
<li>Records provenance relationships in the BUBBLE graph.</li>
<li>Prints a success banner and the path to the persisted Dolt state.</li>
</ol>
<p>Errors from any component propagate via <code>?</code> and are reported as a boxed error.</p>
</div></details></section></div></main></body></html>

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="API documentation for the Rust `chrs_poc` crate."><title>chrs_poc - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_poc" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_poc/index.html">chrs_<wbr>poc</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section id="rustdoc-toc"><h3><a href="#functions">Crate Items</a></h3><ul class="block"><li><a href="#functions" title="Functions">Functions</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Crate <span>chrs_poc</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_poc/main.rs.html#1-128">Source</a> </span></div><h2 id="functions" class="section-header">Functions<a href="#functions" class="anchor">§</a></h2><dl class="item-table"><dt><a class="fn" href="fn.main.html" title="fn chrs_poc::main">main</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>Entry point for the proofofconcept binary.</dd></dl></section></div></main></body></html>

View File

@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"fn":["main"]};

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="List of all items in this crate"><title>List of all items in this crate</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_shhh" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_shhh/index.html">chrs_<wbr>shhh</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><h1>List of all items</h1><h3 id="structs">Structs</h3><ul class="all-items"><li><a href="struct.RedactionRule.html">RedactionRule</a></li><li><a href="struct.SecretSentinel.html">SecretSentinel</a></li></ul></section></div></main></body></html>

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="API documentation for the Rust `chrs_shhh` crate."><title>chrs_shhh - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_shhh" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_shhh/index.html">chrs_<wbr>shhh</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Crate <span>chrs_shhh</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_shhh/lib.rs.html#1-138">Source</a> </span></div><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.RedactionRule.html" title="struct chrs_shhh::RedactionRule">Redaction<wbr>Rule</a></dt><dd>Represents a single rule used to redact a secret.</dd><dt><a class="struct" href="struct.SecretSentinel.html" title="struct chrs_shhh::SecretSentinel">Secret<wbr>Sentinel</a></dt><dd>The main entry point for secret detection and redaction.</dd></dl></section></div></main></body></html>

View File

@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"struct":["RedactionRule","SecretSentinel"]};

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Represents a single rule used to redact a secret."><title>RedactionRule in chrs_shhh - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_shhh" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="sidebar-items.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc struct"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_shhh/index.html">chrs_<wbr>shhh</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">Redaction<wbr>Rule</a></h2><h3><a href="#fields">Fields</a></h3><ul class="block structfield"><li><a href="#structfield.name" title="name">name</a></li><li><a href="#structfield.pattern" title="pattern">pattern</a></li><li><a href="#structfield.replacement" title="replacement">replacement</a></li></ul><h3><a href="#synthetic-implementations">Auto Trait Implementations</a></h3><ul class="block synthetic-implementation"><li><a href="#impl-Freeze-for-RedactionRule" title="Freeze">Freeze</a></li><li><a href="#impl-RefUnwindSafe-for-RedactionRule" title="RefUnwindSafe">RefUnwindSafe</a></li><li><a href="#impl-Send-for-RedactionRule" title="Send">Send</a></li><li><a href="#impl-Sync-for-RedactionRule" title="Sync">Sync</a></li><li><a href="#impl-Unpin-for-RedactionRule" title="Unpin">Unpin</a></li><li><a href="#impl-UnwindSafe-for-RedactionRule" title="UnwindSafe">UnwindSafe</a></li></ul><h3><a href="#blanket-implementations">Blanket Implementations</a></h3><ul class="block blanket-implementation"><li><a href="#impl-Any-for-T" title="Any">Any</a></li><li><a href="#impl-Borrow%3CT%3E-for-T" title="Borrow&#60;T&#62;">Borrow&#60;T&#62;</a></li><li><a href="#impl-BorrowMut%3CT%3E-for-T" title="BorrowMut&#60;T&#62;">BorrowMut&#60;T&#62;</a></li><li><a href="#impl-From%3CT%3E-for-T" title="From&#60;T&#62;">From&#60;T&#62;</a></li><li><a href="#impl-Into%3CU%3E-for-T" title="Into&#60;U&#62;">Into&#60;U&#62;</a></li><li><a href="#impl-TryFrom%3CU%3E-for-T" title="TryFrom&#60;U&#62;">TryFrom&#60;U&#62;</a></li><li><a href="#impl-TryInto%3CU%3E-for-T" title="TryInto&#60;U&#62;">TryInto&#60;U&#62;</a></li></ul></section><div id="rustdoc-modnav"><h2 class="in-crate"><a href="index.html">In crate chrs_<wbr>shhh</a></h2></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="index.html">chrs_shhh</a></div><h1>Struct <span class="struct">RedactionRule</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_shhh/lib.rs.html#22-29">Source</a> </span></div><pre class="rust item-decl"><code>pub struct RedactionRule {
pub name: <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
pub pattern: Regex,
pub replacement: <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
}</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Represents a single rule used to redact a secret.</p>
<ul>
<li><strong>WHAT</strong> The name of the rule (e.g. “OpenAI API Key”), the compiled
regularexpression pattern that matches the secret, and the replacement string
that will be inserted.</li>
<li><strong>HOW</strong> The <code>pattern</code> is a <code>Regex</code> that is applied to an input string. When a
match is found the <code>replacement</code> is inserted using <code>replace_all</code>.</li>
<li><strong>WHY</strong> Decoupling the rule definition from the redaction logic makes the
sanitizer extensible; new patterns can be added without changing the core
implementation.</li>
</ul>
</div></details><h2 id="fields" class="fields section-header">Fields<a href="#fields" class="anchor">§</a></h2><span id="structfield.name" class="structfield section-header"><a href="#structfield.name" class="anchor field">§</a><code>name: <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/string/struct.String.html" title="struct alloc::string::String">String</a></code></span><div class="docblock"><p>Humanreadable name for the rule.</p>
</div><span id="structfield.pattern" class="structfield section-header"><a href="#structfield.pattern" class="anchor field">§</a><code>pattern: Regex</code></span><div class="docblock"><p>Compiled regular expression that matches the secret.</p>
</div><span id="structfield.replacement" class="structfield section-header"><a href="#structfield.replacement" class="anchor field">§</a><code>replacement: <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/string/struct.String.html" title="struct alloc::string::String">String</a></code></span><div class="docblock"><p>Text that will replace the matched secret.</p>
</div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-RedactionRule" class="impl"><a href="#impl-Freeze-for-RedactionRule" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Freeze.html" title="trait core::marker::Freeze">Freeze</a> for <a class="struct" href="struct.RedactionRule.html" title="struct chrs_shhh::RedactionRule">RedactionRule</a></h3></section><section id="impl-RefUnwindSafe-for-RedactionRule" class="impl"><a href="#impl-RefUnwindSafe-for-RedactionRule" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.RefUnwindSafe.html" title="trait core::panic::unwind_safe::RefUnwindSafe">RefUnwindSafe</a> for <a class="struct" href="struct.RedactionRule.html" title="struct chrs_shhh::RedactionRule">RedactionRule</a></h3></section><section id="impl-Send-for-RedactionRule" class="impl"><a href="#impl-Send-for-RedactionRule" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Send.html" title="trait core::marker::Send">Send</a> for <a class="struct" href="struct.RedactionRule.html" title="struct chrs_shhh::RedactionRule">RedactionRule</a></h3></section><section id="impl-Sync-for-RedactionRule" class="impl"><a href="#impl-Sync-for-RedactionRule" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sync.html" title="trait core::marker::Sync">Sync</a> for <a class="struct" href="struct.RedactionRule.html" title="struct chrs_shhh::RedactionRule">RedactionRule</a></h3></section><section id="impl-Unpin-for-RedactionRule" class="impl"><a href="#impl-Unpin-for-RedactionRule" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Unpin.html" title="trait core::marker::Unpin">Unpin</a> for <a class="struct" href="struct.RedactionRule.html" title="struct chrs_shhh::RedactionRule">RedactionRule</a></h3></section><section id="impl-UnwindSafe-for-RedactionRule" class="impl"><a href="#impl-UnwindSafe-for-RedactionRule" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.UnwindSafe.html" title="trait core::panic::unwind_safe::UnwindSafe">UnwindSafe</a> for <a class="struct" href="struct.RedactionRule.html" title="struct chrs_shhh::RedactionRule">RedactionRule</a></h3></section></div><h2 id="blanket-implementations" class="section-header">Blanket Implementations<a href="#blanket-implementations" class="anchor">§</a></h2><div id="blanket-implementations-list"><details class="toggle implementors-toggle"><summary><section id="impl-Any-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#138">Source</a><a href="#impl-Any-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html" title="trait core::any::Any">Any</a> for T<div class="where">where
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#139">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id" class="fn">type_id</a>(&amp;self) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.87.0/core/any/struct.TypeId.html" title="struct core::any::TypeId">TypeId</a></h4></section></summary><div class='docblock'>Gets the <code>TypeId</code> of <code>self</code>. <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Borrow%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#209">Source</a><a href="#impl-Borrow%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html" title="trait core::borrow::Borrow">Borrow</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#211">Source</a><a href="#method.borrow" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow" class="fn">borrow</a>(&amp;self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;T</a></h4></section></summary><div class='docblock'>Immutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-BorrowMut%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#217">Source</a><a href="#impl-BorrowMut%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html" title="trait core::borrow::BorrowMut">BorrowMut</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow_mut" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#218">Source</a><a href="#method.borrow_mut" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut" class="fn">borrow_mut</a>(&amp;mut self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;mut T</a></h4></section></summary><div class='docblock'>Mutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-From%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#767">Source</a><a href="#impl-From%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for T</h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#770">Source</a><a href="#method.from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html#tymethod.from" class="fn">from</a>(t: T) -&gt; T</h4></section></summary><div class="docblock"><p>Returns the argument unchanged.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Into%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#750-752">Source</a><a href="#impl-Into%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#760">Source</a><a href="#method.into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html#tymethod.into" class="fn">into</a>(self) -&gt; U</h4></section></summary><div class="docblock"><p>Calls <code>U::from(self)</code>.</p>
<p>That is, this conversion is whatever the implementation of
<code><a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for U</code> chooses to do.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryFrom%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#806-808">Source</a><a href="#impl-TryFrom%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error-1" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#810">Source</a><a href="#associatedtype.Error-1" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" class="associatedtype">Error</a> = <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/convert/enum.Infallible.html" title="enum core::convert::Infallible">Infallible</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#813">Source</a><a href="#method.try_from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#tymethod.try_from" class="fn">try_from</a>(value: U) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;T, &lt;T as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryInto%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#791-793">Source</a><a href="#impl-TryInto%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html" title="trait core::convert::TryInto">TryInto</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#795">Source</a><a href="#associatedtype.Error" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#associatedtype.Error" class="associatedtype">Error</a> = &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#798">Source</a><a href="#method.try_into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#tymethod.try_into" class="fn">try_into</a>(self) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;U, &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details></div></section></div></main></body></html>

View File

@@ -0,0 +1,42 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="The main entry point for secret detection and redaction."><title>SecretSentinel in chrs_shhh - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_shhh" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="sidebar-items.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc struct"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_shhh/index.html">chrs_<wbr>shhh</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">Secret<wbr>Sentinel</a></h2><h3><a href="#implementations">Methods</a></h3><ul class="block method"><li><a href="#method.contains_secrets" title="contains_secrets">contains_secrets</a></li><li><a href="#method.new_default" title="new_default">new_default</a></li><li><a href="#method.scrub_text" title="scrub_text">scrub_text</a></li></ul><h3><a href="#synthetic-implementations">Auto Trait Implementations</a></h3><ul class="block synthetic-implementation"><li><a href="#impl-Freeze-for-SecretSentinel" title="Freeze">Freeze</a></li><li><a href="#impl-RefUnwindSafe-for-SecretSentinel" title="RefUnwindSafe">RefUnwindSafe</a></li><li><a href="#impl-Send-for-SecretSentinel" title="Send">Send</a></li><li><a href="#impl-Sync-for-SecretSentinel" title="Sync">Sync</a></li><li><a href="#impl-Unpin-for-SecretSentinel" title="Unpin">Unpin</a></li><li><a href="#impl-UnwindSafe-for-SecretSentinel" title="UnwindSafe">UnwindSafe</a></li></ul><h3><a href="#blanket-implementations">Blanket Implementations</a></h3><ul class="block blanket-implementation"><li><a href="#impl-Any-for-T" title="Any">Any</a></li><li><a href="#impl-Borrow%3CT%3E-for-T" title="Borrow&#60;T&#62;">Borrow&#60;T&#62;</a></li><li><a href="#impl-BorrowMut%3CT%3E-for-T" title="BorrowMut&#60;T&#62;">BorrowMut&#60;T&#62;</a></li><li><a href="#impl-From%3CT%3E-for-T" title="From&#60;T&#62;">From&#60;T&#62;</a></li><li><a href="#impl-Into%3CU%3E-for-T" title="Into&#60;U&#62;">Into&#60;U&#62;</a></li><li><a href="#impl-TryFrom%3CU%3E-for-T" title="TryFrom&#60;U&#62;">TryFrom&#60;U&#62;</a></li><li><a href="#impl-TryInto%3CU%3E-for-T" title="TryInto&#60;U&#62;">TryInto&#60;U&#62;</a></li></ul></section><div id="rustdoc-modnav"><h2 class="in-crate"><a href="index.html">In crate chrs_<wbr>shhh</a></h2></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="index.html">chrs_shhh</a></div><h1>Struct <span class="struct">SecretSentinel</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_shhh/lib.rs.html#38-40">Source</a> </span></div><pre class="rust item-decl"><code>pub struct SecretSentinel { <span class="comment">/* private fields */</span> }</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>The main entry point for secret detection and redaction.</p>
<ul>
<li><strong>WHAT</strong> Holds a collection of <code>RedactionRule</code>s.</li>
<li><strong>HOW</strong> Provides methods to scrub a string (<code>scrub_text</code>) and to simply
check whether any secret is present (<code>contains_secrets</code>).</li>
<li><strong>WHY</strong> Centralising the rules in a struct enables reuse and makes testing
straightforward.</li>
</ul>
</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-SecretSentinel" class="impl"><a class="src rightside" href="../src/chrs_shhh/lib.rs.html#52-109">Source</a><a href="#impl-SecretSentinel" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.SecretSentinel.html" title="struct chrs_shhh::SecretSentinel">SecretSentinel</a></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.new_default" class="method"><a class="src rightside" href="../src/chrs_shhh/lib.rs.html#61-81">Source</a><h4 class="code-header">pub fn <a href="#method.new_default" class="fn">new_default</a>() -&gt; Self</h4></section></summary><div class="docblock"><p>Constructs a <code>SecretSentinel</code> prepopulated with a sensible default set of rules.</p>
<ul>
<li><strong>WHAT</strong> Returns a sentinel containing three rules: OpenAI, AWS and a generic
secret matcher.</li>
<li><strong>HOW</strong> Instantiates <code>RedactionRule</code>s using the lazilyinitialised regexes
above and stores them in the <code>rules</code> vector.</li>
<li><strong>WHY</strong> Provides a readytouse configuration for typical development
environments while still allowing callers to create custom instances.</li>
</ul>
</div></details><details class="toggle method-toggle" open><summary><section id="method.scrub_text" class="method"><a class="src rightside" href="../src/chrs_shhh/lib.rs.html#89-98">Source</a><h4 class="code-header">pub fn <a href="#method.scrub_text" class="fn">scrub_text</a>(&amp;self, input: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.str.html">str</a>) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/string/struct.String.html" title="struct alloc::string::String">String</a></h4></section></summary><div class="docblock"><p>Redacts all secrets found in <code>input</code> according to the configured rules.</p>
<ul>
<li><strong>WHAT</strong> Returns a new <code>String</code> where each match has been replaced.</li>
<li><strong>HOW</strong> Iterates over the rules and applies <code>replace_all</code> for each.</li>
<li><strong>WHY</strong> Performing the replacements sequentially ensures that overlapping
patterns are handled deterministically.</li>
</ul>
</div></details><details class="toggle method-toggle" open><summary><section id="method.contains_secrets" class="method"><a class="src rightside" href="../src/chrs_shhh/lib.rs.html#106-108">Source</a><h4 class="code-header">pub fn <a href="#method.contains_secrets" class="fn">contains_secrets</a>(&amp;self, input: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.str.html">str</a>) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.bool.html">bool</a></h4></section></summary><div class="docblock"><p>Checks whether any of the configured rules match <code>input</code>.</p>
<ul>
<li><strong>WHAT</strong> Returns <code>true</code> if at least one rules pattern matches.</li>
<li><strong>HOW</strong> Uses <code>Iter::any</code> over <code>self.rules</code> with <code>is_match</code>.</li>
<li><strong>WHY</strong> A quick predicate useful for shortcircuiting logging or error
handling before performing the full redaction.</li>
</ul>
</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-SecretSentinel" class="impl"><a href="#impl-Freeze-for-SecretSentinel" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Freeze.html" title="trait core::marker::Freeze">Freeze</a> for <a class="struct" href="struct.SecretSentinel.html" title="struct chrs_shhh::SecretSentinel">SecretSentinel</a></h3></section><section id="impl-RefUnwindSafe-for-SecretSentinel" class="impl"><a href="#impl-RefUnwindSafe-for-SecretSentinel" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.RefUnwindSafe.html" title="trait core::panic::unwind_safe::RefUnwindSafe">RefUnwindSafe</a> for <a class="struct" href="struct.SecretSentinel.html" title="struct chrs_shhh::SecretSentinel">SecretSentinel</a></h3></section><section id="impl-Send-for-SecretSentinel" class="impl"><a href="#impl-Send-for-SecretSentinel" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Send.html" title="trait core::marker::Send">Send</a> for <a class="struct" href="struct.SecretSentinel.html" title="struct chrs_shhh::SecretSentinel">SecretSentinel</a></h3></section><section id="impl-Sync-for-SecretSentinel" class="impl"><a href="#impl-Sync-for-SecretSentinel" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sync.html" title="trait core::marker::Sync">Sync</a> for <a class="struct" href="struct.SecretSentinel.html" title="struct chrs_shhh::SecretSentinel">SecretSentinel</a></h3></section><section id="impl-Unpin-for-SecretSentinel" class="impl"><a href="#impl-Unpin-for-SecretSentinel" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Unpin.html" title="trait core::marker::Unpin">Unpin</a> for <a class="struct" href="struct.SecretSentinel.html" title="struct chrs_shhh::SecretSentinel">SecretSentinel</a></h3></section><section id="impl-UnwindSafe-for-SecretSentinel" class="impl"><a href="#impl-UnwindSafe-for-SecretSentinel" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.UnwindSafe.html" title="trait core::panic::unwind_safe::UnwindSafe">UnwindSafe</a> for <a class="struct" href="struct.SecretSentinel.html" title="struct chrs_shhh::SecretSentinel">SecretSentinel</a></h3></section></div><h2 id="blanket-implementations" class="section-header">Blanket Implementations<a href="#blanket-implementations" class="anchor">§</a></h2><div id="blanket-implementations-list"><details class="toggle implementors-toggle"><summary><section id="impl-Any-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#138">Source</a><a href="#impl-Any-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html" title="trait core::any::Any">Any</a> for T<div class="where">where
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#139">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id" class="fn">type_id</a>(&amp;self) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.87.0/core/any/struct.TypeId.html" title="struct core::any::TypeId">TypeId</a></h4></section></summary><div class='docblock'>Gets the <code>TypeId</code> of <code>self</code>. <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Borrow%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#209">Source</a><a href="#impl-Borrow%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html" title="trait core::borrow::Borrow">Borrow</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#211">Source</a><a href="#method.borrow" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow" class="fn">borrow</a>(&amp;self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;T</a></h4></section></summary><div class='docblock'>Immutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-BorrowMut%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#217">Source</a><a href="#impl-BorrowMut%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html" title="trait core::borrow::BorrowMut">BorrowMut</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow_mut" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#218">Source</a><a href="#method.borrow_mut" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut" class="fn">borrow_mut</a>(&amp;mut self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;mut T</a></h4></section></summary><div class='docblock'>Mutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-From%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#767">Source</a><a href="#impl-From%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for T</h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#770">Source</a><a href="#method.from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html#tymethod.from" class="fn">from</a>(t: T) -&gt; T</h4></section></summary><div class="docblock"><p>Returns the argument unchanged.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Into%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#750-752">Source</a><a href="#impl-Into%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#760">Source</a><a href="#method.into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html#tymethod.into" class="fn">into</a>(self) -&gt; U</h4></section></summary><div class="docblock"><p>Calls <code>U::from(self)</code>.</p>
<p>That is, this conversion is whatever the implementation of
<code><a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for U</code> chooses to do.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryFrom%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#806-808">Source</a><a href="#impl-TryFrom%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error-1" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#810">Source</a><a href="#associatedtype.Error-1" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" class="associatedtype">Error</a> = <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/convert/enum.Infallible.html" title="enum core::convert::Infallible">Infallible</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#813">Source</a><a href="#method.try_from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#tymethod.try_from" class="fn">try_from</a>(value: U) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;T, &lt;T as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryInto%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#791-793">Source</a><a href="#impl-TryInto%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html" title="trait core::convert::TryInto">TryInto</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#795">Source</a><a href="#associatedtype.Error" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#associatedtype.Error" class="associatedtype">Error</a> = &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#798">Source</a><a href="#method.try_into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#tymethod.try_into" class="fn">try_into</a>(self) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;U, &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details></div></section></div></main></body></html>

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="List of all items in this crate"><title>List of all items in this crate</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_slurp" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_slurp/index.html">chrs_<wbr>slurp</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#enums" title="Enums">Enums</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><h1>List of all items</h1><h3 id="structs">Structs</h3><ul class="all-items"><li><a href="struct.CurationEngine.html">CurationEngine</a></li><li><a href="struct.DecisionRecord.html">DecisionRecord</a></li></ul><h3 id="enums">Enums</h3><ul class="all-items"><li><a href="enum.SlurpError.html">SlurpError</a></li></ul></section></div></main></body></html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,34 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="chrs-slurp"><title>chrs_slurp - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_slurp" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_slurp/index.html">chrs_<wbr>slurp</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section id="rustdoc-toc"><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#chrs-slurp" title="chrs-slurp">chrs-slurp</a><ul><li><a href="#architectural-rationale" title="Architectural Rationale">Architectural Rationale</a></li></ul></li><li><a href="#public-api" title="Public API">Public API</a></li></ul><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#enums" title="Enums">Enums</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Crate <span>chrs_slurp</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_slurp/lib.rs.html#1-181">Source</a> </span></div><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><h2 id="chrs-slurp"><a class="doc-anchor" href="#chrs-slurp">§</a>chrs-slurp</h2>
<p><strong>Intelligence Crate</strong> Provides the <em>curation</em> layer for the CHORUS system.</p>
<p>The purpose of this crate is to take <strong>Decision Records</strong> generated by autonomous
agents, validate them, and persist them into the graph database. It isolates the
validation and storage concerns so that other components (e.g. provenance, security)
can work with a clean, audited data model.</p>
<h3 id="architectural-rationale"><a class="doc-anchor" href="#architectural-rationale">§</a>Architectural Rationale</h3>
<ul>
<li><strong>Separation of concerns</strong> Agents produce raw decisions; this crate is the
single source of truth for how those decisions are stored.</li>
<li><strong>Auditability</strong> By persisting to a Doltbacked graph each decision is versioned
and can be replaybacked, satisfying CHORUSs requirement for reproducible
reasoning.</li>
<li><strong>Extensibility</strong> The <code>CurationEngine</code> can be extended with additional validation
steps (e.g. policy checks) without touching the agents themselves.</li>
</ul>
<p>The crate depends on:</p>
<ul>
<li><code>chrs-graph</code> a thin wrapper around a Doltbacked graph implementation.</li>
<li><code>ucxl</code> for addressing external knowledge artefacts.</li>
<li><code>chrono</code>, <code>serde</code>, <code>uuid</code> standard utilities for timestamps, (de)serialization
and unique identifiers.</li>
</ul>
<hr />
<h2 id="public-api"><a class="doc-anchor" href="#public-api">§</a>Public API</h2>
<p>The public surface consists of three items:</p>
<ul>
<li><code>DecisionRecord</code> data structure representing a curated decision.</li>
<li><code>SlurpError</code> enumeration of possible errors while curating.</li>
<li><code>CurationEngine</code> the engine that validates and persists <code>DecisionRecord</code>s.</li>
</ul>
<p>Each item is documented inline below.</p>
</div></details><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.CurationEngine.html" title="struct chrs_slurp::CurationEngine">Curation<wbr>Engine</a></dt><dd>Core engine that validates and persists <code>DecisionRecord</code>s into the
Doltbacked graph.</dd><dt><a class="struct" href="struct.DecisionRecord.html" title="struct chrs_slurp::DecisionRecord">Decision<wbr>Record</a></dt><dd>A record representing a curated decision within the CHORUS system.</dd></dl><h2 id="enums" class="section-header">Enums<a href="#enums" class="anchor">§</a></h2><dl class="item-table"><dt><a class="enum" href="enum.SlurpError.html" title="enum chrs_slurp::SlurpError">Slurp<wbr>Error</a></dt><dd>Errors that can arise while slurping (curating) a decision record.</dd></dl></section></div></main></body></html>

View File

@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"enum":["SlurpError"],"struct":["CurationEngine","DecisionRecord"]};

View File

@@ -0,0 +1,36 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Core engine that validates and persists `DecisionRecord`s into the Doltbacked graph."><title>CurationEngine in chrs_slurp - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_slurp" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="sidebar-items.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc struct"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_slurp/index.html">chrs_<wbr>slurp</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">Curation<wbr>Engine</a></h2><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#why" title="Why">Why</a></li></ul><h3><a href="#implementations">Methods</a></h3><ul class="block method"><li><a href="#method.curate_decision" title="curate_decision">curate_decision</a></li><li><a href="#method.new" title="new">new</a></li></ul><h3><a href="#synthetic-implementations">Auto Trait Implementations</a></h3><ul class="block synthetic-implementation"><li><a href="#impl-Freeze-for-CurationEngine" title="Freeze">Freeze</a></li><li><a href="#impl-RefUnwindSafe-for-CurationEngine" title="RefUnwindSafe">RefUnwindSafe</a></li><li><a href="#impl-Send-for-CurationEngine" title="Send">Send</a></li><li><a href="#impl-Sync-for-CurationEngine" title="Sync">Sync</a></li><li><a href="#impl-Unpin-for-CurationEngine" title="Unpin">Unpin</a></li><li><a href="#impl-UnwindSafe-for-CurationEngine" title="UnwindSafe">UnwindSafe</a></li></ul><h3><a href="#blanket-implementations">Blanket Implementations</a></h3><ul class="block blanket-implementation"><li><a href="#impl-Any-for-T" title="Any">Any</a></li><li><a href="#impl-Borrow%3CT%3E-for-T" title="Borrow&#60;T&#62;">Borrow&#60;T&#62;</a></li><li><a href="#impl-BorrowMut%3CT%3E-for-T" title="BorrowMut&#60;T&#62;">BorrowMut&#60;T&#62;</a></li><li><a href="#impl-From%3CT%3E-for-T" title="From&#60;T&#62;">From&#60;T&#62;</a></li><li><a href="#impl-Into%3CU%3E-for-T" title="Into&#60;U&#62;">Into&#60;U&#62;</a></li><li><a href="#impl-TryFrom%3CU%3E-for-T" title="TryFrom&#60;U&#62;">TryFrom&#60;U&#62;</a></li><li><a href="#impl-TryInto%3CU%3E-for-T" title="TryInto&#60;U&#62;">TryInto&#60;U&#62;</a></li></ul></section><div id="rustdoc-modnav"><h2 class="in-crate"><a href="index.html">In crate chrs_<wbr>slurp</a></h2></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="index.html">chrs_slurp</a></div><h1>Struct <span class="struct">CurationEngine</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_slurp/lib.rs.html#98-100">Source</a> </span></div><pre class="rust item-decl"><code>pub struct CurationEngine { <span class="comment">/* private fields */</span> }</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Core engine that validates and persists <code>DecisionRecord</code>s into the
Doltbacked graph.</p>
<h2 id="why"><a class="doc-anchor" href="#why">§</a>Why</h2>
<p>Centralising curation logic ensures a single place for validation and
storage semantics, keeping the rest of the codebase agnostic of the graph
implementation details.</p>
</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-CurationEngine" class="impl"><a class="src rightside" href="../src/chrs_slurp/lib.rs.html#102-156">Source</a><a href="#impl-CurationEngine" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.CurationEngine.html" title="struct chrs_slurp::CurationEngine">CurationEngine</a></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.new" class="method"><a class="src rightside" href="../src/chrs_slurp/lib.rs.html#108-110">Source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>(graph: <a class="struct" href="../chrs_graph/struct.DoltGraph.html" title="struct chrs_graph::DoltGraph">DoltGraph</a>) -&gt; Self</h4></section></summary><div class="docblock"><p>Creates a new <code>CurationEngine</code> bound to the supplied <code>DoltGraph</code>.</p>
<p>The engine holds a reference to the graph for the lifetime of the
instance; callers are responsible for providing a correctly initialised
graph.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="method.curate_decision" class="method"><a class="src rightside" href="../src/chrs_slurp/lib.rs.html#127-155">Source</a><h4 class="code-header">pub fn <a href="#method.curate_decision" class="fn">curate_decision</a>(&amp;self, dr: <a class="struct" href="struct.DecisionRecord.html" title="struct chrs_slurp::DecisionRecord">DecisionRecord</a>) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="enum" href="enum.SlurpError.html" title="enum chrs_slurp::SlurpError">SlurpError</a>&gt;</h4></section></summary><div class="docblock"><p>Validates the citations in <code>dr</code> and persists the decision into the
graph.</p>
<p>The method performs three steps:</p>
<ol>
<li><strong>Citation validation</strong> each citation string is parsed into a
<code>UCXLAddress</code>. Invalid citations produce a <code>ValidationError</code>.</li>
<li><strong>Table assurance</strong> attempts to create the <code>curated_decisions</code>
table if it does not already exist. Errors are ignored because the
table may already be present.</li>
<li><strong>Insertion &amp; commit</strong> the decision is serialised to JSON and
inserted as a node, then the graph transaction is committed.</li>
</ol>
<h5 id="errors"><a class="doc-anchor" href="#errors">§</a>Errors</h5>
<p>Propagates any <code>GraphError</code>, <code>serde_json::Error</code>, or custom
validation failures.</p>
</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-CurationEngine" class="impl"><a href="#impl-Freeze-for-CurationEngine" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Freeze.html" title="trait core::marker::Freeze">Freeze</a> for <a class="struct" href="struct.CurationEngine.html" title="struct chrs_slurp::CurationEngine">CurationEngine</a></h3></section><section id="impl-RefUnwindSafe-for-CurationEngine" class="impl"><a href="#impl-RefUnwindSafe-for-CurationEngine" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.RefUnwindSafe.html" title="trait core::panic::unwind_safe::RefUnwindSafe">RefUnwindSafe</a> for <a class="struct" href="struct.CurationEngine.html" title="struct chrs_slurp::CurationEngine">CurationEngine</a></h3></section><section id="impl-Send-for-CurationEngine" class="impl"><a href="#impl-Send-for-CurationEngine" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Send.html" title="trait core::marker::Send">Send</a> for <a class="struct" href="struct.CurationEngine.html" title="struct chrs_slurp::CurationEngine">CurationEngine</a></h3></section><section id="impl-Sync-for-CurationEngine" class="impl"><a href="#impl-Sync-for-CurationEngine" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sync.html" title="trait core::marker::Sync">Sync</a> for <a class="struct" href="struct.CurationEngine.html" title="struct chrs_slurp::CurationEngine">CurationEngine</a></h3></section><section id="impl-Unpin-for-CurationEngine" class="impl"><a href="#impl-Unpin-for-CurationEngine" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Unpin.html" title="trait core::marker::Unpin">Unpin</a> for <a class="struct" href="struct.CurationEngine.html" title="struct chrs_slurp::CurationEngine">CurationEngine</a></h3></section><section id="impl-UnwindSafe-for-CurationEngine" class="impl"><a href="#impl-UnwindSafe-for-CurationEngine" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.UnwindSafe.html" title="trait core::panic::unwind_safe::UnwindSafe">UnwindSafe</a> for <a class="struct" href="struct.CurationEngine.html" title="struct chrs_slurp::CurationEngine">CurationEngine</a></h3></section></div><h2 id="blanket-implementations" class="section-header">Blanket Implementations<a href="#blanket-implementations" class="anchor">§</a></h2><div id="blanket-implementations-list"><details class="toggle implementors-toggle"><summary><section id="impl-Any-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#138">Source</a><a href="#impl-Any-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html" title="trait core::any::Any">Any</a> for T<div class="where">where
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#139">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id" class="fn">type_id</a>(&amp;self) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.87.0/core/any/struct.TypeId.html" title="struct core::any::TypeId">TypeId</a></h4></section></summary><div class='docblock'>Gets the <code>TypeId</code> of <code>self</code>. <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Borrow%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#209">Source</a><a href="#impl-Borrow%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html" title="trait core::borrow::Borrow">Borrow</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#211">Source</a><a href="#method.borrow" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow" class="fn">borrow</a>(&amp;self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;T</a></h4></section></summary><div class='docblock'>Immutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-BorrowMut%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#217">Source</a><a href="#impl-BorrowMut%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html" title="trait core::borrow::BorrowMut">BorrowMut</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow_mut" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#218">Source</a><a href="#method.borrow_mut" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut" class="fn">borrow_mut</a>(&amp;mut self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;mut T</a></h4></section></summary><div class='docblock'>Mutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-From%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#767">Source</a><a href="#impl-From%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for T</h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#770">Source</a><a href="#method.from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html#tymethod.from" class="fn">from</a>(t: T) -&gt; T</h4></section></summary><div class="docblock"><p>Returns the argument unchanged.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Into%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#750-752">Source</a><a href="#impl-Into%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#760">Source</a><a href="#method.into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html#tymethod.into" class="fn">into</a>(self) -&gt; U</h4></section></summary><div class="docblock"><p>Calls <code>U::from(self)</code>.</p>
<p>That is, this conversion is whatever the implementation of
<code><a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for U</code> chooses to do.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryFrom%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#806-808">Source</a><a href="#impl-TryFrom%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error-1" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#810">Source</a><a href="#associatedtype.Error-1" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" class="associatedtype">Error</a> = <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/convert/enum.Infallible.html" title="enum core::convert::Infallible">Infallible</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#813">Source</a><a href="#method.try_from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#tymethod.try_from" class="fn">try_from</a>(value: U) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;T, &lt;T as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryInto%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#791-793">Source</a><a href="#impl-TryInto%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html" title="trait core::convert::TryInto">TryInto</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#795">Source</a><a href="#associatedtype.Error" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#associatedtype.Error" class="associatedtype">Error</a> = &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#798">Source</a><a href="#method.try_into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#tymethod.try_into" class="fn">try_into</a>(self) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;U, &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details></div></section></div></main></body></html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="List of all items in this crate"><title>List of all items in this crate</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_sync" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_sync/index.html">chrs_<wbr>sync</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><h1>List of all items</h1><h3 id="structs">Structs</h3><ul class="all-items"><li><a href="struct.SyncManager.html">SyncManager</a></li></ul></section></div></main></body></html>

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="API documentation for the Rust `chrs_sync` crate."><title>chrs_sync - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_sync" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_sync/index.html">chrs_<wbr>sync</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section id="rustdoc-toc"><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Crate <span>chrs_sync</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_sync/lib.rs.html#1-116">Source</a> </span></div><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.SyncManager.html" title="struct chrs_sync::SyncManager">Sync<wbr>Manager</a></dt><dd>Manages synchronization of a Dolt repository across peers.</dd></dl></section></div></main></body></html>

View File

@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"struct":["SyncManager"]};

View File

@@ -0,0 +1,52 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Manages synchronization of a Dolt repository across peers."><title>SyncManager in chrs_sync - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="chrs_sync" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../static.files/storage-82c7156e.js"></script><script defer src="sidebar-items.js"></script><script defer src="../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc struct"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../chrs_sync/index.html">chrs_<wbr>sync</a><span class="version">0.1.0</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">Sync<wbr>Manager</a></h2><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#fields-1" title="Fields">Fields</a></li><li><a href="#rationale" title="Rationale">Rationale</a></li></ul><h3><a href="#implementations">Methods</a></h3><ul class="block method"><li><a href="#method.broadcast_state" title="broadcast_state">broadcast_state</a></li><li><a href="#method.handle_sync_signal" title="handle_sync_signal">handle_sync_signal</a></li><li><a href="#method.new" title="new">new</a></li></ul><h3><a href="#synthetic-implementations">Auto Trait Implementations</a></h3><ul class="block synthetic-implementation"><li><a href="#impl-Freeze-for-SyncManager" title="!Freeze">!Freeze</a></li><li><a href="#impl-RefUnwindSafe-for-SyncManager" title="!RefUnwindSafe">!RefUnwindSafe</a></li><li><a href="#impl-Sync-for-SyncManager" title="!Sync">!Sync</a></li><li><a href="#impl-UnwindSafe-for-SyncManager" title="!UnwindSafe">!UnwindSafe</a></li><li><a href="#impl-Send-for-SyncManager" title="Send">Send</a></li><li><a href="#impl-Unpin-for-SyncManager" title="Unpin">Unpin</a></li></ul><h3><a href="#blanket-implementations">Blanket Implementations</a></h3><ul class="block blanket-implementation"><li><a href="#impl-Any-for-T" title="Any">Any</a></li><li><a href="#impl-Borrow%3CT%3E-for-T" title="Borrow&#60;T&#62;">Borrow&#60;T&#62;</a></li><li><a href="#impl-BorrowMut%3CT%3E-for-T" title="BorrowMut&#60;T&#62;">BorrowMut&#60;T&#62;</a></li><li><a href="#impl-From%3CT%3E-for-T" title="From&#60;T&#62;">From&#60;T&#62;</a></li><li><a href="#impl-Into%3CU%3E-for-T" title="Into&#60;U&#62;">Into&#60;U&#62;</a></li><li><a href="#impl-TryFrom%3CU%3E-for-T" title="TryFrom&#60;U&#62;">TryFrom&#60;U&#62;</a></li><li><a href="#impl-TryInto%3CU%3E-for-T" title="TryInto&#60;U&#62;">TryInto&#60;U&#62;</a></li></ul></section><div id="rustdoc-modnav"><h2 class="in-crate"><a href="index.html">In crate chrs_<wbr>sync</a></h2></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="index.html">chrs_sync</a></div><h1>Struct <span class="struct">SyncManager</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/chrs_sync/lib.rs.html#24-27">Source</a> </span></div><pre class="rust item-decl"><code>pub struct SyncManager { <span class="comment">/* private fields */</span> }</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Manages synchronization of a Dolt repository across peers.</p>
<h2 id="fields-1"><a class="doc-anchor" href="#fields-1">§</a>Fields</h2>
<ul>
<li><code>mailbox</code> The <code>Mailbox</code> instance used to send and receive messages.</li>
<li><code>repo_path</code> Filesystem path to the local Dolt repository.</li>
</ul>
<h2 id="rationale"><a class="doc-anchor" href="#rationale">§</a>Rationale</h2>
<p>The CHORUS architecture relies on deterministic state replication. By
broadcasting the latest commit hash (<code>sync_signal</code>) each peer can decide
whether to pull updates. This struct encapsulates that behaviour, keeping the
rest of the system agnostic of the underlying VCS commands.</p>
</div></details><h2 id="implementations" class="section-header">Implementations<a href="#implementations" class="anchor">§</a></h2><div id="implementations-list"><details class="toggle implementors-toggle" open><summary><section id="impl-SyncManager" class="impl"><a class="src rightside" href="../src/chrs_sync/lib.rs.html#29-116">Source</a><a href="#impl-SyncManager" class="anchor">§</a><h3 class="code-header">impl <a class="struct" href="struct.SyncManager.html" title="struct chrs_sync::SyncManager">SyncManager</a></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.new" class="method"><a class="src rightside" href="../src/chrs_sync/lib.rs.html#38-40">Source</a><h4 class="code-header">pub fn <a href="#method.new" class="fn">new</a>(mailbox: <a class="struct" href="../chrs_mail/struct.Mailbox.html" title="struct chrs_mail::Mailbox">Mailbox</a>, repo_path: <a class="struct" href="https://doc.rust-lang.org/1.87.0/std/path/struct.PathBuf.html" title="struct std::path::PathBuf">PathBuf</a>) -&gt; Self</h4></section></summary><div class="docblock"><p>Creates a new <code>SyncManager</code>.</p>
<h5 id="parameters"><a class="doc-anchor" href="#parameters">§</a>Parameters</h5>
<ul>
<li><code>mailbox</code> An alreadyopened <code>Mailbox</code> for peer communication.</li>
<li><code>repo_path</code> Path to the Dolt repository that should be kept in sync.</li>
</ul>
<p>Returns a fullyinitialised manager ready to broadcast or handle sync
signals.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="method.broadcast_state" class="method"><a class="src rightside" href="../src/chrs_sync/lib.rs.html#54-83">Source</a><h4 class="code-header">pub fn <a href="#method.broadcast_state" class="fn">broadcast_state</a>(
&amp;self,
from_peer: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.str.html">str</a>,
to_peer: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.str.html">str</a>,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a>&lt;dyn <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/error/trait.Error.html" title="trait core::error::Error">Error</a>&gt;&gt;</h4></section></summary><div class="docblock"><p>Broadcasts the current repository state to a remote peer.</p>
<p>The method executes <code>dolt log -n 1 --format %H</code> to obtain the most recent
commit hash, constructs a <code>Message</code> with topic <code>"sync_signal"</code> and sends it
via the mailbox.</p>
<ul>
<li><code>from_peer</code> Identifier of the sender.</li>
<li><code>to_peer</code> Identifier of the intended recipient.</li>
</ul>
<h5 id="errors"><a class="doc-anchor" href="#errors">§</a>Errors</h5>
<p>Returns any I/O or commandexecution error wrapped in a boxed <code>dyn Error</code>.</p>
</div></details><details class="toggle method-toggle" open><summary><section id="method.handle_sync_signal" class="method"><a class="src rightside" href="../src/chrs_sync/lib.rs.html#95-115">Source</a><h4 class="code-header">pub fn <a href="#method.handle_sync_signal" class="fn">handle_sync_signal</a>(&amp;self, msg: &amp;<a class="struct" href="../chrs_mail/struct.Message.html" title="struct chrs_mail::Message">Message</a>) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.87.0/alloc/boxed/struct.Box.html" title="struct alloc::boxed::Box">Box</a>&lt;dyn <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/error/trait.Error.html" title="trait core::error::Error">Error</a>&gt;&gt;</h4></section></summary><div class="docblock"><p>Handles an incoming <code>sync_signal</code> message.</p>
<p>If the message topic is not <code>"sync_signal"</code> the function returns <code>Ok(())</code>
immediately. Otherwise it extracts the remote commit hash and attempts a
<code>dolt pull origin</code> to bring the local repository uptodate. In a real
P2P deployment the remote URL would be derived from the sender, but the
current implementation uses the default remote configuration.</p>
<h5 id="errors-1"><a class="doc-anchor" href="#errors-1">§</a>Errors</h5>
<p>Propagates any command execution failures.</p>
</div></details></div></details></div><h2 id="synthetic-implementations" class="section-header">Auto Trait Implementations<a href="#synthetic-implementations" class="anchor">§</a></h2><div id="synthetic-implementations-list"><section id="impl-Freeze-for-SyncManager" class="impl"><a href="#impl-Freeze-for-SyncManager" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Freeze.html" title="trait core::marker::Freeze">Freeze</a> for <a class="struct" href="struct.SyncManager.html" title="struct chrs_sync::SyncManager">SyncManager</a></h3></section><section id="impl-RefUnwindSafe-for-SyncManager" class="impl"><a href="#impl-RefUnwindSafe-for-SyncManager" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.RefUnwindSafe.html" title="trait core::panic::unwind_safe::RefUnwindSafe">RefUnwindSafe</a> for <a class="struct" href="struct.SyncManager.html" title="struct chrs_sync::SyncManager">SyncManager</a></h3></section><section id="impl-Send-for-SyncManager" class="impl"><a href="#impl-Send-for-SyncManager" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Send.html" title="trait core::marker::Send">Send</a> for <a class="struct" href="struct.SyncManager.html" title="struct chrs_sync::SyncManager">SyncManager</a></h3></section><section id="impl-Sync-for-SyncManager" class="impl"><a href="#impl-Sync-for-SyncManager" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sync.html" title="trait core::marker::Sync">Sync</a> for <a class="struct" href="struct.SyncManager.html" title="struct chrs_sync::SyncManager">SyncManager</a></h3></section><section id="impl-Unpin-for-SyncManager" class="impl"><a href="#impl-Unpin-for-SyncManager" class="anchor">§</a><h3 class="code-header">impl <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Unpin.html" title="trait core::marker::Unpin">Unpin</a> for <a class="struct" href="struct.SyncManager.html" title="struct chrs_sync::SyncManager">SyncManager</a></h3></section><section id="impl-UnwindSafe-for-SyncManager" class="impl"><a href="#impl-UnwindSafe-for-SyncManager" class="anchor">§</a><h3 class="code-header">impl !<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/panic/unwind_safe/trait.UnwindSafe.html" title="trait core::panic::unwind_safe::UnwindSafe">UnwindSafe</a> for <a class="struct" href="struct.SyncManager.html" title="struct chrs_sync::SyncManager">SyncManager</a></h3></section></div><h2 id="blanket-implementations" class="section-header">Blanket Implementations<a href="#blanket-implementations" class="anchor">§</a></h2><div id="blanket-implementations-list"><details class="toggle implementors-toggle"><summary><section id="impl-Any-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#138">Source</a><a href="#impl-Any-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html" title="trait core::any::Any">Any</a> for T<div class="where">where
T: 'static + ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.type_id" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/any.rs.html#139">Source</a><a href="#method.type_id" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id" class="fn">type_id</a>(&amp;self) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.87.0/core/any/struct.TypeId.html" title="struct core::any::TypeId">TypeId</a></h4></section></summary><div class='docblock'>Gets the <code>TypeId</code> of <code>self</code>. <a href="https://doc.rust-lang.org/1.87.0/core/any/trait.Any.html#tymethod.type_id">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Borrow%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#209">Source</a><a href="#impl-Borrow%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html" title="trait core::borrow::Borrow">Borrow</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#211">Source</a><a href="#method.borrow" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow" class="fn">borrow</a>(&amp;self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;T</a></h4></section></summary><div class='docblock'>Immutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.Borrow.html#tymethod.borrow">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-BorrowMut%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#217">Source</a><a href="#impl-BorrowMut%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html" title="trait core::borrow::BorrowMut">BorrowMut</a>&lt;T&gt; for T<div class="where">where
T: ?<a class="trait" href="https://doc.rust-lang.org/1.87.0/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.borrow_mut" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/borrow.rs.html#218">Source</a><a href="#method.borrow_mut" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut" class="fn">borrow_mut</a>(&amp;mut self) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.87.0/std/primitive.reference.html">&amp;mut T</a></h4></section></summary><div class='docblock'>Mutably borrows from an owned value. <a href="https://doc.rust-lang.org/1.87.0/core/borrow/trait.BorrowMut.html#tymethod.borrow_mut">Read more</a></div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-From%3CT%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#767">Source</a><a href="#impl-From%3CT%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for T</h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#770">Source</a><a href="#method.from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html#tymethod.from" class="fn">from</a>(t: T) -&gt; T</h4></section></summary><div class="docblock"><p>Returns the argument unchanged.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-Into%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#750-752">Source</a><a href="#impl-Into%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle method-toggle" open><summary><section id="method.into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#760">Source</a><a href="#method.into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html#tymethod.into" class="fn">into</a>(self) -&gt; U</h4></section></summary><div class="docblock"><p>Calls <code>U::from(self)</code>.</p>
<p>That is, this conversion is whatever the implementation of
<code><a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.From.html" title="trait core::convert::From">From</a>&lt;T&gt; for U</code> chooses to do.</p>
</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryFrom%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#806-808">Source</a><a href="#impl-TryFrom%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.Into.html" title="trait core::convert::Into">Into</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error-1" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#810">Source</a><a href="#associatedtype.Error-1" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" class="associatedtype">Error</a> = <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/convert/enum.Infallible.html" title="enum core::convert::Infallible">Infallible</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_from" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#813">Source</a><a href="#method.try_from" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#tymethod.try_from" class="fn">try_from</a>(value: U) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;T, &lt;T as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;U&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details><details class="toggle implementors-toggle"><summary><section id="impl-TryInto%3CU%3E-for-T" class="impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#791-793">Source</a><a href="#impl-TryInto%3CU%3E-for-T" class="anchor">§</a><h3 class="code-header">impl&lt;T, U&gt; <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html" title="trait core::convert::TryInto">TryInto</a>&lt;U&gt; for T<div class="where">where
U: <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;,</div></h3></section></summary><div class="impl-items"><details class="toggle" open><summary><section id="associatedtype.Error" class="associatedtype trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#795">Source</a><a href="#associatedtype.Error" class="anchor">§</a><h4 class="code-header">type <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#associatedtype.Error" class="associatedtype">Error</a> = &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a></h4></section></summary><div class='docblock'>The type returned in the event of a conversion error.</div></details><details class="toggle method-toggle" open><summary><section id="method.try_into" class="method trait-impl"><a class="src rightside" href="https://doc.rust-lang.org/1.87.0/src/core/convert/mod.rs.html#798">Source</a><a href="#method.try_into" class="anchor">§</a><h4 class="code-header">fn <a href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryInto.html#tymethod.try_into" class="fn">try_into</a>(self) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.87.0/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;U, &lt;U as <a class="trait" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html" title="trait core::convert::TryFrom">TryFrom</a>&lt;T&gt;&gt;::<a class="associatedtype" href="https://doc.rust-lang.org/1.87.0/core/convert/trait.TryFrom.html#associatedtype.Error" title="type core::convert::TryFrom::Error">Error</a>&gt;</h4></section></summary><div class='docblock'>Performs the conversion.</div></details></div></details></div></section></div></main></body></html>

2
target/doc/crates.js Normal file
View File

@@ -0,0 +1,2 @@
window.ALL_CRATES = ["chrs_agent","chrs_bubble","chrs_graph","chrs_mail","chrs_poc","chrs_shhh","chrs_slurp","chrs_sync","ucxl"];
//{"start":21,"fragment_lengths":[12,14,13,12,11,12,13,12,7]}

1
target/doc/help.html Normal file
View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Documentation for Rustdoc"><title>Help</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="./static.files/${f}">`).join(""))</script><link rel="stylesheet" href="./static.files/normalize-9960930a.css"><link rel="stylesheet" href="./static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="./" data-static-root-path="./static.files/" data-current-crate="chrs_poc" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="./static.files/storage-82c7156e.js"></script><script defer src="./static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="./static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="./static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="./static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button><a class="logo-container" href="./index.html"><img class="rust-logo" src="./static.files/rust-logo-9a9549ea.svg" alt=""></a></nav><nav class="sidebar"><div class="sidebar-crate"><a class="logo-container" href="./index.html"><img class="rust-logo" src="./static.files/rust-logo-9a9549ea.svg" alt="logo"></a><h2><a href="./index.html">Rustdoc</a><span class="version">1.87.0</span></h2></div><div class="version">(17067e9ac 2025-05-09)</div><h2 class="location">Help</h2><div class="sidebar-elems"></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Rustdoc help</h1><span class="out-of-band"><a id="back" href="javascript:void(0)" onclick="history.back();">Back</a></span></div><noscript><section><p>You need to enable JavaScript to use keyboard commands or search.</p><p>For more information, browse the <a href="https://doc.rust-lang.org/1.87.0/rustdoc/">rustdoc handbook</a>.</p></section></noscript></section></div></main></body></html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
searchState.loadedDescShard("chrs_agent", 0, "Represents a running CHORUS agent.\nReturns the argument unchanged.\nInitializes a new <code>CHORUSAgent</code>.\nCalls <code>U::from(self)</code>.\nEntry point for the CHORUS agent binary.\nMain event loop of the agent.")

View File

@@ -0,0 +1 @@
searchState.loadedDescShard("chrs_bubble", 0, "Errors that can arise when working with a <code>ProvenanceGraph</code>.\nThe target node <em>cites</em> the source node.\nThe target node was <em>derived</em> from the source node.\nThe target node was <em>influenced</em> by the source node.\nRepresents the kind of relationship between two provenance …\nCore structure that maintains an inmemory DAG of …\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCalls <code>U::from(self)</code>.\nCalls <code>U::from(self)</code>.\nCalls <code>U::from(self)</code>.\nCreates a new <code>ProvenanceGraph</code> backed by a …\nRecords a directed edge between two existing nodes.\nRecords a provenance node with a unique <code>Uuid</code> and an …")

View File

@@ -0,0 +1 @@
searchState.loadedDescShard("chrs_graph", 0, "chrs-graph library implementation using Dolt for graph …\nRepresents a failure when executing a Dolt command.\nWrapper around a Dolt repository that stores graph data.\nEnumeration of possible errors that can arise while …\nPropagates I/O errors from the standard library (e.g., …\nA generic catchall for errors that dont fit the …\nPropagates JSON (de)serialization errors from <code>serde_json</code>.\nStage all changes and commit them with the provided <code>message</code>…\nCreate a SQL table within the Dolt repository.\nReturns the argument unchanged.\nReturns the argument unchanged.\nInitialise (or open) a Dolt repository at the given <code>path</code>.\nInsert a node represented by a JSON object into the …\nCalls <code>U::from(self)</code>.\nCalls <code>U::from(self)</code>.\nFilesystem path to the root of the Dolt repository.")

View File

@@ -0,0 +1 @@
searchState.loadedDescShard("chrs_mail", 0, "chrs-mail library implementation\nPropagates chrono parsing errors, primarily when …\nPropagates JSON (de)serialization errors from <code>serde_json</code>.\nErrors that can occur while using the <code>Mailbox</code>.\nWrapper around a SQLite connection providing …\nRepresents a mail message stored in the mailbox.\nPropagates any <code>rusqlite::Error</code> encountered while …\nPropagates UUID parsing errors.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nIdentifier of the sending peer.\nGlobally unique identifier for the message.\nCalls <code>U::from(self)</code>.\nCalls <code>U::from(self)</code>.\nCalls <code>U::from(self)</code>.\nMark a message as read by setting its <code>read_at</code> timestamp.\nOpen (or create) a mailbox database at <code>path</code>.\nArbitrary JSON payload containing the message body.\nOptional timestamp (UTC) when the recipient read the …\nRetrieve all unread messages addressed to <code>peer_id</code>.\nStore a new message in the mailbox.\nTimestamp (UTC) when the message was sent.\nIdentifier of the receiving peer.\nTopic or channel of the message; used for routing/filters.")

View File

@@ -0,0 +1 @@
searchState.loadedDescShard("chrs_poc", 0, "Entry point for the proofofconcept binary.")

View File

@@ -0,0 +1 @@
searchState.loadedDescShard("chrs_shhh", 0, "Represents a single rule used to redact a secret.\nThe main entry point for secret detection and redaction.\nChecks whether any of the configured rules match <code>input</code>.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCalls <code>U::from(self)</code>.\nCalls <code>U::from(self)</code>.\nHumanreadable name for the rule.\nConstructs a <code>SecretSentinel</code> prepopulated with a …\nCompiled regular expression that matches the secret.\nText that will replace the matched secret.\nRedacts all secrets found in <code>input</code> according to the …")

View File

@@ -0,0 +1 @@
searchState.loadedDescShard("chrs_slurp", 0, "chrs-slurp\nCore engine that validates and persists <code>DecisionRecord</code>s …\nA record representing a curated decision within the CHORUS …\nErrors that can arise while slurping (curating) a decision …\nIdentifier of the agent or human that authored the …\nSerialized UCXL addresses that serve as citations for the …\nValidates the citations in <code>dr</code> and persists the decision …\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nUnique identifier for the decision.\nCalls <code>U::from(self)</code>.\nCalls <code>U::from(self)</code>.\nCalls <code>U::from(self)</code>.\nCreates a new <code>CurationEngine</code> bound to the supplied …\nFreeform textual reasoning explaining the decision.\nThe moment the decision was created.")

View File

@@ -0,0 +1 @@
searchState.loadedDescShard("chrs_sync", 0, "Manages synchronization of a Dolt repository across peers.\nBroadcasts the current repository state to a remote peer.\nReturns the argument unchanged.\nHandles an incoming <code>sync_signal</code> message.\nCalls <code>U::from(self)</code>.\nCreates a new <code>SyncManager</code>.")

View File

@@ -0,0 +1 @@
searchState.loadedDescShard("ucxl", 0, "UCXL core data structures and utilities.\nFuture (“^^”) a speculative or planned version of …\nInmemory implementation of <code>MetadataStore</code> backed by a …\nTrait defining a simple keyvalue metadata store.\nPast (“~~”) a historical snapshot of a resource.\nPresent (“#”) the current version of a resource.\nRepresents the temporal axis in a UCXL address.\nRepresents a parsed UCXL address.\nThe identifier of the agent (e.g., a user or system …\nFormats the temporal axis back to its string token.\nSerialises the address back to its canonical string form.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nParses a temporal axis token from its textual …\nParses a full UCXL address string into a <code>UCXLAddress</code> value.\nRetrieves the metadata for <code>path</code> if it exists.\nCalls <code>U::from(self)</code>.\nCalls <code>U::from(self)</code>.\nCalls <code>U::from(self)</code>.\nCreates a fresh, empty <code>InMemoryMetadataStore</code>.\nPath to the resource relative to the project root.\nThe project namespace this address belongs to.\nRemoves the metadata entry for <code>path</code>, returning the old …\nOptional role associated with the agent (e.g., “admin”…\nStores <code>metadata</code> for <code>path</code>, overwriting any existing value.\nThe specific task within the project.\nTemporal axis indicating present, past or future.\nUCXL filesystem watcher.\nRepresents a watcher rooted at a specific base path.\nReturns the argument unchanged.\nCalls <code>U::from(self)</code>.\nCreates a new <code>UCXLWatcher</code> for the given path.\nStarts the watch loop, blocking indefinitely while …")

1
target/doc/settings.html Normal file
View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Settings of Rustdoc"><title>Settings</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="./static.files/${f}">`).join(""))</script><link rel="stylesheet" href="./static.files/normalize-9960930a.css"><link rel="stylesheet" href="./static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="./" data-static-root-path="./static.files/" data-current-crate="chrs_poc" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="./static.files/storage-82c7156e.js"></script><script defer src="./static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="./static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="./static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="./static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button><a class="logo-container" href="./index.html"><img class="rust-logo" src="./static.files/rust-logo-9a9549ea.svg" alt=""></a></nav><nav class="sidebar"><div class="sidebar-crate"><a class="logo-container" href="./index.html"><img class="rust-logo" src="./static.files/rust-logo-9a9549ea.svg" alt="logo"></a><h2><a href="./index.html">Rustdoc</a><span class="version">1.87.0</span></h2></div><div class="version">(17067e9ac 2025-05-09)</div><h2 class="location">Settings</h2><div class="sidebar-elems"></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Rustdoc settings</h1><span class="out-of-band"><a id="back" href="javascript:void(0)" onclick="history.back();">Back</a></span></div><noscript><section>You need to enable JavaScript be able to update your settings.</section></noscript><script defer src="./static.files/settings-d72f25bb.js"></script></section></div></main></body></html>

3
target/doc/src-files.js Normal file
View File

@@ -0,0 +1,3 @@
var srcIndex = new Map(JSON.parse('[["chrs_agent",["",[],["main.rs"]]],["chrs_bubble",["",[],["lib.rs"]]],["chrs_graph",["",[],["lib.rs"]]],["chrs_mail",["",[],["lib.rs"]]],["chrs_poc",["",[],["main.rs"]]],["chrs_shhh",["",[],["lib.rs"]]],["chrs_slurp",["",[],["lib.rs"]]],["chrs_sync",["",[],["lib.rs"]]],["ucxl",["",[],["lib.rs","watcher.rs"]]]]'));
createSrcSidebar();
//{"start":36,"fragment_lengths":[34,35,34,33,33,33,34,33,41]}

View File

@@ -0,0 +1,115 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `chrs-agent/src/main.rs`."><title>main.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="chrs_agent" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../../static.files/storage-82c7156e.js"></script><script defer src="../../static.files/src-script-63605ae7.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">chrs_agent/</div>main.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">/// chrs-agent crate implements the core CHORUS agent runtime.
<a href=#2 id=2 data-nosnippet>2</a>///
<a href=#3 id=3 data-nosnippet>3</a>/// An agent runs a message loop that receives tasks from a `Mailbox`, logs them to a
<a href=#4 id=4 data-nosnippet>4</a>/// `DoltGraph` (the persistent state graph), and marks them as read. The design
<a href=#5 id=5 data-nosnippet>5</a>/// follows the CHORUS architectural pattern where agents are autonomous workers
<a href=#6 id=6 data-nosnippet>6</a>/// that interact through the `chrs_mail` messaging layer and maintain a provable
<a href=#7 id=7 data-nosnippet>7</a>/// execution history in the graph.
<a href=#8 id=8 data-nosnippet>8</a>
<a href=#9 id=9 data-nosnippet>9</a></span><span class="kw">use </span>chrs_graph::DoltGraph;
<a href=#10 id=10 data-nosnippet>10</a><span class="kw">use </span>chrs_mail::{Mailbox, Message};
<a href=#11 id=11 data-nosnippet>11</a><span class="kw">use </span>chrono::Utc;
<a href=#12 id=12 data-nosnippet>12</a><span class="kw">use </span>std::path::Path;
<a href=#13 id=13 data-nosnippet>13</a><span class="kw">use </span>std::time::Duration;
<a href=#14 id=14 data-nosnippet>14</a><span class="kw">use </span>tokio::time::sleep;
<a href=#15 id=15 data-nosnippet>15</a><span class="kw">use </span>uuid::Uuid;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="doccomment">/// Represents a running CHORUS agent.
<a href=#18 id=18 data-nosnippet>18</a>///
<a href=#19 id=19 data-nosnippet>19</a>/// # Fields
<a href=#20 id=20 data-nosnippet>20</a>/// * `id` Logical identifier for the agent (e.g., "agent-001").
<a href=#21 id=21 data-nosnippet>21</a>/// * `mailbox` The `Mailbox` used for interagent communication.
<a href=#22 id=22 data-nosnippet>22</a>/// * `graph` Persistence layer (`DoltGraph`) where task logs are stored.
<a href=#23 id=23 data-nosnippet>23</a>///
<a href=#24 id=24 data-nosnippet>24</a>/// # Rationale
<a href=#25 id=25 data-nosnippet>25</a>/// Agents are isolated units of work. By keeping a dedicated mailbox and a graph
<a href=#26 id=26 data-nosnippet>26</a>/// per agent we guarantee that each agent can be started, stopped, and reasoned
<a href=#27 id=27 data-nosnippet>27</a>/// about independently while still contributing to the global CHORUS state.
<a href=#28 id=28 data-nosnippet>28</a></span><span class="kw">pub struct </span>CHORUSAgent {
<a href=#29 id=29 data-nosnippet>29</a> id: String,
<a href=#30 id=30 data-nosnippet>30</a> mailbox: Mailbox,
<a href=#31 id=31 data-nosnippet>31</a> graph: DoltGraph,
<a href=#32 id=32 data-nosnippet>32</a>}
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">impl </span>CHORUSAgent {
<a href=#35 id=35 data-nosnippet>35</a> <span class="doccomment">/// Initializes a new `CHORUSAgent`.
<a href=#36 id=36 data-nosnippet>36</a> ///
<a href=#37 id=37 data-nosnippet>37</a> /// This creates the filesystem layout under `base_path`, opens or creates the
<a href=#38 id=38 data-nosnippet>38</a> /// SQLite mailbox, and initialises a `DoltGraph` for state persistence.
<a href=#39 id=39 data-nosnippet>39</a> /// It also ensures that a `task_log` table exists for recording incoming
<a href=#40 id=40 data-nosnippet>40</a> /// messages.
<a href=#41 id=41 data-nosnippet>41</a> ///
<a href=#42 id=42 data-nosnippet>42</a> /// # Parameters
<a href=#43 id=43 data-nosnippet>43</a> /// * `id` Identifier for the agent instance.
<a href=#44 id=44 data-nosnippet>44</a> /// * `base_path` Directory where the agent stores its data.
<a href=#45 id=45 data-nosnippet>45</a> ///
<a href=#46 id=46 data-nosnippet>46</a> /// Returns an instance ready to run its event loop.
<a href=#47 id=47 data-nosnippet>47</a> </span><span class="kw">async fn </span>init(id: <span class="kw-2">&amp;</span>str, base_path: <span class="kw-2">&amp;</span>Path) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, Box&lt;<span class="kw">dyn </span>std::error::Error&gt;&gt; {
<a href=#48 id=48 data-nosnippet>48</a> <span class="kw">let </span>mail_path = base_path.join(<span class="string">"mail.sqlite"</span>);
<a href=#49 id=49 data-nosnippet>49</a> <span class="kw">let </span>graph_path = base_path.join(<span class="string">"state_graph"</span>);
<a href=#50 id=50 data-nosnippet>50</a>
<a href=#51 id=51 data-nosnippet>51</a> std::fs::create_dir_all(<span class="kw-2">&amp;</span>graph_path)<span class="question-mark">?</span>;
<a href=#52 id=52 data-nosnippet>52</a>
<a href=#53 id=53 data-nosnippet>53</a> <span class="kw">let </span>mailbox = Mailbox::open(mail_path)<span class="question-mark">?</span>;
<a href=#54 id=54 data-nosnippet>54</a> <span class="kw">let </span>graph = DoltGraph::init(<span class="kw-2">&amp;</span>graph_path)<span class="question-mark">?</span>;
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a> <span class="comment">// Ensure table exists
<a href=#57 id=57 data-nosnippet>57</a> </span><span class="kw">let _ </span>= graph.create_table(<span class="string">"task_log"</span>, <span class="string">"id TEXT PRIMARY KEY, topic TEXT, payload TEXT, received_at TEXT"</span>);
<a href=#58 id=58 data-nosnippet>58</a>
<a href=#59 id=59 data-nosnippet>59</a> <span class="prelude-val">Ok</span>(<span class="self">Self </span>{
<a href=#60 id=60 data-nosnippet>60</a> id: id.to_string(),
<a href=#61 id=61 data-nosnippet>61</a> mailbox,
<a href=#62 id=62 data-nosnippet>62</a> graph,
<a href=#63 id=63 data-nosnippet>63</a> })
<a href=#64 id=64 data-nosnippet>64</a> }
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a> <span class="doccomment">/// Main event loop of the agent.
<a href=#67 id=67 data-nosnippet>67</a> ///
<a href=#68 id=68 data-nosnippet>68</a> /// It repeatedly polls the mailbox for pending messages addressed to this
<a href=#69 id=69 data-nosnippet>69</a> /// agent, logs each message into the `task_log` table, commits the graph, and
<a href=#70 id=70 data-nosnippet>70</a> /// acknowledges the message. The loop sleeps for a configurable interval to
<a href=#71 id=71 data-nosnippet>71</a> /// avoid busywaiting.
<a href=#72 id=72 data-nosnippet>72</a> </span><span class="kw">async fn </span>run_loop(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<a href=#73 id=73 data-nosnippet>73</a> <span class="macro">println!</span>(<span class="string">"Agent {} starting run loop..."</span>, <span class="self">self</span>.id);
<a href=#74 id=74 data-nosnippet>74</a> <span class="kw">loop </span>{
<a href=#75 id=75 data-nosnippet>75</a> <span class="kw">match </span><span class="self">self</span>.mailbox.receive_pending(<span class="kw-2">&amp;</span><span class="self">self</span>.id) {
<a href=#76 id=76 data-nosnippet>76</a> <span class="prelude-val">Ok</span>(messages) =&gt; {
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">for </span>msg <span class="kw">in </span>messages {
<a href=#78 id=78 data-nosnippet>78</a> <span class="macro">println!</span>(<span class="string">"Received message: {:?}"</span>, msg.topic);
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">let </span>log_entry = <span class="macro">serde_json::json!</span>({
<a href=#80 id=80 data-nosnippet>80</a> <span class="string">"id"</span>: msg.id.to_string(),
<a href=#81 id=81 data-nosnippet>81</a> <span class="string">"topic"</span>: msg.topic,
<a href=#82 id=82 data-nosnippet>82</a> <span class="string">"payload"</span>: msg.payload.to_string(),
<a href=#83 id=83 data-nosnippet>83</a> <span class="string">"received_at"</span>: Utc::now().to_rfc3339()
<a href=#84 id=84 data-nosnippet>84</a> });
<a href=#85 id=85 data-nosnippet>85</a> <span class="kw">if let </span><span class="prelude-val">Err</span>(e) = <span class="self">self</span>.graph.insert_node(<span class="string">"task_log"</span>, log_entry) {
<a href=#86 id=86 data-nosnippet>86</a> <span class="macro">eprintln!</span>(<span class="string">"Failed to log task to graph: {}"</span>, e);
<a href=#87 id=87 data-nosnippet>87</a> } <span class="kw">else </span>{
<a href=#88 id=88 data-nosnippet>88</a> <span class="kw">let _ </span>= <span class="self">self</span>.graph.commit(<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"Logged task: {}"</span>, msg.id));
<a href=#89 id=89 data-nosnippet>89</a> <span class="kw">let _ </span>= <span class="self">self</span>.mailbox.mark_read(msg.id);
<a href=#90 id=90 data-nosnippet>90</a> }
<a href=#91 id=91 data-nosnippet>91</a> }
<a href=#92 id=92 data-nosnippet>92</a> }
<a href=#93 id=93 data-nosnippet>93</a> <span class="prelude-val">Err</span>(e) =&gt; <span class="macro">eprintln!</span>(<span class="string">"Mailbox error: {}"</span>, e),
<a href=#94 id=94 data-nosnippet>94</a> }
<a href=#95 id=95 data-nosnippet>95</a> sleep(Duration::from_secs(<span class="number">5</span>)).<span class="kw">await</span>;
<a href=#96 id=96 data-nosnippet>96</a> }
<a href=#97 id=97 data-nosnippet>97</a> }
<a href=#98 id=98 data-nosnippet>98</a>}
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a><span class="doccomment">/// Entry point for the CHORUS agent binary.
<a href=#101 id=101 data-nosnippet>101</a>///
<a href=#102 id=102 data-nosnippet>102</a>/// It creates a data directory under `/home/Tony/rust/projects/reset/CHORUS/data`
<a href=#103 id=103 data-nosnippet>103</a>/// (note the capitalised `Tony` matches the original path), initialises the
<a href=#104 id=104 data-nosnippet>104</a>/// `CHORUSAgent`, and starts its run loop.
<a href=#105 id=105 data-nosnippet>105</a></span><span class="attr">#[tokio::main]
<a href=#106 id=106 data-nosnippet>106</a></span><span class="kw">async fn </span>main() -&gt; <span class="prelude-ty">Result</span>&lt;(), Box&lt;<span class="kw">dyn </span>std::error::Error&gt;&gt; {
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">let </span>agent_id = <span class="string">"agent-001"</span>;
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">let </span>base_path = Path::new(<span class="string">"/home/Tony/rust/projects/reset/CHORUS/data/agent-001"</span>);
<a href=#109 id=109 data-nosnippet>109</a> std::fs::create_dir_all(base_path)<span class="question-mark">?</span>;
<a href=#110 id=110 data-nosnippet>110</a>
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">let </span>agent = CHORUSAgent::init(agent_id, base_path).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#112 id=112 data-nosnippet>112</a> agent.run_loop().<span class="kw">await</span>;
<a href=#113 id=113 data-nosnippet>113</a>
<a href=#114 id=114 data-nosnippet>114</a> <span class="prelude-val">Ok</span>(())
<a href=#115 id=115 data-nosnippet>115</a>}</code></pre></div></section></main></body></html>

View File

@@ -0,0 +1,217 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `chrs-bubble/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="chrs_bubble" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../../static.files/storage-82c7156e.js"></script><script defer src="../../static.files/src-script-63605ae7.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">chrs_bubble/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">/// # chrs-bubble
<a href=#2 id=2 data-nosnippet>2</a>///
<a href=#3 id=3 data-nosnippet>3</a>/// A provenancetracking crate that records nodes and edges in a directed acyclic
<a href=#4 id=4 data-nosnippet>4</a>/// graph (DAG) and persists them using a Doltbacked graph implementation.
<a href=#5 id=5 data-nosnippet>5</a>/// The crate is deliberately small it only pulls in `petgraph` for the inmemory
<a href=#6 id=6 data-nosnippet>6</a>/// DAG, `serde` for serialization, `uuid` for unique identifiers and `thiserror`
<a href=#7 id=7 data-nosnippet>7</a>/// for ergonomic error handling. It is used by higherlevel components that need
<a href=#8 id=8 data-nosnippet>8</a>/// to capture the provenance of generated artifacts (e.g. files, messages, or
<a href=#9 id=9 data-nosnippet>9</a>/// results) and later query that history.
<a href=#10 id=10 data-nosnippet>10</a>///
<a href=#11 id=11 data-nosnippet>11</a>/// The public API is organised around three concepts:
<a href=#12 id=12 data-nosnippet>12</a>/// * **ProvenanceEdge** The type of relationship between two nodes.
<a href=#13 id=13 data-nosnippet>13</a>/// * **BubbleError** Errors that can occur when interacting with the underlying
<a href=#14 id=14 data-nosnippet>14</a>/// Dolt graph or when a node cannot be found.
<a href=#15 id=15 data-nosnippet>15</a>/// * **ProvenanceGraph** The façade that holds an inmemory DAG and a
<a href=#16 id=16 data-nosnippet>16</a>/// `DoltGraph` persistence layer, exposing methods to record nodes and links.
<a href=#17 id=17 data-nosnippet>17</a>///
<a href=#18 id=18 data-nosnippet>18</a>/// Each item is documented with a *WHAT*, *HOW* and *WHY* section so that users can
<a href=#19 id=19 data-nosnippet>19</a>/// quickly understand its purpose, its implementation details and the design
<a href=#20 id=20 data-nosnippet>20</a>/// rationale.
<a href=#21 id=21 data-nosnippet>21</a></span><span class="kw">use </span>chrs_graph::{DoltGraph, GraphError};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>petgraph::graph::{DiGraph, NodeIndex};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>serde::{Deserialize, Serialize};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>std::collections::HashMap;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>thiserror::Error;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>ucxl::UCXLAddress;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>uuid::Uuid;
<a href=#28 id=28 data-nosnippet>28</a>
<a href=#29 id=29 data-nosnippet>29</a><span class="doccomment">/// Represents the kind of relationship between two provenance nodes.
<a href=#30 id=30 data-nosnippet>30</a>///
<a href=#31 id=31 data-nosnippet>31</a>/// * **WHAT** An enumeration of supported edge types. Currently we support:
<a href=#32 id=32 data-nosnippet>32</a>/// - `DerivedFrom` Indicates that the target was derived from the source.
<a href=#33 id=33 data-nosnippet>33</a>/// - `Cites` A citation relationship.
<a href=#34 id=34 data-nosnippet>34</a>/// - `InfluencedBy` Denotes influence without direct derivation.
<a href=#35 id=35 data-nosnippet>35</a>/// * **HOW** Used as the edge payload in the `petgraph::DiGraph`. The enum is
<a href=#36 id=36 data-nosnippet>36</a>/// `#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]` so it
<a href=#37 id=37 data-nosnippet>37</a>/// can be serialised when persisting the graph.
<a href=#38 id=38 data-nosnippet>38</a>/// * **WHY** Encoding edge semantics as a dedicated enum makes provenance
<a href=#39 id=39 data-nosnippet>39</a>/// queries expressive and typesafe, while keeping the ondisk representation
<a href=#40 id=40 data-nosnippet>40</a>/// simple (a stringified variant).
<a href=#41 id=41 data-nosnippet>41</a></span><span class="attr">#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
<a href=#42 id=42 data-nosnippet>42</a></span><span class="kw">pub enum </span>ProvenanceEdge {
<a href=#43 id=43 data-nosnippet>43</a> <span class="doccomment">/// The target node was *derived* from the source node.
<a href=#44 id=44 data-nosnippet>44</a> </span>DerivedFrom,
<a href=#45 id=45 data-nosnippet>45</a> <span class="doccomment">/// The target node *cites* the source node.
<a href=#46 id=46 data-nosnippet>46</a> </span>Cites,
<a href=#47 id=47 data-nosnippet>47</a> <span class="doccomment">/// The target node was *influenced* by the source node.
<a href=#48 id=48 data-nosnippet>48</a> </span>InfluencedBy,
<a href=#49 id=49 data-nosnippet>49</a>}
<a href=#50 id=50 data-nosnippet>50</a>
<a href=#51 id=51 data-nosnippet>51</a><span class="doccomment">/// Errors that can arise when working with a `ProvenanceGraph`.
<a href=#52 id=52 data-nosnippet>52</a>///
<a href=#53 id=53 data-nosnippet>53</a>/// * **WHAT** Enumerates possible failure modes:
<a href=#54 id=54 data-nosnippet>54</a>/// - Graphlevel errors (`GraphError`).
<a href=#55 id=55 data-nosnippet>55</a>/// - Serde JSON errors (`serde_json::Error`).
<a href=#56 id=56 data-nosnippet>56</a>/// - A lookup failure when a node identifier cannot be resolved.
<a href=#57 id=57 data-nosnippet>57</a>/// * **HOW** Implements `std::error::Error` via the `thiserror::Error` derive
<a href=#58 id=58 data-nosnippet>58</a>/// macro, forwarding underlying error sources with `#[from]`.
<a href=#59 id=59 data-nosnippet>59</a>/// * **WHY** A single error type simplifies error propagation for callers and
<a href=#60 id=60 data-nosnippet>60</a>/// retains the original context for debugging.
<a href=#61 id=61 data-nosnippet>61</a></span><span class="attr">#[derive(Debug, Error)]
<a href=#62 id=62 data-nosnippet>62</a></span><span class="kw">pub enum </span>BubbleError {
<a href=#63 id=63 data-nosnippet>63</a> <span class="attr">#[error(<span class="string">"Graph error: {0}"</span>)]
<a href=#64 id=64 data-nosnippet>64</a> </span>Graph(<span class="attr">#[from] </span>GraphError),
<a href=#65 id=65 data-nosnippet>65</a> <span class="attr">#[error(<span class="string">"Serde error: {0}"</span>)]
<a href=#66 id=66 data-nosnippet>66</a> </span>Serde(<span class="attr">#[from] </span>serde_json::Error),
<a href=#67 id=67 data-nosnippet>67</a> <span class="attr">#[error(<span class="string">"Node not found: {0}"</span>)]
<a href=#68 id=68 data-nosnippet>68</a> </span>NodeNotFound(Uuid),
<a href=#69 id=69 data-nosnippet>69</a>}
<a href=#70 id=70 data-nosnippet>70</a>
<a href=#71 id=71 data-nosnippet>71</a><span class="doccomment">/// Core structure that maintains an inmemory DAG of provenance nodes and a
<a href=#72 id=72 data-nosnippet>72</a>/// persistent `DoltGraph` backend.
<a href=#73 id=73 data-nosnippet>73</a>///
<a href=#74 id=74 data-nosnippet>74</a>/// * **WHAT** Holds:
<a href=#75 id=75 data-nosnippet>75</a>/// - `persistence`: The Doltbased storage implementation.
<a href=#76 id=76 data-nosnippet>76</a>/// - `dag`: A `petgraph::DiGraph` where node payloads are UUIDs and edges are
<a href=#77 id=77 data-nosnippet>77</a>/// `ProvenanceEdge`s.
<a href=#78 id=78 data-nosnippet>78</a>/// - `node_map`: A fast lookup map from node UUID to the corresponding
<a href=#79 id=79 data-nosnippet>79</a>/// `petgraph::NodeIndex`.
<a href=#80 id=80 data-nosnippet>80</a>/// * **HOW** Provides methods to create nodes (`record_node`) and edges
<a href=#81 id=81 data-nosnippet>81</a>/// (`record_link`). These methods insert into the inmemory graph and then
<a href=#82 id=82 data-nosnippet>82</a>/// persist the data in Dolt tables using simple `INSERT` statements followed by
<a href=#83 id=83 data-nosnippet>83</a>/// a `commit`.
<a href=#84 id=84 data-nosnippet>84</a>/// * **WHY** Separating the transient inmemory representation from durable
<a href=#85 id=85 data-nosnippet>85</a>/// storage gives fast runtime queries while guaranteeing that the provenance
<a href=#86 id=86 data-nosnippet>86</a>/// graph can survive process restarts and be inspected via Dolt tools.
<a href=#87 id=87 data-nosnippet>87</a></span><span class="kw">pub struct </span>ProvenanceGraph {
<a href=#88 id=88 data-nosnippet>88</a> persistence: DoltGraph,
<a href=#89 id=89 data-nosnippet>89</a> dag: DiGraph&lt;Uuid, ProvenanceEdge&gt;,
<a href=#90 id=90 data-nosnippet>90</a> node_map: HashMap&lt;Uuid, NodeIndex&gt;,
<a href=#91 id=91 data-nosnippet>91</a>}
<a href=#92 id=92 data-nosnippet>92</a>
<a href=#93 id=93 data-nosnippet>93</a><span class="kw">impl </span>ProvenanceGraph {
<a href=#94 id=94 data-nosnippet>94</a> <span class="doccomment">/// Creates a new `ProvenanceGraph` backed by a preinitialised `DoltGraph`.
<a href=#95 id=95 data-nosnippet>95</a> ///
<a href=#96 id=96 data-nosnippet>96</a> /// * **WHAT** Returns a fresh instance with empty inmemory structures.
<a href=#97 id=97 data-nosnippet>97</a> /// * **HOW** Stores the supplied `persistence` and constructs a new `DiGraph`
<a href=#98 id=98 data-nosnippet>98</a> /// and empty `HashMap`.
<a href=#99 id=99 data-nosnippet>99</a> /// * **WHY** Allows callers to decide where the Dolt repository lives (e.g.
<a href=#100 id=100 data-nosnippet>100</a> /// a temporary directory for tests or a permanent location for production).
<a href=#101 id=101 data-nosnippet>101</a> </span><span class="kw">pub fn </span>new(persistence: DoltGraph) -&gt; <span class="self">Self </span>{
<a href=#102 id=102 data-nosnippet>102</a> <span class="self">Self </span>{
<a href=#103 id=103 data-nosnippet>103</a> persistence,
<a href=#104 id=104 data-nosnippet>104</a> dag: DiGraph::new(),
<a href=#105 id=105 data-nosnippet>105</a> node_map: HashMap::new(),
<a href=#106 id=106 data-nosnippet>106</a> }
<a href=#107 id=107 data-nosnippet>107</a> }
<a href=#108 id=108 data-nosnippet>108</a>
<a href=#109 id=109 data-nosnippet>109</a> <span class="doccomment">/// Records a provenance node with a unique `Uuid` and an associated address.
<a href=#110 id=110 data-nosnippet>110</a> ///
<a href=#111 id=111 data-nosnippet>111</a> /// * **WHAT** Persists the node both inmemory (`dag` + `node_map`) and in a
<a href=#112 id=112 data-nosnippet>112</a> /// Dolt table called `provenance_nodes`.
<a href=#113 id=113 data-nosnippet>113</a> /// * **HOW** If the node does not already exist, it is added to the DAG and a
<a href=#114 id=114 data-nosnippet>114</a> /// row is inserted via `persistence.insert_node`. A commit is performed with a
<a href=#115 id=115 data-nosnippet>115</a> /// descriptive message.
<a href=#116 id=116 data-nosnippet>116</a> /// * **WHY** Storing the address (typically a UCXL address) allows later
<a href=#117 id=117 data-nosnippet>117</a> /// resolution of where the artifact originated.
<a href=#118 id=118 data-nosnippet>118</a> </span><span class="kw">pub fn </span>record_node(<span class="kw-2">&amp;mut </span><span class="self">self</span>, id: Uuid, address: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;(), BubbleError&gt; {
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw">if </span>!<span class="self">self</span>.node_map.contains_key(<span class="kw-2">&amp;</span>id) {
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw">let </span>idx = <span class="self">self</span>.dag.add_node(id);
<a href=#121 id=121 data-nosnippet>121</a> <span class="self">self</span>.node_map.insert(id, idx);
<a href=#122 id=122 data-nosnippet>122</a>
<a href=#123 id=123 data-nosnippet>123</a> <span class="comment">// Ensure the backing table exists ignore errors if it already does.
<a href=#124 id=124 data-nosnippet>124</a> </span><span class="self">self</span>.persistence
<a href=#125 id=125 data-nosnippet>125</a> .create_table(
<a href=#126 id=126 data-nosnippet>126</a> <span class="string">"provenance_nodes"</span>,
<a href=#127 id=127 data-nosnippet>127</a> <span class="string">"id VARCHAR(255) PRIMARY KEY, address TEXT"</span>,
<a href=#128 id=128 data-nosnippet>128</a> )
<a href=#129 id=129 data-nosnippet>129</a> .ok();
<a href=#130 id=130 data-nosnippet>130</a>
<a href=#131 id=131 data-nosnippet>131</a> <span class="kw">let </span>data = <span class="macro">serde_json::json!</span>({
<a href=#132 id=132 data-nosnippet>132</a> <span class="string">"id"</span>: id.to_string(),
<a href=#133 id=133 data-nosnippet>133</a> <span class="string">"address"</span>: address,
<a href=#134 id=134 data-nosnippet>134</a> });
<a href=#135 id=135 data-nosnippet>135</a> <span class="self">self</span>.persistence.insert_node(<span class="string">"provenance_nodes"</span>, data)<span class="question-mark">?</span>;
<a href=#136 id=136 data-nosnippet>136</a> <span class="self">self</span>.persistence
<a href=#137 id=137 data-nosnippet>137</a> .commit(<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"Record provenance node: {}"</span>, id))<span class="question-mark">?</span>;
<a href=#138 id=138 data-nosnippet>138</a> }
<a href=#139 id=139 data-nosnippet>139</a> <span class="prelude-val">Ok</span>(())
<a href=#140 id=140 data-nosnippet>140</a> }
<a href=#141 id=141 data-nosnippet>141</a>
<a href=#142 id=142 data-nosnippet>142</a> <span class="doccomment">/// Records a directed edge between two existing nodes.
<a href=#143 id=143 data-nosnippet>143</a> ///
<a href=#144 id=144 data-nosnippet>144</a> /// * **WHAT** Adds an edge of type `ProvenanceEdge` to the DAG and stores a
<a href=#145 id=145 data-nosnippet>145</a> /// corresponding row in the `provenance_links` Dolt table.
<a href=#146 id=146 data-nosnippet>146</a> /// * **HOW** Retrieves the `NodeIndex` for each UUID (erroring with
<a href=#147 id=147 data-nosnippet>147</a> /// `BubbleError::NodeNotFound` if missing), adds the edge to `dag`, then
<a href=#148 id=148 data-nosnippet>148</a> /// inserts a row containing a new link UUID, source/target IDs and the edge
<a href=#149 id=149 data-nosnippet>149</a> /// type as a string.
<a href=#150 id=150 data-nosnippet>150</a> /// * **WHY** Persisting links allows the full provenance graph to be queried
<a href=#151 id=151 data-nosnippet>151</a> /// outside the process, while the inmemory representation keeps runtime
<a href=#152 id=152 data-nosnippet>152</a> /// operations cheap.
<a href=#153 id=153 data-nosnippet>153</a> </span><span class="kw">pub fn </span>record_link(
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#155 id=155 data-nosnippet>155</a> source: Uuid,
<a href=#156 id=156 data-nosnippet>156</a> target: Uuid,
<a href=#157 id=157 data-nosnippet>157</a> edge: ProvenanceEdge,
<a href=#158 id=158 data-nosnippet>158</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;(), BubbleError&gt; {
<a href=#159 id=159 data-nosnippet>159</a> <span class="kw">let </span>source_idx = <span class="kw-2">*</span><span class="self">self
<a href=#160 id=160 data-nosnippet>160</a> </span>.node_map
<a href=#161 id=161 data-nosnippet>161</a> .get(<span class="kw-2">&amp;</span>source)
<a href=#162 id=162 data-nosnippet>162</a> .ok_or(BubbleError::NodeNotFound(source))<span class="question-mark">?</span>;
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">let </span>target_idx = <span class="kw-2">*</span><span class="self">self
<a href=#164 id=164 data-nosnippet>164</a> </span>.node_map
<a href=#165 id=165 data-nosnippet>165</a> .get(<span class="kw-2">&amp;</span>target)
<a href=#166 id=166 data-nosnippet>166</a> .ok_or(BubbleError::NodeNotFound(target))<span class="question-mark">?</span>;
<a href=#167 id=167 data-nosnippet>167</a>
<a href=#168 id=168 data-nosnippet>168</a> <span class="self">self</span>.dag.add_edge(source_idx, target_idx, edge);
<a href=#169 id=169 data-nosnippet>169</a>
<a href=#170 id=170 data-nosnippet>170</a> <span class="comment">// Ensure the links table exists.
<a href=#171 id=171 data-nosnippet>171</a> </span><span class="self">self</span>.persistence
<a href=#172 id=172 data-nosnippet>172</a> .create_table(
<a href=#173 id=173 data-nosnippet>173</a> <span class="string">"provenance_links"</span>,
<a href=#174 id=174 data-nosnippet>174</a> <span class="string">"id VARCHAR(255) PRIMARY KEY, source_id TEXT, target_id TEXT, edge_type TEXT"</span>,
<a href=#175 id=175 data-nosnippet>175</a> )
<a href=#176 id=176 data-nosnippet>176</a> .ok();
<a href=#177 id=177 data-nosnippet>177</a>
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">let </span>link_id = Uuid::new_v4();
<a href=#179 id=179 data-nosnippet>179</a> <span class="kw">let </span>data = <span class="macro">serde_json::json!</span>({
<a href=#180 id=180 data-nosnippet>180</a> <span class="string">"id"</span>: link_id.to_string(),
<a href=#181 id=181 data-nosnippet>181</a> <span class="string">"source_id"</span>: source.to_string(),
<a href=#182 id=182 data-nosnippet>182</a> <span class="string">"target_id"</span>: target.to_string(),
<a href=#183 id=183 data-nosnippet>183</a> <span class="string">"edge_type"</span>: <span class="macro">format!</span>(<span class="string">"{:?}"</span>, edge),
<a href=#184 id=184 data-nosnippet>184</a> });
<a href=#185 id=185 data-nosnippet>185</a> <span class="self">self</span>.persistence.insert_node(<span class="string">"provenance_links"</span>, data)<span class="question-mark">?</span>;
<a href=#186 id=186 data-nosnippet>186</a> <span class="self">self</span>.persistence
<a href=#187 id=187 data-nosnippet>187</a> .commit(<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"Record provenance link: {} -&gt; {}"</span>, source, target))<span class="question-mark">?</span>;
<a href=#188 id=188 data-nosnippet>188</a> <span class="prelude-val">Ok</span>(())
<a href=#189 id=189 data-nosnippet>189</a> }
<a href=#190 id=190 data-nosnippet>190</a>}
<a href=#191 id=191 data-nosnippet>191</a>
<a href=#192 id=192 data-nosnippet>192</a><span class="attr">#[cfg(test)]
<a href=#193 id=193 data-nosnippet>193</a></span><span class="kw">mod </span>tests {
<a href=#194 id=194 data-nosnippet>194</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
<a href=#195 id=195 data-nosnippet>195</a> <span class="kw">use </span>tempfile::TempDir;
<a href=#196 id=196 data-nosnippet>196</a>
<a href=#197 id=197 data-nosnippet>197</a> <span class="attr">#[test]
<a href=#198 id=198 data-nosnippet>198</a> </span><span class="kw">fn </span>test_provenance_dag() {
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">let </span>dir = TempDir::new().unwrap();
<a href=#200 id=200 data-nosnippet>200</a> <span class="kw">let </span>persistence = DoltGraph::init(dir.path()).expect(<span class="string">"dolt init failed"</span>);
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">let </span><span class="kw-2">mut </span>graph = ProvenanceGraph::new(persistence);
<a href=#202 id=202 data-nosnippet>202</a>
<a href=#203 id=203 data-nosnippet>203</a> <span class="kw">let </span>id1 = Uuid::new_v4();
<a href=#204 id=204 data-nosnippet>204</a> <span class="kw">let </span>id2 = Uuid::new_v4();
<a href=#205 id=205 data-nosnippet>205</a>
<a href=#206 id=206 data-nosnippet>206</a> graph
<a href=#207 id=207 data-nosnippet>207</a> .record_node(id1, <span class="string">"ucxl://agent:1@proj:task/#/file1.txt"</span>)
<a href=#208 id=208 data-nosnippet>208</a> .unwrap();
<a href=#209 id=209 data-nosnippet>209</a> graph
<a href=#210 id=210 data-nosnippet>210</a> .record_node(id2, <span class="string">"ucxl://agent:1@proj:task/#/file2.txt"</span>)
<a href=#211 id=211 data-nosnippet>211</a> .unwrap();
<a href=#212 id=212 data-nosnippet>212</a>
<a href=#213 id=213 data-nosnippet>213</a> graph
<a href=#214 id=214 data-nosnippet>214</a> .record_link(id1, id2, ProvenanceEdge::DerivedFrom)
<a href=#215 id=215 data-nosnippet>215</a> .unwrap();
<a href=#216 id=216 data-nosnippet>216</a> }
<a href=#217 id=217 data-nosnippet>217</a>}</code></pre></div></section></main></body></html>

View File

@@ -0,0 +1,167 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `chrs-graph/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="chrs_graph" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../../static.files/storage-82c7156e.js"></script><script defer src="../../static.files/src-script-63605ae7.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">chrs_graph/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! chrs-graph library implementation using Dolt for graph persistence.
<a href=#2 id=2 data-nosnippet>2</a>
<a href=#3 id=3 data-nosnippet>3</a></span><span class="kw">use </span>chrono::Utc;
<a href=#4 id=4 data-nosnippet>4</a><span class="kw">use </span>serde_json::Value;
<a href=#5 id=5 data-nosnippet>5</a><span class="kw">use </span>std::{path::Path, process::Command};
<a href=#6 id=6 data-nosnippet>6</a><span class="kw">use </span>thiserror::Error;
<a href=#7 id=7 data-nosnippet>7</a><span class="kw">use </span>uuid::Uuid;
<a href=#8 id=8 data-nosnippet>8</a>
<a href=#9 id=9 data-nosnippet>9</a><span class="doccomment">/// Enumeration of possible errors that can arise while interacting with the `DoltGraph`.
<a href=#10 id=10 data-nosnippet>10</a>///
<a href=#11 id=11 data-nosnippet>11</a>/// Each variant wraps an underlying error source, making it easier for callers to
<a href=#12 id=12 data-nosnippet>12</a>/// understand the failure context and decide on remedial actions.
<a href=#13 id=13 data-nosnippet>13</a></span><span class="attr">#[derive(Error, Debug)]
<a href=#14 id=14 data-nosnippet>14</a></span><span class="kw">pub enum </span>GraphError {
<a href=#15 id=15 data-nosnippet>15</a> <span class="doccomment">/// Propagates I/O errors from the standard library (e.g., filesystem access).
<a href=#16 id=16 data-nosnippet>16</a> </span><span class="attr">#[error(<span class="string">"IO error: {0}"</span>)]
<a href=#17 id=17 data-nosnippet>17</a> </span>Io(<span class="attr">#[from] </span>std::io::Error),
<a href=#18 id=18 data-nosnippet>18</a> <span class="doccomment">/// Represents a failure when executing a Dolt command.
<a href=#19 id=19 data-nosnippet>19</a> </span><span class="attr">#[error(<span class="string">"Command failed: {0}"</span>)]
<a href=#20 id=20 data-nosnippet>20</a> </span>CommandFailed(String),
<a href=#21 id=21 data-nosnippet>21</a> <span class="doccomment">/// Propagates JSON (de)serialization errors from `serde_json`.
<a href=#22 id=22 data-nosnippet>22</a> </span><span class="attr">#[error(<span class="string">"Serde JSON error: {0}"</span>)]
<a href=#23 id=23 data-nosnippet>23</a> </span>SerdeJson(<span class="attr">#[from] </span>serde_json::Error),
<a href=#24 id=24 data-nosnippet>24</a> <span class="doccomment">/// A generic catchall for errors that don't fit the other categories.
<a href=#25 id=25 data-nosnippet>25</a> </span><span class="attr">#[error(<span class="string">"Other error: {0}"</span>)]
<a href=#26 id=26 data-nosnippet>26</a> </span>Other(String),
<a href=#27 id=27 data-nosnippet>27</a>}
<a href=#28 id=28 data-nosnippet>28</a>
<a href=#29 id=29 data-nosnippet>29</a><span class="doccomment">/// Wrapper around a Dolt repository that stores graph data.
<a href=#30 id=30 data-nosnippet>30</a>///
<a href=#31 id=31 data-nosnippet>31</a>/// The `DoltGraph` type encapsulates a path to a Dolt repo and provides highlevel
<a href=#32 id=32 data-nosnippet>32</a>/// operations such as initializing the repo, committing changes, creating tables, and
<a href=#33 id=33 data-nosnippet>33</a>/// inserting nodes expressed as JSON objects.
<a href=#34 id=34 data-nosnippet>34</a>///
<a href=#35 id=35 data-nosnippet>35</a>/// # Architectural Rationale
<a href=#36 id=36 data-nosnippet>36</a>/// Dolt offers a Gitlike versioncontrolled SQL database, which aligns well with CHORUS's
<a href=#37 id=37 data-nosnippet>37</a>/// need for an immutable, queryable history of graph mutations. By wrapping Dolt commands in
<a href=#38 id=38 data-nosnippet>38</a>/// this struct we isolate the rest of the codebase from the commandline interface, making the
<a href=#39 id=39 data-nosnippet>39</a>/// graph layer portable and easier to test.
<a href=#40 id=40 data-nosnippet>40</a></span><span class="kw">pub struct </span>DoltGraph {
<a href=#41 id=41 data-nosnippet>41</a> <span class="doccomment">/// Filesystem path to the root of the Dolt repository.
<a href=#42 id=42 data-nosnippet>42</a> </span><span class="kw">pub </span>repo_path: std::path::PathBuf,
<a href=#43 id=43 data-nosnippet>43</a>}
<a href=#44 id=44 data-nosnippet>44</a>
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">impl </span>DoltGraph {
<a href=#46 id=46 data-nosnippet>46</a> <span class="doccomment">/// Initialise (or open) a Dolt repository at the given `path`.
<a href=#47 id=47 data-nosnippet>47</a> ///
<a href=#48 id=48 data-nosnippet>48</a> /// If the directory does not already contain a `.dolt` subdirectory, the function runs
<a href=#49 id=49 data-nosnippet>49</a> /// `dolt init` to create a new repository. Errors from the underlying command are wrapped in
<a href=#50 id=50 data-nosnippet>50</a> /// `GraphError::CommandFailed`.
<a href=#51 id=51 data-nosnippet>51</a> </span><span class="kw">pub fn </span>init(path: <span class="kw-2">&amp;</span>Path) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, GraphError&gt; {
<a href=#52 id=52 data-nosnippet>52</a> <span class="kw">if </span>!path.join(<span class="string">".dolt"</span>).exists() {
<a href=#53 id=53 data-nosnippet>53</a> <span class="kw">let </span>status = Command::new(<span class="string">"dolt"</span>)
<a href=#54 id=54 data-nosnippet>54</a> .arg(<span class="string">"init"</span>)
<a href=#55 id=55 data-nosnippet>55</a> .current_dir(path)
<a href=#56 id=56 data-nosnippet>56</a> .status()<span class="question-mark">?</span>;
<a href=#57 id=57 data-nosnippet>57</a> <span class="kw">if </span>!status.success() {
<a href=#58 id=58 data-nosnippet>58</a> <span class="kw">return </span><span class="prelude-val">Err</span>(GraphError::CommandFailed(<span class="macro">format!</span>(
<a href=#59 id=59 data-nosnippet>59</a> <span class="string">"dolt init failed with status {:?}"</span>,
<a href=#60 id=60 data-nosnippet>60</a> status
<a href=#61 id=61 data-nosnippet>61</a> )));
<a href=#62 id=62 data-nosnippet>62</a> }
<a href=#63 id=63 data-nosnippet>63</a> }
<a href=#64 id=64 data-nosnippet>64</a> <span class="prelude-val">Ok</span>(<span class="self">Self </span>{
<a href=#65 id=65 data-nosnippet>65</a> repo_path: path.to_path_buf(),
<a href=#66 id=66 data-nosnippet>66</a> })
<a href=#67 id=67 data-nosnippet>67</a> }
<a href=#68 id=68 data-nosnippet>68</a>
<a href=#69 id=69 data-nosnippet>69</a> <span class="doccomment">/// Execute a Dolt command with the specified arguments.
<a href=#70 id=70 data-nosnippet>70</a> ///
<a href=#71 id=71 data-nosnippet>71</a> /// This helper centralises command execution and error handling. It runs `dolt` with the
<a href=#72 id=72 data-nosnippet>72</a> /// provided argument slice, captures stdout/stderr, and returns `GraphError::CommandFailed`
<a href=#73 id=73 data-nosnippet>73</a> /// when the command exits with a nonzero status.
<a href=#74 id=74 data-nosnippet>74</a> </span><span class="kw">fn </span>run_cmd(<span class="kw-2">&amp;</span><span class="self">self</span>, args: <span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span>str]) -&gt; <span class="prelude-ty">Result</span>&lt;(), GraphError&gt; {
<a href=#75 id=75 data-nosnippet>75</a> <span class="kw">let </span>output = Command::new(<span class="string">"dolt"</span>)
<a href=#76 id=76 data-nosnippet>76</a> .args(args)
<a href=#77 id=77 data-nosnippet>77</a> .current_dir(<span class="kw-2">&amp;</span><span class="self">self</span>.repo_path)
<a href=#78 id=78 data-nosnippet>78</a> .output()<span class="question-mark">?</span>;
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">if </span>!output.status.success() {
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">let </span>stderr = String::from_utf8_lossy(<span class="kw-2">&amp;</span>output.stderr);
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">return </span><span class="prelude-val">Err</span>(GraphError::CommandFailed(stderr.to_string()));
<a href=#82 id=82 data-nosnippet>82</a> }
<a href=#83 id=83 data-nosnippet>83</a> <span class="prelude-val">Ok</span>(())
<a href=#84 id=84 data-nosnippet>84</a> }
<a href=#85 id=85 data-nosnippet>85</a>
<a href=#86 id=86 data-nosnippet>86</a> <span class="doccomment">/// Stage all changes and commit them with the provided `message`.
<a href=#87 id=87 data-nosnippet>87</a> ///
<a href=#88 id=88 data-nosnippet>88</a> /// The method first runs `dolt add -A` to stage modifications, then `dolt commit -m`.
<a href=#89 id=89 data-nosnippet>89</a> /// Any failure in these steps propagates as a `GraphError`.
<a href=#90 id=90 data-nosnippet>90</a> </span><span class="kw">pub fn </span>commit(<span class="kw-2">&amp;</span><span class="self">self</span>, message: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;(), GraphError&gt; {
<a href=#91 id=91 data-nosnippet>91</a> <span class="self">self</span>.run_cmd(<span class="kw-2">&amp;</span>[<span class="string">"add"</span>, <span class="string">"-A"</span>])<span class="question-mark">?</span>;
<a href=#92 id=92 data-nosnippet>92</a> <span class="self">self</span>.run_cmd(<span class="kw-2">&amp;</span>[<span class="string">"commit"</span>, <span class="string">"-m"</span>, message])<span class="question-mark">?</span>;
<a href=#93 id=93 data-nosnippet>93</a> <span class="prelude-val">Ok</span>(())
<a href=#94 id=94 data-nosnippet>94</a> }
<a href=#95 id=95 data-nosnippet>95</a>
<a href=#96 id=96 data-nosnippet>96</a> <span class="doccomment">/// Create a SQL table within the Dolt repository.
<a href=#97 id=97 data-nosnippet>97</a> ///
<a href=#98 id=98 data-nosnippet>98</a> /// `schema` should be a commaseparated column definition list (e.g., `"id INT PRIMARY KEY, name TEXT"`).
<a href=#99 id=99 data-nosnippet>99</a> /// If the table already exists, the function treats it as a noop and returns `Ok(())`.
<a href=#100 id=100 data-nosnippet>100</a> </span><span class="kw">pub fn </span>create_table(<span class="kw-2">&amp;</span><span class="self">self</span>, table_name: <span class="kw-2">&amp;</span>str, schema: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;(), GraphError&gt; {
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">let </span>query = <span class="macro">format!</span>(<span class="string">"CREATE TABLE {} ({})"</span>, table_name, schema);
<a href=#102 id=102 data-nosnippet>102</a> <span class="kw">if let </span><span class="prelude-val">Err</span>(e) = <span class="self">self</span>.run_cmd(<span class="kw-2">&amp;</span>[<span class="string">"sql"</span>, <span class="string">"-q"</span>, <span class="kw-2">&amp;</span>query]) {
<a href=#103 id=103 data-nosnippet>103</a> <span class="kw">if </span>e.to_string().contains(<span class="string">"already exists"</span>) {
<a href=#104 id=104 data-nosnippet>104</a> <span class="comment">// Table is already present not an error for our usecase.
<a href=#105 id=105 data-nosnippet>105</a> </span><span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#106 id=106 data-nosnippet>106</a> }
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">return </span><span class="prelude-val">Err</span>(e);
<a href=#108 id=108 data-nosnippet>108</a> }
<a href=#109 id=109 data-nosnippet>109</a> <span class="self">self</span>.commit(<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"Create table {}"</span>, table_name))<span class="question-mark">?</span>;
<a href=#110 id=110 data-nosnippet>110</a> <span class="prelude-val">Ok</span>(())
<a href=#111 id=111 data-nosnippet>111</a> }
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a> <span class="doccomment">/// Insert a node represented by a JSON object into the specified `table`.
<a href=#114 id=114 data-nosnippet>114</a> ///
<a href=#115 id=115 data-nosnippet>115</a> /// The JSON `data` must be an object where keys correspond to column names. Supported value
<a href=#116 id=116 data-nosnippet>116</a> /// types are strings, numbers, booleans, and null. Complex JSON structures are rejected because
<a href=#117 id=117 data-nosnippet>117</a> /// they cannot be directly mapped to SQL scalar columns.
<a href=#118 id=118 data-nosnippet>118</a> </span><span class="kw">pub fn </span>insert_node(<span class="kw-2">&amp;</span><span class="self">self</span>, table: <span class="kw-2">&amp;</span>str, data: Value) -&gt; <span class="prelude-ty">Result</span>&lt;(), GraphError&gt; {
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw">let </span>obj = data
<a href=#120 id=120 data-nosnippet>120</a> .as_object()
<a href=#121 id=121 data-nosnippet>121</a> .ok_or_else(|| GraphError::Other(<span class="string">"Data must be a JSON object"</span>.into()))<span class="question-mark">?</span>;
<a href=#122 id=122 data-nosnippet>122</a> <span class="kw">let </span>columns: Vec&lt;String&gt; = obj.keys().cloned().collect();
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">let </span><span class="kw-2">mut </span>values: Vec&lt;String&gt; = Vec::new();
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">for </span>key <span class="kw">in </span><span class="kw-2">&amp;</span>columns {
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw">let </span>v = <span class="kw-2">&amp;</span>obj[key];
<a href=#126 id=126 data-nosnippet>126</a> <span class="kw">let </span>sql_val = <span class="kw">match </span>v {
<a href=#127 id=127 data-nosnippet>127</a> Value::String(s) =&gt; <span class="macro">format!</span>(<span class="string">"'{}'"</span>, s.replace(<span class="string">'\''</span>, <span class="string">"''"</span>)),
<a href=#128 id=128 data-nosnippet>128</a> Value::Number(n) =&gt; n.to_string(),
<a href=#129 id=129 data-nosnippet>129</a> Value::Bool(b) =&gt; {
<a href=#130 id=130 data-nosnippet>130</a> <span class="kw">if </span><span class="kw-2">*</span>b {
<a href=#131 id=131 data-nosnippet>131</a> <span class="string">"TRUE"</span>.into()
<a href=#132 id=132 data-nosnippet>132</a> } <span class="kw">else </span>{
<a href=#133 id=133 data-nosnippet>133</a> <span class="string">"FALSE"</span>.into()
<a href=#134 id=134 data-nosnippet>134</a> }
<a href=#135 id=135 data-nosnippet>135</a> }
<a href=#136 id=136 data-nosnippet>136</a> Value::Null =&gt; <span class="string">"NULL"</span>.into(),
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">_ </span>=&gt; <span class="kw">return </span><span class="prelude-val">Err</span>(GraphError::Other(<span class="string">"Unsupported JSON value type"</span>.into())),
<a href=#138 id=138 data-nosnippet>138</a> };
<a href=#139 id=139 data-nosnippet>139</a> values.push(sql_val);
<a href=#140 id=140 data-nosnippet>140</a> }
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">let </span>query = <span class="macro">format!</span>(
<a href=#142 id=142 data-nosnippet>142</a> <span class="string">"INSERT INTO {} ({}) VALUES ({})"</span>,
<a href=#143 id=143 data-nosnippet>143</a> table,
<a href=#144 id=144 data-nosnippet>144</a> columns.join(<span class="string">", "</span>),
<a href=#145 id=145 data-nosnippet>145</a> values.join(<span class="string">", "</span>)
<a href=#146 id=146 data-nosnippet>146</a> );
<a href=#147 id=147 data-nosnippet>147</a> <span class="self">self</span>.run_cmd(<span class="kw-2">&amp;</span>[<span class="string">"sql"</span>, <span class="string">"-q"</span>, <span class="kw-2">&amp;</span>query])<span class="question-mark">?</span>;
<a href=#148 id=148 data-nosnippet>148</a> <span class="prelude-val">Ok</span>(())
<a href=#149 id=149 data-nosnippet>149</a> }
<a href=#150 id=150 data-nosnippet>150</a>}
<a href=#151 id=151 data-nosnippet>151</a>
<a href=#152 id=152 data-nosnippet>152</a><span class="attr">#[cfg(test)]
<a href=#153 id=153 data-nosnippet>153</a></span><span class="kw">mod </span>tests {
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">use </span>tempfile::TempDir;
<a href=#156 id=156 data-nosnippet>156</a>
<a href=#157 id=157 data-nosnippet>157</a> <span class="attr">#[test]
<a href=#158 id=158 data-nosnippet>158</a> </span><span class="kw">fn </span>test_init_create_table_and_commit() {
<a href=#159 id=159 data-nosnippet>159</a> <span class="kw">let </span>dir = TempDir::new().unwrap();
<a href=#160 id=160 data-nosnippet>160</a> <span class="comment">// Initialise a Dolt repository in a temporary directory.
<a href=#161 id=161 data-nosnippet>161</a> </span><span class="kw">let </span>graph = DoltGraph::init(dir.path()).expect(<span class="string">"init failed"</span>);
<a href=#162 id=162 data-nosnippet>162</a> <span class="comment">// Create a simple `nodes` table.
<a href=#163 id=163 data-nosnippet>163</a> </span>graph
<a href=#164 id=164 data-nosnippet>164</a> .create_table(<span class="string">"nodes"</span>, <span class="string">"id INT PRIMARY KEY, name TEXT"</span>)
<a href=#165 id=165 data-nosnippet>165</a> .expect(<span class="string">"create table failed"</span>);
<a href=#166 id=166 data-nosnippet>166</a> }
<a href=#167 id=167 data-nosnippet>167</a>}</code></pre></div></section></main></body></html>

View File

@@ -0,0 +1,235 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `chrs-mail/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="chrs_mail" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../../static.files/storage-82c7156e.js"></script><script defer src="../../static.files/src-script-63605ae7.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">chrs_mail/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! chrs-mail library implementation
<a href=#2 id=2 data-nosnippet>2</a>
<a href=#3 id=3 data-nosnippet>3</a></span><span class="kw">use </span>std::path::Path;
<a href=#4 id=4 data-nosnippet>4</a><span class="kw">use </span>chrono::{DateTime, Utc};
<a href=#5 id=5 data-nosnippet>5</a><span class="kw">use </span>rusqlite::{params, Connection};
<a href=#6 id=6 data-nosnippet>6</a><span class="kw">use </span>serde::{Deserialize, Serialize};
<a href=#7 id=7 data-nosnippet>7</a><span class="kw">use </span>serde_json::Value <span class="kw">as </span>JsonValue;
<a href=#8 id=8 data-nosnippet>8</a><span class="kw">use </span>thiserror::Error;
<a href=#9 id=9 data-nosnippet>9</a><span class="kw">use </span>uuid::Uuid;
<a href=#10 id=10 data-nosnippet>10</a>
<a href=#11 id=11 data-nosnippet>11</a><span class="doccomment">/// Represents a mail message stored in the mailbox.
<a href=#12 id=12 data-nosnippet>12</a>///
<a href=#13 id=13 data-nosnippet>13</a>/// # Definition
<a href=#14 id=14 data-nosnippet>14</a>/// `Message` is a data structure that models a single mail exchange between two peers.
<a href=#15 id=15 data-nosnippet>15</a>/// It contains a unique identifier, sender and recipient identifiers, a topic string, a JSON payload,
<a href=#16 id=16 data-nosnippet>16</a>/// and timestamps for when the message was sent and optionally when it was read.
<a href=#17 id=17 data-nosnippet>17</a>///
<a href=#18 id=18 data-nosnippet>18</a>/// # Implementation Details
<a href=#19 id=19 data-nosnippet>19</a>/// - `id` is a **Uuid** generated by the caller to guarantee global uniqueness.
<a href=#20 id=20 data-nosnippet>20</a>/// - `payload` uses `serde_json::Value` so arbitrary JSON can be attached to the message.
<a href=#21 id=21 data-nosnippet>21</a>/// - `sent_at` and `read_at` are stored as `chrono::DateTime&lt;Utc&gt;` to provide timezoneagnostic timestamps.
<a href=#22 id=22 data-nosnippet>22</a>///
<a href=#23 id=23 data-nosnippet>23</a>/// # Rationale
<a href=#24 id=24 data-nosnippet>24</a>/// This struct provides a lightweight, serialisable representation of a message that can be persisted
<a href=#25 id=25 data-nosnippet>25</a>/// in the SQLitebacked mailbox (see `Mailbox`). Keeping the payload as JSON allows different subsystems
<a href=#26 id=26 data-nosnippet>26</a>/// of the CHORUS platform to embed domainspecific data without requiring a rigid schema.
<a href=#27 id=27 data-nosnippet>27</a></span><span class="attr">#[derive(Debug, Serialize, Deserialize, Clone)]
<a href=#28 id=28 data-nosnippet>28</a></span><span class="kw">pub struct </span>Message {
<a href=#29 id=29 data-nosnippet>29</a> <span class="doccomment">/// Globally unique identifier for the message.
<a href=#30 id=30 data-nosnippet>30</a> </span><span class="kw">pub </span>id: Uuid,
<a href=#31 id=31 data-nosnippet>31</a> <span class="doccomment">/// Identifier of the sending peer.
<a href=#32 id=32 data-nosnippet>32</a> </span><span class="kw">pub </span>from_peer: String,
<a href=#33 id=33 data-nosnippet>33</a> <span class="doccomment">/// Identifier of the receiving peer.
<a href=#34 id=34 data-nosnippet>34</a> </span><span class="kw">pub </span>to_peer: String,
<a href=#35 id=35 data-nosnippet>35</a> <span class="doccomment">/// Topic or channel of the message; used for routing/filters.
<a href=#36 id=36 data-nosnippet>36</a> </span><span class="kw">pub </span>topic: String,
<a href=#37 id=37 data-nosnippet>37</a> <span class="doccomment">/// Arbitrary JSON payload containing the message body.
<a href=#38 id=38 data-nosnippet>38</a> </span><span class="kw">pub </span>payload: JsonValue,
<a href=#39 id=39 data-nosnippet>39</a> <span class="doccomment">/// Timestamp (UTC) when the message was sent.
<a href=#40 id=40 data-nosnippet>40</a> </span><span class="kw">pub </span>sent_at: DateTime&lt;Utc&gt;,
<a href=#41 id=41 data-nosnippet>41</a> <span class="doccomment">/// Optional timestamp (UTC) when the recipient read the message.
<a href=#42 id=42 data-nosnippet>42</a> </span><span class="kw">pub </span>read_at: <span class="prelude-ty">Option</span>&lt;DateTime&lt;Utc&gt;&gt;,
<a href=#43 id=43 data-nosnippet>43</a>}
<a href=#44 id=44 data-nosnippet>44</a>
<a href=#45 id=45 data-nosnippet>45</a><span class="doccomment">/// Errors that can occur while using the `Mailbox`.
<a href=#46 id=46 data-nosnippet>46</a>///
<a href=#47 id=47 data-nosnippet>47</a>/// Each variant wraps an underlying error type from a dependency, allowing callers to
<a href=#48 id=48 data-nosnippet>48</a>/// react appropriately (e.g., retry on SQLite errors, surface serialization problems, etc.).
<a href=#49 id=49 data-nosnippet>49</a></span><span class="attr">#[derive(Debug, Error)]
<a href=#50 id=50 data-nosnippet>50</a></span><span class="kw">pub enum </span>MailError {
<a href=#51 id=51 data-nosnippet>51</a> <span class="doccomment">/// Propagates any `rusqlite::Error` encountered while interacting with the SQLite DB.
<a href=#52 id=52 data-nosnippet>52</a> </span><span class="attr">#[error(<span class="string">"SQLite error: {0}"</span>)]
<a href=#53 id=53 data-nosnippet>53</a> </span>Sqlite(<span class="attr">#[from] </span>rusqlite::Error),
<a href=#54 id=54 data-nosnippet>54</a> <span class="doccomment">/// Propagates JSON (de)serialization errors from `serde_json`.
<a href=#55 id=55 data-nosnippet>55</a> </span><span class="attr">#[error(<span class="string">"JSON serialization error: {0}"</span>)]
<a href=#56 id=56 data-nosnippet>56</a> </span>Json(<span class="attr">#[from] </span>serde_json::Error),
<a href=#57 id=57 data-nosnippet>57</a> <span class="doccomment">/// Propagates UUID parsing errors.
<a href=#58 id=58 data-nosnippet>58</a> </span><span class="attr">#[error(<span class="string">"UUID parsing error: {0}"</span>)]
<a href=#59 id=59 data-nosnippet>59</a> </span>Uuid(<span class="attr">#[from] </span>uuid::Error),
<a href=#60 id=60 data-nosnippet>60</a> <span class="doccomment">/// Propagates chrono parsing errors, primarily when deserialising timestamps from string.
<a href=#61 id=61 data-nosnippet>61</a> </span><span class="attr">#[error(<span class="string">"Chrono parsing error: {0}"</span>)]
<a href=#62 id=62 data-nosnippet>62</a> </span>ChronoParse(<span class="attr">#[from] </span>chrono::ParseError),
<a href=#63 id=63 data-nosnippet>63</a>}
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a><span class="doccomment">/// Wrapper around a SQLite connection providing mailboxstyle functionalities.
<a href=#66 id=66 data-nosnippet>66</a>///
<a href=#67 id=67 data-nosnippet>67</a>/// The `Mailbox` abstracts a SQLite database that stores `Message` records. It offers a minimal
<a href=#68 id=68 data-nosnippet>68</a>/// API for opening/creating the DB, sending messages, receiving pending messages for a peer, and
<a href=#69 id=69 data-nosnippet>69</a>/// marking messages as read.
<a href=#70 id=70 data-nosnippet>70</a>///
<a href=#71 id=71 data-nosnippet>71</a>/// # Architectural Rationale
<a href=#72 id=72 data-nosnippet>72</a>/// Using SQLite (via `rusqlite`) provides a zeroconfiguration, filebased persistence layer that is
<a href=#73 id=73 data-nosnippet>73</a>/// portable across the various environments where CHORUS components may run. The wrapper isolates the
<a href=#74 id=74 data-nosnippet>74</a>/// rest of the codebase from raw SQL handling, ensuring a single place for schema evolution and error
<a href=#75 id=75 data-nosnippet>75</a>/// mapping.
<a href=#76 id=76 data-nosnippet>76</a></span><span class="kw">pub struct </span>Mailbox {
<a href=#77 id=77 data-nosnippet>77</a> conn: Connection,
<a href=#78 id=78 data-nosnippet>78</a>}
<a href=#79 id=79 data-nosnippet>79</a>
<a href=#80 id=80 data-nosnippet>80</a><span class="kw">impl </span>Mailbox {
<a href=#81 id=81 data-nosnippet>81</a> <span class="doccomment">/// Open (or create) a mailbox database at `path`.
<a href=#82 id=82 data-nosnippet>82</a> ///
<a href=#83 id=83 data-nosnippet>83</a> /// The function creates the SQLite file if it does not exist, enables WAL mode for better
<a href=#84 id=84 data-nosnippet>84</a> /// concurrency, and ensures the `messages` table is present.
<a href=#85 id=85 data-nosnippet>85</a> </span><span class="kw">pub fn </span>open&lt;P: AsRef&lt;Path&gt;&gt;(path: P) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, MailError&gt; {
<a href=#86 id=86 data-nosnippet>86</a> <span class="kw">let </span>conn = Connection::open(path)<span class="question-mark">?</span>;
<a href=#87 id=87 data-nosnippet>87</a> <span class="comment">// Enable WAL mode for improved concurrency and durability.
<a href=#88 id=88 data-nosnippet>88</a> </span>conn.pragma_update(<span class="prelude-val">None</span>, <span class="string">"journal_mode"</span>, <span class="kw-2">&amp;</span><span class="string">"WAL"</span>)<span class="question-mark">?</span>;
<a href=#89 id=89 data-nosnippet>89</a> <span class="comment">// Create the `messages` table if it does not already exist.
<a href=#90 id=90 data-nosnippet>90</a> </span>conn.execute(
<a href=#91 id=91 data-nosnippet>91</a> <span class="string">"CREATE TABLE IF NOT EXISTS messages (
<a href=#92 id=92 data-nosnippet>92</a> id TEXT PRIMARY KEY,
<a href=#93 id=93 data-nosnippet>93</a> from_peer TEXT NOT NULL,
<a href=#94 id=94 data-nosnippet>94</a> to_peer TEXT NOT NULL,
<a href=#95 id=95 data-nosnippet>95</a> topic TEXT NOT NULL,
<a href=#96 id=96 data-nosnippet>96</a> payload TEXT NOT NULL,
<a href=#97 id=97 data-nosnippet>97</a> sent_at TEXT NOT NULL,
<a href=#98 id=98 data-nosnippet>98</a> read_at TEXT
<a href=#99 id=99 data-nosnippet>99</a> )"</span>,
<a href=#100 id=100 data-nosnippet>100</a> [],
<a href=#101 id=101 data-nosnippet>101</a> )<span class="question-mark">?</span>;
<a href=#102 id=102 data-nosnippet>102</a> <span class="prelude-val">Ok</span>(<span class="self">Self </span>{ conn })
<a href=#103 id=103 data-nosnippet>103</a> }
<a href=#104 id=104 data-nosnippet>104</a>
<a href=#105 id=105 data-nosnippet>105</a> <span class="doccomment">/// Store a new message in the mailbox.
<a href=#106 id=106 data-nosnippet>106</a> ///
<a href=#107 id=107 data-nosnippet>107</a> /// The `payload` field is serialised to a JSON string before insertion. The `read_at` column is
<a href=#108 id=108 data-nosnippet>108</a> /// initialised to `NULL` because the message has not yet been consumed.
<a href=#109 id=109 data-nosnippet>109</a> </span><span class="kw">pub fn </span>send(<span class="kw-2">&amp;</span><span class="self">self</span>, msg: <span class="kw-2">&amp;</span>Message) -&gt; <span class="prelude-ty">Result</span>&lt;(), MailError&gt; {
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">let </span>payload_str = serde_json::to_string(<span class="kw-2">&amp;</span>msg.payload)<span class="question-mark">?</span>;
<a href=#111 id=111 data-nosnippet>111</a> <span class="self">self</span>.conn.execute(
<a href=#112 id=112 data-nosnippet>112</a> <span class="string">"INSERT INTO messages (id, from_peer, to_peer, topic, payload, sent_at, read_at)
<a href=#113 id=113 data-nosnippet>113</a> VALUES (?1, ?2, ?3, ?4, ?5, ?6, NULL)"</span>,
<a href=#114 id=114 data-nosnippet>114</a> <span class="macro">params!</span>[
<a href=#115 id=115 data-nosnippet>115</a> msg.id.to_string(),
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw-2">&amp;</span>msg.from_peer,
<a href=#117 id=117 data-nosnippet>117</a> <span class="kw-2">&amp;</span>msg.to_peer,
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw-2">&amp;</span>msg.topic,
<a href=#119 id=119 data-nosnippet>119</a> payload_str,
<a href=#120 id=120 data-nosnippet>120</a> msg.sent_at.to_rfc3339(),
<a href=#121 id=121 data-nosnippet>121</a> ],
<a href=#122 id=122 data-nosnippet>122</a> )<span class="question-mark">?</span>;
<a href=#123 id=123 data-nosnippet>123</a> <span class="prelude-val">Ok</span>(())
<a href=#124 id=124 data-nosnippet>124</a> }
<a href=#125 id=125 data-nosnippet>125</a>
<a href=#126 id=126 data-nosnippet>126</a> <span class="doccomment">/// Retrieve all unread messages addressed to `peer_id`.
<a href=#127 id=127 data-nosnippet>127</a> ///
<a href=#128 id=128 data-nosnippet>128</a> /// The query filters on `to_peer` and `read_at IS NULL`. Returned rows are transformed back into
<a href=#129 id=129 data-nosnippet>129</a> /// `Message` structs, parsing the UUID, JSON payload, and RFC3339 timestamps.
<a href=#130 id=130 data-nosnippet>130</a> </span><span class="kw">pub fn </span>receive_pending(<span class="kw-2">&amp;</span><span class="self">self</span>, peer_id: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;Message&gt;, MailError&gt; {
<a href=#131 id=131 data-nosnippet>131</a> <span class="kw">let </span><span class="kw-2">mut </span>stmt = <span class="self">self</span>.conn.prepare(
<a href=#132 id=132 data-nosnippet>132</a> <span class="string">"SELECT id, from_peer, to_peer, topic, payload, sent_at, read_at
<a href=#133 id=133 data-nosnippet>133</a> FROM messages
<a href=#134 id=134 data-nosnippet>134</a> WHERE to_peer = ?1 AND read_at IS NULL"</span>,
<a href=#135 id=135 data-nosnippet>135</a> )<span class="question-mark">?</span>;
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">let </span>rows = stmt.query_map(<span class="macro">params!</span>[peer_id], |row| {
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">let </span>id_str: String = row.get(<span class="number">0</span>)<span class="question-mark">?</span>;
<a href=#138 id=138 data-nosnippet>138</a> <span class="kw">let </span>from_peer: String = row.get(<span class="number">1</span>)<span class="question-mark">?</span>;
<a href=#139 id=139 data-nosnippet>139</a> <span class="kw">let </span>to_peer: String = row.get(<span class="number">2</span>)<span class="question-mark">?</span>;
<a href=#140 id=140 data-nosnippet>140</a> <span class="kw">let </span>topic: String = row.get(<span class="number">3</span>)<span class="question-mark">?</span>;
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">let </span>payload_str: String = row.get(<span class="number">4</span>)<span class="question-mark">?</span>;
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">let </span>sent_at_str: String = row.get(<span class="number">5</span>)<span class="question-mark">?</span>;
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">let </span>read_at_opt: <span class="prelude-ty">Option</span>&lt;String&gt; = row.get(<span class="number">6</span>)<span class="question-mark">?</span>;
<a href=#144 id=144 data-nosnippet>144</a>
<a href=#145 id=145 data-nosnippet>145</a> <span class="comment">// Parse Uuid
<a href=#146 id=146 data-nosnippet>146</a> </span><span class="kw">let </span>id = Uuid::parse_str(<span class="kw-2">&amp;</span>id_str)
<a href=#147 id=147 data-nosnippet>147</a> .map_err(|e| rusqlite::Error::FromSqlConversionFailure(<span class="number">0</span>, rusqlite::types::Type::Text, Box::new(e)))<span class="question-mark">?</span>;
<a href=#148 id=148 data-nosnippet>148</a> <span class="comment">// Parse JSON payload
<a href=#149 id=149 data-nosnippet>149</a> </span><span class="kw">let </span>payload: JsonValue = serde_json::from_str(<span class="kw-2">&amp;</span>payload_str)
<a href=#150 id=150 data-nosnippet>150</a> .map_err(|e| rusqlite::Error::FromSqlConversionFailure(<span class="number">4</span>, rusqlite::types::Type::Text, Box::new(e)))<span class="question-mark">?</span>;
<a href=#151 id=151 data-nosnippet>151</a> <span class="comment">// Parse timestamps
<a href=#152 id=152 data-nosnippet>152</a> </span><span class="kw">let </span>sent_at = DateTime::parse_from_rfc3339(<span class="kw-2">&amp;</span>sent_at_str)
<a href=#153 id=153 data-nosnippet>153</a> .map_err(|e| rusqlite::Error::FromSqlConversionFailure(<span class="number">5</span>, rusqlite::types::Type::Text, Box::new(e)))<span class="question-mark">?
<a href=#154 id=154 data-nosnippet>154</a> </span>.with_timezone(<span class="kw-2">&amp;</span>Utc);
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">let </span>read_at = <span class="kw">match </span>read_at_opt {
<a href=#156 id=156 data-nosnippet>156</a> <span class="prelude-val">Some</span>(s) =&gt; <span class="prelude-val">Some</span>(
<a href=#157 id=157 data-nosnippet>157</a> DateTime::parse_from_rfc3339(<span class="kw-2">&amp;</span>s)
<a href=#158 id=158 data-nosnippet>158</a> .map_err(|e| rusqlite::Error::FromSqlConversionFailure(<span class="number">6</span>, rusqlite::types::Type::Text, Box::new(e)))<span class="question-mark">?
<a href=#159 id=159 data-nosnippet>159</a> </span>.with_timezone(<span class="kw-2">&amp;</span>Utc),
<a href=#160 id=160 data-nosnippet>160</a> ),
<a href=#161 id=161 data-nosnippet>161</a> <span class="prelude-val">None </span>=&gt; <span class="prelude-val">None</span>,
<a href=#162 id=162 data-nosnippet>162</a> };
<a href=#163 id=163 data-nosnippet>163</a>
<a href=#164 id=164 data-nosnippet>164</a> <span class="prelude-val">Ok</span>(Message {
<a href=#165 id=165 data-nosnippet>165</a> id,
<a href=#166 id=166 data-nosnippet>166</a> from_peer,
<a href=#167 id=167 data-nosnippet>167</a> to_peer,
<a href=#168 id=168 data-nosnippet>168</a> topic,
<a href=#169 id=169 data-nosnippet>169</a> payload,
<a href=#170 id=170 data-nosnippet>170</a> sent_at,
<a href=#171 id=171 data-nosnippet>171</a> read_at,
<a href=#172 id=172 data-nosnippet>172</a> })
<a href=#173 id=173 data-nosnippet>173</a> })<span class="question-mark">?</span>;
<a href=#174 id=174 data-nosnippet>174</a>
<a href=#175 id=175 data-nosnippet>175</a> <span class="kw">let </span><span class="kw-2">mut </span>msgs = Vec::new();
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">for </span>msg_res <span class="kw">in </span>rows {
<a href=#177 id=177 data-nosnippet>177</a> msgs.push(msg_res<span class="question-mark">?</span>);
<a href=#178 id=178 data-nosnippet>178</a> }
<a href=#179 id=179 data-nosnippet>179</a> <span class="prelude-val">Ok</span>(msgs)
<a href=#180 id=180 data-nosnippet>180</a> }
<a href=#181 id=181 data-nosnippet>181</a>
<a href=#182 id=182 data-nosnippet>182</a> <span class="doccomment">/// Mark a message as read by setting its `read_at` timestamp.
<a href=#183 id=183 data-nosnippet>183</a> ///
<a href=#184 id=184 data-nosnippet>184</a> /// The current UTC time is stored in the `read_at` column for the row with the matching `id`.
<a href=#185 id=185 data-nosnippet>185</a> </span><span class="kw">pub fn </span>mark_read(<span class="kw-2">&amp;</span><span class="self">self</span>, msg_id: Uuid) -&gt; <span class="prelude-ty">Result</span>&lt;(), MailError&gt; {
<a href=#186 id=186 data-nosnippet>186</a> <span class="kw">let </span>now = Utc::now().to_rfc3339();
<a href=#187 id=187 data-nosnippet>187</a> <span class="self">self</span>.conn.execute(
<a href=#188 id=188 data-nosnippet>188</a> <span class="string">"UPDATE messages SET read_at = ?1 WHERE id = ?2"</span>,
<a href=#189 id=189 data-nosnippet>189</a> <span class="macro">params!</span>[now, msg_id.to_string()],
<a href=#190 id=190 data-nosnippet>190</a> )<span class="question-mark">?</span>;
<a href=#191 id=191 data-nosnippet>191</a> <span class="prelude-val">Ok</span>(())
<a href=#192 id=192 data-nosnippet>192</a> }
<a href=#193 id=193 data-nosnippet>193</a>}
<a href=#194 id=194 data-nosnippet>194</a>
<a href=#195 id=195 data-nosnippet>195</a><span class="attr">#[cfg(test)]
<a href=#196 id=196 data-nosnippet>196</a></span><span class="kw">mod </span>tests {
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">use </span>std::env;
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">use </span>std::fs;
<a href=#200 id=200 data-nosnippet>200</a>
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">fn </span>temp_db_path() -&gt; std::path::PathBuf {
<a href=#202 id=202 data-nosnippet>202</a> <span class="kw">let </span><span class="kw-2">mut </span>dir = env::temp_dir();
<a href=#203 id=203 data-nosnippet>203</a> dir.push(<span class="macro">format!</span>(<span class="string">"chrs_mail_test_{}.sqlite"</span>, Uuid::new_v4()));
<a href=#204 id=204 data-nosnippet>204</a> dir
<a href=#205 id=205 data-nosnippet>205</a> }
<a href=#206 id=206 data-nosnippet>206</a>
<a href=#207 id=207 data-nosnippet>207</a> <span class="attr">#[test]
<a href=#208 id=208 data-nosnippet>208</a> </span><span class="kw">fn </span>roundtrip_send_and_receive() -&gt; <span class="prelude-ty">Result</span>&lt;(), MailError&gt; {
<a href=#209 id=209 data-nosnippet>209</a> <span class="kw">let </span>db_path = temp_db_path();
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">if </span>db_path.exists() {
<a href=#211 id=211 data-nosnippet>211</a> fs::remove_file(<span class="kw-2">&amp;</span>db_path).unwrap();
<a href=#212 id=212 data-nosnippet>212</a> }
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let </span>mailbox = Mailbox::open(<span class="kw-2">&amp;</span>db_path)<span class="question-mark">?</span>;
<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">let </span>msg = Message {
<a href=#215 id=215 data-nosnippet>215</a> id: Uuid::new_v4(),
<a href=#216 id=216 data-nosnippet>216</a> from_peer: <span class="string">"alice"</span>.into(),
<a href=#217 id=217 data-nosnippet>217</a> to_peer: <span class="string">"bob"</span>.into(),
<a href=#218 id=218 data-nosnippet>218</a> topic: <span class="string">"greeting"</span>.into(),
<a href=#219 id=219 data-nosnippet>219</a> payload: <span class="macro">serde_json::json!</span>({<span class="string">"text"</span>: <span class="string">"Hello"</span>}),
<a href=#220 id=220 data-nosnippet>220</a> sent_at: Utc::now(),
<a href=#221 id=221 data-nosnippet>221</a> read_at: <span class="prelude-val">None</span>,
<a href=#222 id=222 data-nosnippet>222</a> };
<a href=#223 id=223 data-nosnippet>223</a> mailbox.send(<span class="kw-2">&amp;</span>msg)<span class="question-mark">?</span>;
<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">let </span>pending = mailbox.receive_pending(<span class="string">"bob"</span>)<span class="question-mark">?</span>;
<a href=#225 id=225 data-nosnippet>225</a> <span class="macro">assert_eq!</span>(pending.len(), <span class="number">1</span>);
<a href=#226 id=226 data-nosnippet>226</a> <span class="macro">assert_eq!</span>(pending[<span class="number">0</span>].id, msg.id);
<a href=#227 id=227 data-nosnippet>227</a>
<a href=#228 id=228 data-nosnippet>228</a> mailbox.mark_read(msg.id)<span class="question-mark">?</span>;
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">let </span>pending2 = mailbox.receive_pending(<span class="string">"bob"</span>)<span class="question-mark">?</span>;
<a href=#230 id=230 data-nosnippet>230</a> <span class="macro">assert!</span>(pending2.is_empty());
<a href=#231 id=231 data-nosnippet>231</a>
<a href=#232 id=232 data-nosnippet>232</a> fs::remove_file(db_path).unwrap();
<a href=#233 id=233 data-nosnippet>233</a> <span class="prelude-val">Ok</span>(())
<a href=#234 id=234 data-nosnippet>234</a> }
<a href=#235 id=235 data-nosnippet>235</a>}</code></pre></div></section></main></body></html>

View File

@@ -0,0 +1,128 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `chrs-poc/src/main.rs`."><title>main.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="chrs_poc" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../../static.files/storage-82c7156e.js"></script><script defer src="../../static.files/src-script-63605ae7.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">chrs_poc/</div>main.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">/// chrs-poc crate provides an endtoend proofofconcept demonstration of the CHORUS
<a href=#2 id=2 data-nosnippet>2</a>/// system. It wires together the core components:
<a href=#3 id=3 data-nosnippet>3</a>///
<a href=#4 id=4 data-nosnippet>4</a>/// * `Mailbox` messagepassing layer (`chrs_mail`).
<a href=#5 id=5 data-nosnippet>5</a>/// * `DoltGraph` persistent state graph (`chrs_graph`).
<a href=#6 id=6 data-nosnippet>6</a>/// * `ProvenanceGraph` provenance tracking (`chrs_bubble`).
<a href=#7 id=7 data-nosnippet>7</a>/// * `SecretSentinel` secret scrubbing (`chrs_shhh`).
<a href=#8 id=8 data-nosnippet>8</a>/// * `CurationEngine` decision record curation (`chrs_slurp`).
<a href=#9 id=9 data-nosnippet>9</a>///
<a href=#10 id=10 data-nosnippet>10</a>/// The flow mirrors a realistic task lifecycle: a client dispatches a task
<a href=#11 id=11 data-nosnippet>11</a>/// message, an agent processes it, generates reasoning (with a deliberately
<a href=#12 id=12 data-nosnippet>12</a>/// injected secret), the secret is scrubbed, a decision record is curated, and
<a href=#13 id=13 data-nosnippet>13</a>/// provenance links are recorded. The final state is persisted in a Dolt
<a href=#14 id=14 data-nosnippet>14</a>/// repository.
<a href=#15 id=15 data-nosnippet>15</a>
<a href=#16 id=16 data-nosnippet>16</a></span><span class="kw">use </span>chrs_bubble::{ProvenanceGraph, ProvenanceEdge};
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>chrs_graph::DoltGraph;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>chrs_mail::{Mailbox, Message};
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>chrs_shhh::SecretSentinel;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>chrs_slurp::{CurationEngine, DecisionRecord};
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>chrono::Utc;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>std::fs;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>std::path::Path;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>uuid::Uuid;
<a href=#25 id=25 data-nosnippet>25</a>
<a href=#26 id=26 data-nosnippet>26</a><span class="doccomment">/// Entry point for the proofofconcept binary.
<a href=#27 id=27 data-nosnippet>27</a>///
<a href=#28 id=28 data-nosnippet>28</a>/// The function performs the following highlevel steps, each documented inline:
<a href=#29 id=29 data-nosnippet>29</a>/// 1. Sets up a temporary workspace.
<a href=#30 id=30 data-nosnippet>30</a>/// 2. Initialises all required components.
<a href=#31 id=31 data-nosnippet>31</a>/// 3. Simulates a client sending an audit task to an agent.
<a href=#32 id=32 data-nosnippet>32</a>/// 4. Processes the task as the agent would, including secret scrubbing.
<a href=#33 id=33 data-nosnippet>33</a>/// 5. Curates a `DecisionRecord` via the SLURP engine.
<a href=#34 id=34 data-nosnippet>34</a>/// 6. Records provenance relationships in the BUBBLE graph.
<a href=#35 id=35 data-nosnippet>35</a>/// 7. Prints a success banner and the path to the persisted Dolt state.
<a href=#36 id=36 data-nosnippet>36</a>///
<a href=#37 id=37 data-nosnippet>37</a>/// Errors from any component propagate via `?` and are reported as a boxed error.
<a href=#38 id=38 data-nosnippet>38</a></span><span class="attr">#[tokio::main]
<a href=#39 id=39 data-nosnippet>39</a></span><span class="kw">async fn </span>main() -&gt; <span class="prelude-ty">Result</span>&lt;(), Box&lt;<span class="kw">dyn </span>std::error::Error&gt;&gt; {
<a href=#40 id=40 data-nosnippet>40</a> <span class="macro">println!</span>(<span class="string">"=== CHORUS End-to-End Proof of Concept ==="</span>);
<a href=#41 id=41 data-nosnippet>41</a>
<a href=#42 id=42 data-nosnippet>42</a> <span class="comment">// ---------------------------------------------------------------------
<a href=#43 id=43 data-nosnippet>43</a> // 1. Setup paths
<a href=#44 id=44 data-nosnippet>44</a> // ---------------------------------------------------------------------
<a href=#45 id=45 data-nosnippet>45</a> </span><span class="kw">let </span>base_path = Path::new(<span class="string">"/tmp/chrs_poc"</span>);
<a href=#46 id=46 data-nosnippet>46</a> <span class="kw">if </span>base_path.exists() {
<a href=#47 id=47 data-nosnippet>47</a> fs::remove_dir_all(base_path)<span class="question-mark">?</span>;
<a href=#48 id=48 data-nosnippet>48</a> }
<a href=#49 id=49 data-nosnippet>49</a> fs::create_dir_all(base_path)<span class="question-mark">?</span>;
<a href=#50 id=50 data-nosnippet>50</a>
<a href=#51 id=51 data-nosnippet>51</a> <span class="kw">let </span>mail_path = base_path.join(<span class="string">"mail.sqlite"</span>);
<a href=#52 id=52 data-nosnippet>52</a> <span class="kw">let </span>graph_path = base_path.join(<span class="string">"state_graph"</span>);
<a href=#53 id=53 data-nosnippet>53</a> fs::create_dir_all(<span class="kw-2">&amp;</span>graph_path)<span class="question-mark">?</span>;
<a href=#54 id=54 data-nosnippet>54</a>
<a href=#55 id=55 data-nosnippet>55</a> <span class="comment">// ---------------------------------------------------------------------
<a href=#56 id=56 data-nosnippet>56</a> // 2. Initialise Components
<a href=#57 id=57 data-nosnippet>57</a> // ---------------------------------------------------------------------
<a href=#58 id=58 data-nosnippet>58</a> </span><span class="kw">let </span>mailbox = Mailbox::open(<span class="kw-2">&amp;</span>mail_path)<span class="question-mark">?</span>;
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">let </span>persistence = DoltGraph::init(<span class="kw-2">&amp;</span>graph_path)<span class="question-mark">?</span>;
<a href=#60 id=60 data-nosnippet>60</a> <span class="kw">let </span><span class="kw-2">mut </span>provenance = ProvenanceGraph::new(persistence);
<a href=#61 id=61 data-nosnippet>61</a>
<a href=#62 id=62 data-nosnippet>62</a> <span class="comment">// A separate graph handle is needed for the SLURP engine because the
<a href=#63 id=63 data-nosnippet>63</a> // provenance graph consumes the original `DoltGraph`. In production we would
<a href=#64 id=64 data-nosnippet>64</a> // share via `Arc&lt;Mutex&lt;&gt;&gt;`.
<a href=#65 id=65 data-nosnippet>65</a> </span><span class="kw">let </span>slurp_persistence = DoltGraph::init(<span class="kw-2">&amp;</span>graph_path)<span class="question-mark">?</span>;
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw">let </span>curator = CurationEngine::new(slurp_persistence);
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">let </span>sentinel = SecretSentinel::new_default();
<a href=#68 id=68 data-nosnippet>68</a>
<a href=#69 id=69 data-nosnippet>69</a> <span class="macro">println!</span>(<span class="string">"[POC] Components initialized."</span>);
<a href=#70 id=70 data-nosnippet>70</a>
<a href=#71 id=71 data-nosnippet>71</a> <span class="comment">// ---------------------------------------------------------------------
<a href=#72 id=72 data-nosnippet>72</a> // 3. Dispatch Task (simulate client sending message to Agent-A)
<a href=#73 id=73 data-nosnippet>73</a> // ---------------------------------------------------------------------
<a href=#74 id=74 data-nosnippet>74</a> </span><span class="kw">let </span>task_id = Uuid::new_v4();
<a href=#75 id=75 data-nosnippet>75</a> <span class="kw">let </span>task_msg = Message {
<a href=#76 id=76 data-nosnippet>76</a> id: task_id,
<a href=#77 id=77 data-nosnippet>77</a> from_peer: <span class="string">"client"</span>.into(),
<a href=#78 id=78 data-nosnippet>78</a> to_peer: <span class="string">"agent-a"</span>.into(),
<a href=#79 id=79 data-nosnippet>79</a> topic: <span class="string">"audit_system"</span>.into(),
<a href=#80 id=80 data-nosnippet>80</a> payload: <span class="macro">serde_json::json!</span>({<span class="string">"action"</span>: <span class="string">"audit"</span>, <span class="string">"target"</span>: <span class="string">"UCXL"</span>}),
<a href=#81 id=81 data-nosnippet>81</a> sent_at: Utc::now(),
<a href=#82 id=82 data-nosnippet>82</a> read_at: <span class="prelude-val">None</span>,
<a href=#83 id=83 data-nosnippet>83</a> };
<a href=#84 id=84 data-nosnippet>84</a> mailbox.send(<span class="kw-2">&amp;</span>task_msg)<span class="question-mark">?</span>;
<a href=#85 id=85 data-nosnippet>85</a> <span class="macro">println!</span>(<span class="string">"[POC] Task dispatched to Agent-A: {}"</span>, task_id);
<a href=#86 id=86 data-nosnippet>86</a>
<a href=#87 id=87 data-nosnippet>87</a> <span class="comment">// ---------------------------------------------------------------------
<a href=#88 id=88 data-nosnippet>88</a> // 4. Process Task (Agent-A logic)
<a href=#89 id=89 data-nosnippet>89</a> // ---------------------------------------------------------------------
<a href=#90 id=90 data-nosnippet>90</a> </span><span class="kw">let </span>pending = mailbox.receive_pending(<span class="string">"agent-a"</span>)<span class="question-mark">?</span>;
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">for </span>msg <span class="kw">in </span>pending {
<a href=#92 id=92 data-nosnippet>92</a> <span class="macro">println!</span>(<span class="string">"[POC] Agent-A received task: {}"</span>, msg.topic);
<a href=#93 id=93 data-nosnippet>93</a>
<a href=#94 id=94 data-nosnippet>94</a> <span class="comment">// Simulated reasoning that accidentally contains a secret.
<a href=#95 id=95 data-nosnippet>95</a> </span><span class="kw">let </span>raw_reasoning = <span class="string">"Audit complete. Verified UCXL address parsing. My secret key is sk-1234567890abcdef1234567890abcdef1234567890abcdef"</span>;
<a href=#96 id=96 data-nosnippet>96</a>
<a href=#97 id=97 data-nosnippet>97</a> <span class="comment">// 5. SHHH: Scrub secrets from the reasoning output.
<a href=#98 id=98 data-nosnippet>98</a> </span><span class="kw">let </span>clean_reasoning = sentinel.scrub_text(raw_reasoning);
<a href=#99 id=99 data-nosnippet>99</a> <span class="macro">println!</span>(<span class="string">"[POC] SHHH scrubbed reasoning: {}"</span>, clean_reasoning);
<a href=#100 id=100 data-nosnippet>100</a>
<a href=#101 id=101 data-nosnippet>101</a> <span class="comment">// 6. SLURP: Create and curate a DecisionRecord.
<a href=#102 id=102 data-nosnippet>102</a> </span><span class="kw">let </span>dr = DecisionRecord {
<a href=#103 id=103 data-nosnippet>103</a> id: Uuid::new_v4(),
<a href=#104 id=104 data-nosnippet>104</a> author: <span class="string">"agent-a"</span>.into(),
<a href=#105 id=105 data-nosnippet>105</a> reasoning: clean_reasoning,
<a href=#106 id=106 data-nosnippet>106</a> citations: <span class="macro">vec!</span>[<span class="string">"ucxl://system:watcher@local:filesystem/#/UCXL/src/lib.rs"</span>.into()],
<a href=#107 id=107 data-nosnippet>107</a> timestamp: Utc::now(),
<a href=#108 id=108 data-nosnippet>108</a> };
<a href=#109 id=109 data-nosnippet>109</a> curator.curate_decision(dr.clone())<span class="question-mark">?</span>;
<a href=#110 id=110 data-nosnippet>110</a>
<a href=#111 id=111 data-nosnippet>111</a> <span class="comment">// 7. BUBBLE: Record provenance relationships.
<a href=#112 id=112 data-nosnippet>112</a> </span>provenance.record_node(task_id, <span class="string">"ucxl://client:user@poc:task/#/audit_request"</span>)<span class="question-mark">?</span>;
<a href=#113 id=113 data-nosnippet>113</a> provenance.record_node(dr.id, <span class="string">"ucxl://agent-a:worker@poc:task/#/audit_result"</span>)<span class="question-mark">?</span>;
<a href=#114 id=114 data-nosnippet>114</a> provenance.record_link(dr.id, task_id, ProvenanceEdge::DerivedFrom)<span class="question-mark">?</span>;
<a href=#115 id=115 data-nosnippet>115</a>
<a href=#116 id=116 data-nosnippet>116</a> <span class="macro">println!</span>(<span class="string">"[POC] Provenance recorded: DR {} -&gt; Task {}"</span>, dr.id, task_id);
<a href=#117 id=117 data-nosnippet>117</a>
<a href=#118 id=118 data-nosnippet>118</a> mailbox.mark_read(msg.id)<span class="question-mark">?</span>;
<a href=#119 id=119 data-nosnippet>119</a> }
<a href=#120 id=120 data-nosnippet>120</a>
<a href=#121 id=121 data-nosnippet>121</a> <span class="comment">// ---------------------------------------------------------------------
<a href=#122 id=122 data-nosnippet>122</a> // 8. Final output
<a href=#123 id=123 data-nosnippet>123</a> // ---------------------------------------------------------------------
<a href=#124 id=124 data-nosnippet>124</a> </span><span class="macro">println!</span>(<span class="string">"\n=== POC SUCCESSFUL ==="</span>);
<a href=#125 id=125 data-nosnippet>125</a> <span class="macro">println!</span>(<span class="string">"Final State is persisted in Dolt at: {:?}"</span>, graph_path);
<a href=#126 id=126 data-nosnippet>126</a>
<a href=#127 id=127 data-nosnippet>127</a> <span class="prelude-val">Ok</span>(())
<a href=#128 id=128 data-nosnippet>128</a>}</code></pre></div></section></main></body></html>

View File

@@ -0,0 +1,138 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `chrs-shhh/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="chrs_shhh" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../../static.files/storage-82c7156e.js"></script><script defer src="../../static.files/src-script-63605ae7.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">chrs_shhh/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="kw">use </span>lazy_static::lazy_static;
<a href=#2 id=2 data-nosnippet>2</a><span class="doccomment">/// # chrs-shhh
<a href=#3 id=3 data-nosnippet>3</a>///
<a href=#4 id=4 data-nosnippet>4</a>/// This crate provides utilities for redacting sensitive information from text.
<a href=#5 id=5 data-nosnippet>5</a>/// It defines a set of **redaction rules** that match secret patterns (like API keys)
<a href=#6 id=6 data-nosnippet>6</a>/// and replace them with a placeholder. The crate is deliberately lightweight it
<a href=#7 id=7 data-nosnippet>7</a>/// only depends on `regex` and `lazy_static` and can be embedded in any larger
<a href=#8 id=8 data-nosnippet>8</a>/// application that needs to scrub logs or userprovided data before storage or
<a href=#9 id=9 data-nosnippet>9</a>/// transmission.
<a href=#10 id=10 data-nosnippet>10</a></span><span class="kw">use </span>regex::Regex;
<a href=#11 id=11 data-nosnippet>11</a>
<a href=#12 id=12 data-nosnippet>12</a><span class="doccomment">/// Represents a single rule used to redact a secret.
<a href=#13 id=13 data-nosnippet>13</a>///
<a href=#14 id=14 data-nosnippet>14</a>/// * **WHAT** The name of the rule (e.g. "OpenAI API Key"), the compiled
<a href=#15 id=15 data-nosnippet>15</a>/// regularexpression pattern that matches the secret, and the replacement string
<a href=#16 id=16 data-nosnippet>16</a>/// that will be inserted.
<a href=#17 id=17 data-nosnippet>17</a>/// * **HOW** The `pattern` is a `Regex` that is applied to an input string. When a
<a href=#18 id=18 data-nosnippet>18</a>/// match is found the `replacement` is inserted using `replace_all`.
<a href=#19 id=19 data-nosnippet>19</a>/// * **WHY** Decoupling the rule definition from the redaction logic makes the
<a href=#20 id=20 data-nosnippet>20</a>/// sanitizer extensible; new patterns can be added without changing the core
<a href=#21 id=21 data-nosnippet>21</a>/// implementation.
<a href=#22 id=22 data-nosnippet>22</a></span><span class="kw">pub struct </span>RedactionRule {
<a href=#23 id=23 data-nosnippet>23</a> <span class="doccomment">/// Humanreadable name for the rule.
<a href=#24 id=24 data-nosnippet>24</a> </span><span class="kw">pub </span>name: String,
<a href=#25 id=25 data-nosnippet>25</a> <span class="doccomment">/// Compiled regular expression that matches the secret.
<a href=#26 id=26 data-nosnippet>26</a> </span><span class="kw">pub </span>pattern: Regex,
<a href=#27 id=27 data-nosnippet>27</a> <span class="doccomment">/// Text that will replace the matched secret.
<a href=#28 id=28 data-nosnippet>28</a> </span><span class="kw">pub </span>replacement: String,
<a href=#29 id=29 data-nosnippet>29</a>}
<a href=#30 id=30 data-nosnippet>30</a>
<a href=#31 id=31 data-nosnippet>31</a><span class="doccomment">/// The main entry point for secret detection and redaction.
<a href=#32 id=32 data-nosnippet>32</a>///
<a href=#33 id=33 data-nosnippet>33</a>/// * **WHAT** Holds a collection of `RedactionRule`s.
<a href=#34 id=34 data-nosnippet>34</a>/// * **HOW** Provides methods to scrub a string (`scrub_text`) and to simply
<a href=#35 id=35 data-nosnippet>35</a>/// check whether any secret is present (`contains_secrets`).
<a href=#36 id=36 data-nosnippet>36</a>/// * **WHY** Centralising the rules in a struct enables reuse and makes testing
<a href=#37 id=37 data-nosnippet>37</a>/// straightforward.
<a href=#38 id=38 data-nosnippet>38</a></span><span class="kw">pub struct </span>SecretSentinel {
<a href=#39 id=39 data-nosnippet>39</a> rules: Vec&lt;RedactionRule&gt;,
<a href=#40 id=40 data-nosnippet>40</a>}
<a href=#41 id=41 data-nosnippet>41</a>
<a href=#42 id=42 data-nosnippet>42</a><span class="macro">lazy_static!</span> {
<a href=#43 id=43 data-nosnippet>43</a> <span class="doccomment">/// Matches OpenAI API keys of the form `sk-&lt;48 alphanumeric chars&gt;`.
<a href=#44 id=44 data-nosnippet>44</a> </span><span class="kw">static </span><span class="kw-2">ref </span>OPENAI_KEY: Regex = Regex::new(<span class="string">r"sk-[a-zA-Z0-9]{48}"</span>).unwrap();
<a href=#45 id=45 data-nosnippet>45</a> <span class="doccomment">/// Matches AWS access keys that start with `AKIA` followed by 16 uppercase letters or digits.
<a href=#46 id=46 data-nosnippet>46</a> </span><span class="kw">static </span><span class="kw-2">ref </span>AWS_KEY: Regex = Regex::new(<span class="string">r"AKIA[0-9A-Z]{16}"</span>).unwrap();
<a href=#47 id=47 data-nosnippet>47</a> <span class="doccomment">/// Generic secret pattern that captures common keywords like password, secret, key or token.
<a href=#48 id=48 data-nosnippet>48</a> /// The capture group (`$1`) is retained so that the surrounding identifier is preserved.
<a href=#49 id=49 data-nosnippet>49</a> </span><span class="kw">static </span><span class="kw-2">ref </span>GENERIC_SECRET: Regex = Regex::new(<span class="string">r"(?i)(password|secret|key|token)\s*[:=]\s*[^\s]+"</span>).unwrap();
<a href=#50 id=50 data-nosnippet>50</a>}
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">impl </span>SecretSentinel {
<a href=#53 id=53 data-nosnippet>53</a> <span class="doccomment">/// Constructs a `SecretSentinel` prepopulated with a sensible default set of rules.
<a href=#54 id=54 data-nosnippet>54</a> ///
<a href=#55 id=55 data-nosnippet>55</a> /// * **WHAT** Returns a sentinel containing three rules: OpenAI, AWS and a generic
<a href=#56 id=56 data-nosnippet>56</a> /// secret matcher.
<a href=#57 id=57 data-nosnippet>57</a> /// * **HOW** Instantiates `RedactionRule`s using the lazilyinitialised regexes
<a href=#58 id=58 data-nosnippet>58</a> /// above and stores them in the `rules` vector.
<a href=#59 id=59 data-nosnippet>59</a> /// * **WHY** Provides a readytouse configuration for typical development
<a href=#60 id=60 data-nosnippet>60</a> /// environments while still allowing callers to create custom instances.
<a href=#61 id=61 data-nosnippet>61</a> </span><span class="kw">pub fn </span>new_default() -&gt; <span class="self">Self </span>{
<a href=#62 id=62 data-nosnippet>62</a> <span class="kw">let </span>rules = <span class="macro">vec!</span>[
<a href=#63 id=63 data-nosnippet>63</a> RedactionRule {
<a href=#64 id=64 data-nosnippet>64</a> name: <span class="string">"OpenAI API Key"</span>.into(),
<a href=#65 id=65 data-nosnippet>65</a> pattern: OPENAI_KEY.clone(),
<a href=#66 id=66 data-nosnippet>66</a> replacement: <span class="string">"[REDACTED OPENAI KEY]"</span>.into(),
<a href=#67 id=67 data-nosnippet>67</a> },
<a href=#68 id=68 data-nosnippet>68</a> RedactionRule {
<a href=#69 id=69 data-nosnippet>69</a> name: <span class="string">"AWS Access Key"</span>.into(),
<a href=#70 id=70 data-nosnippet>70</a> pattern: AWS_KEY.clone(),
<a href=#71 id=71 data-nosnippet>71</a> replacement: <span class="string">"[REDACTED AWS KEY]"</span>.into(),
<a href=#72 id=72 data-nosnippet>72</a> },
<a href=#73 id=73 data-nosnippet>73</a> RedactionRule {
<a href=#74 id=74 data-nosnippet>74</a> name: <span class="string">"Generic Secret"</span>.into(),
<a href=#75 id=75 data-nosnippet>75</a> pattern: GENERIC_SECRET.clone(),
<a href=#76 id=76 data-nosnippet>76</a> <span class="comment">// $1 refers to the captured keyword (password, secret, …).
<a href=#77 id=77 data-nosnippet>77</a> </span>replacement: <span class="string">"$1: [REDACTED]"</span>.into(),
<a href=#78 id=78 data-nosnippet>78</a> },
<a href=#79 id=79 data-nosnippet>79</a> ];
<a href=#80 id=80 data-nosnippet>80</a> <span class="self">Self </span>{ rules }
<a href=#81 id=81 data-nosnippet>81</a> }
<a href=#82 id=82 data-nosnippet>82</a>
<a href=#83 id=83 data-nosnippet>83</a> <span class="doccomment">/// Redacts all secrets found in `input` according to the configured rules.
<a href=#84 id=84 data-nosnippet>84</a> ///
<a href=#85 id=85 data-nosnippet>85</a> /// * **WHAT** Returns a new `String` where each match has been replaced.
<a href=#86 id=86 data-nosnippet>86</a> /// * **HOW** Iterates over the rules and applies `replace_all` for each.
<a href=#87 id=87 data-nosnippet>87</a> /// * **WHY** Performing the replacements sequentially ensures that overlapping
<a href=#88 id=88 data-nosnippet>88</a> /// patterns are handled deterministically.
<a href=#89 id=89 data-nosnippet>89</a> </span><span class="kw">pub fn </span>scrub_text(<span class="kw-2">&amp;</span><span class="self">self</span>, input: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">let </span><span class="kw-2">mut </span>scrubbed = input.to_string();
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">for </span>rule <span class="kw">in </span><span class="kw-2">&amp;</span><span class="self">self</span>.rules {
<a href=#92 id=92 data-nosnippet>92</a> scrubbed = rule
<a href=#93 id=93 data-nosnippet>93</a> .pattern
<a href=#94 id=94 data-nosnippet>94</a> .replace_all(<span class="kw-2">&amp;</span>scrubbed, <span class="kw-2">&amp;</span>rule.replacement)
<a href=#95 id=95 data-nosnippet>95</a> .to_string();
<a href=#96 id=96 data-nosnippet>96</a> }
<a href=#97 id=97 data-nosnippet>97</a> scrubbed
<a href=#98 id=98 data-nosnippet>98</a> }
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="doccomment">/// Checks whether any of the configured rules match `input`.
<a href=#101 id=101 data-nosnippet>101</a> ///
<a href=#102 id=102 data-nosnippet>102</a> /// * **WHAT** Returns `true` if at least one rule's pattern matches.
<a href=#103 id=103 data-nosnippet>103</a> /// * **HOW** Uses `Iter::any` over `self.rules` with `is_match`.
<a href=#104 id=104 data-nosnippet>104</a> /// * **WHY** A quick predicate useful for shortcircuiting logging or error
<a href=#105 id=105 data-nosnippet>105</a> /// handling before performing the full redaction.
<a href=#106 id=106 data-nosnippet>106</a> </span><span class="kw">pub fn </span>contains_secrets(<span class="kw-2">&amp;</span><span class="self">self</span>, input: <span class="kw-2">&amp;</span>str) -&gt; bool {
<a href=#107 id=107 data-nosnippet>107</a> <span class="self">self</span>.rules.iter().any(|rule| rule.pattern.is_match(input))
<a href=#108 id=108 data-nosnippet>108</a> }
<a href=#109 id=109 data-nosnippet>109</a>}
<a href=#110 id=110 data-nosnippet>110</a>
<a href=#111 id=111 data-nosnippet>111</a><span class="attr">#[cfg(test)]
<a href=#112 id=112 data-nosnippet>112</a></span><span class="kw">mod </span>tests {
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
<a href=#114 id=114 data-nosnippet>114</a>
<a href=#115 id=115 data-nosnippet>115</a> <span class="attr">#[test]
<a href=#116 id=116 data-nosnippet>116</a> </span><span class="kw">fn </span>test_scrub_openai_key() {
<a href=#117 id=117 data-nosnippet>117</a> <span class="kw">let </span>sentinel = SecretSentinel::new_default();
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">let </span>input = <span class="string">"My key is sk-1234567890abcdef1234567890abcdef1234567890abcdef"</span>;
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw">let </span>output = sentinel.scrub_text(input);
<a href=#120 id=120 data-nosnippet>120</a> <span class="macro">assert!</span>(output.contains(<span class="string">"[REDACTED OPENAI KEY]"</span>));
<a href=#121 id=121 data-nosnippet>121</a> <span class="macro">assert!</span>(!output.contains(<span class="string">"sk-1234567890"</span>));
<a href=#122 id=122 data-nosnippet>122</a> }
<a href=#123 id=123 data-nosnippet>123</a>
<a href=#124 id=124 data-nosnippet>124</a> <span class="attr">#[test]
<a href=#125 id=125 data-nosnippet>125</a> </span><span class="kw">fn </span>test_scrub_generic_password() {
<a href=#126 id=126 data-nosnippet>126</a> <span class="kw">let </span>sentinel = SecretSentinel::new_default();
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">let </span>input = <span class="string">"login with password: my-secret-password now"</span>;
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">let </span>output = sentinel.scrub_text(input);
<a href=#129 id=129 data-nosnippet>129</a> <span class="macro">assert!</span>(output.contains(<span class="string">"password: [REDACTED]"</span>));
<a href=#130 id=130 data-nosnippet>130</a> }
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a> <span class="attr">#[test]
<a href=#133 id=133 data-nosnippet>133</a> </span><span class="kw">fn </span>test_contains_secrets() {
<a href=#134 id=134 data-nosnippet>134</a> <span class="kw">let </span>sentinel = SecretSentinel::new_default();
<a href=#135 id=135 data-nosnippet>135</a> <span class="macro">assert!</span>(sentinel.contains_secrets(<span class="string">"AKIAIOSFODNN7EXAMPLE"</span>));
<a href=#136 id=136 data-nosnippet>136</a> <span class="macro">assert!</span>(!sentinel.contains_secrets(<span class="string">"nothing sensitive here"</span>));
<a href=#137 id=137 data-nosnippet>137</a> }
<a href=#138 id=138 data-nosnippet>138</a>}</code></pre></div></section></main></body></html>

View File

@@ -0,0 +1,181 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `chrs-slurp/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="chrs_slurp" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../../static.files/storage-82c7156e.js"></script><script defer src="../../static.files/src-script-63605ae7.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">chrs_slurp/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! # chrs-slurp
<a href=#2 id=2 data-nosnippet>2</a>//!
<a href=#3 id=3 data-nosnippet>3</a>//! **Intelligence Crate** Provides the *curation* layer for the CHORUS system.
<a href=#4 id=4 data-nosnippet>4</a>//!
<a href=#5 id=5 data-nosnippet>5</a>//! The purpose of this crate is to take **Decision Records** generated by autonomous
<a href=#6 id=6 data-nosnippet>6</a>//! agents, validate them, and persist them into the graph database. It isolates the
<a href=#7 id=7 data-nosnippet>7</a>//! validation and storage concerns so that other components (e.g. provenance, security)
<a href=#8 id=8 data-nosnippet>8</a>//! can work with a clean, audited data model.
<a href=#9 id=9 data-nosnippet>9</a>//!
<a href=#10 id=10 data-nosnippet>10</a>//! ## Architectural Rationale
<a href=#11 id=11 data-nosnippet>11</a>//!
<a href=#12 id=12 data-nosnippet>12</a>//! * **Separation of concerns** Agents produce raw decisions; this crate is the
<a href=#13 id=13 data-nosnippet>13</a>//! single source of truth for how those decisions are stored.
<a href=#14 id=14 data-nosnippet>14</a>//! * **Auditability** By persisting to a Doltbacked graph each decision is versioned
<a href=#15 id=15 data-nosnippet>15</a>//! and can be replaybacked, satisfying CHORUSs requirement for reproducible
<a href=#16 id=16 data-nosnippet>16</a>//! reasoning.
<a href=#17 id=17 data-nosnippet>17</a>//! * **Extensibility** The `CurationEngine` can be extended with additional validation
<a href=#18 id=18 data-nosnippet>18</a>//! steps (e.g. policy checks) without touching the agents themselves.
<a href=#19 id=19 data-nosnippet>19</a>//!
<a href=#20 id=20 data-nosnippet>20</a>//! The crate depends on:
<a href=#21 id=21 data-nosnippet>21</a>//! * `chrs-graph` a thin wrapper around a Doltbacked graph implementation.
<a href=#22 id=22 data-nosnippet>22</a>//! * `ucxl` for addressing external knowledge artefacts.
<a href=#23 id=23 data-nosnippet>23</a>//! * `chrono`, `serde`, `uuid` standard utilities for timestamps, (de)serialization
<a href=#24 id=24 data-nosnippet>24</a>//! and unique identifiers.
<a href=#25 id=25 data-nosnippet>25</a>//!
<a href=#26 id=26 data-nosnippet>26</a>//! ---
<a href=#27 id=27 data-nosnippet>27</a>//!
<a href=#28 id=28 data-nosnippet>28</a>//! # Public API
<a href=#29 id=29 data-nosnippet>29</a>//!
<a href=#30 id=30 data-nosnippet>30</a>//! The public surface consists of three items:
<a href=#31 id=31 data-nosnippet>31</a>//!
<a href=#32 id=32 data-nosnippet>32</a>//! * `DecisionRecord` data structure representing a curated decision.
<a href=#33 id=33 data-nosnippet>33</a>//! * `SlurpError` enumeration of possible errors while curating.
<a href=#34 id=34 data-nosnippet>34</a>//! * `CurationEngine` the engine that validates and persists `DecisionRecord`s.
<a href=#35 id=35 data-nosnippet>35</a>//!
<a href=#36 id=36 data-nosnippet>36</a>//! Each item is documented inline below.
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a></span><span class="kw">use </span>chrono::{DateTime, Utc};
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>chrs_graph::{DoltGraph, GraphError};
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span>serde::{Deserialize, Serialize};
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span>thiserror::Error;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span>ucxl::UCXLAddress;
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">use </span>uuid::Uuid;
<a href=#44 id=44 data-nosnippet>44</a>
<a href=#45 id=45 data-nosnippet>45</a><span class="doccomment">/// A record representing a curated decision within the CHORUS system.
<a href=#46 id=46 data-nosnippet>46</a>///
<a href=#47 id=47 data-nosnippet>47</a>/// # What
<a href=#48 id=48 data-nosnippet>48</a>///
<a href=#49 id=49 data-nosnippet>49</a>/// This struct captures the essential metadata of a decision made by an
<a href=#50 id=50 data-nosnippet>50</a>/// autonomous agent, including who authored it, the reasoning behind it, any
<a href=#51 id=51 data-nosnippet>51</a>/// citations to external knowledge, and a timestamp.
<a href=#52 id=52 data-nosnippet>52</a>///
<a href=#53 id=53 data-nosnippet>53</a>/// # Why
<a href=#54 id=54 data-nosnippet>54</a>///
<a href=#55 id=55 data-nosnippet>55</a>/// Decision records are persisted in the graph database so that downstream
<a href=#56 id=56 data-nosnippet>56</a>/// components (e.g., provenance analysis) can reason about the provenance and
<a href=#57 id=57 data-nosnippet>57</a>/// justification of actions. Storing them as a dedicated table enables
<a href=#58 id=58 data-nosnippet>58</a>/// reproducibility and auditability across the CHORUS architecture.
<a href=#59 id=59 data-nosnippet>59</a></span><span class="attr">#[derive(Debug, Serialize, Deserialize, Clone)]
<a href=#60 id=60 data-nosnippet>60</a></span><span class="kw">pub struct </span>DecisionRecord {
<a href=#61 id=61 data-nosnippet>61</a> <span class="doccomment">/// Unique identifier for the decision.
<a href=#62 id=62 data-nosnippet>62</a> </span><span class="kw">pub </span>id: Uuid,
<a href=#63 id=63 data-nosnippet>63</a> <span class="doccomment">/// Identifier of the agent or human that authored the decision.
<a href=#64 id=64 data-nosnippet>64</a> </span><span class="kw">pub </span>author: String,
<a href=#65 id=65 data-nosnippet>65</a> <span class="doccomment">/// Freeform textual reasoning explaining the decision.
<a href=#66 id=66 data-nosnippet>66</a> </span><span class="kw">pub </span>reasoning: String,
<a href=#67 id=67 data-nosnippet>67</a> <span class="doccomment">/// Serialized UCXL addresses that serve as citations for the decision.
<a href=#68 id=68 data-nosnippet>68</a> /// Each entry should be a valid `UCXLAddress` string.
<a href=#69 id=69 data-nosnippet>69</a> </span><span class="kw">pub </span>citations: Vec&lt;String&gt;,
<a href=#70 id=70 data-nosnippet>70</a> <span class="doccomment">/// The moment the decision was created.
<a href=#71 id=71 data-nosnippet>71</a> </span><span class="kw">pub </span>timestamp: DateTime&lt;Utc&gt;,
<a href=#72 id=72 data-nosnippet>72</a>}
<a href=#73 id=73 data-nosnippet>73</a>
<a href=#74 id=74 data-nosnippet>74</a><span class="doccomment">/// Errors that can arise while slurping (curating) a decision record.
<a href=#75 id=75 data-nosnippet>75</a>///
<a href=#76 id=76 data-nosnippet>76</a>/// * `Graph` underlying graph database operation failed.
<a href=#77 id=77 data-nosnippet>77</a>/// * `Serde` (de)serialization of the decision data failed.
<a href=#78 id=78 data-nosnippet>78</a>/// * `ValidationError` a supplied citation could not be parsed as a
<a href=#79 id=79 data-nosnippet>79</a>/// `UCXLAddress`.
<a href=#80 id=80 data-nosnippet>80</a></span><span class="attr">#[derive(Debug, Error)]
<a href=#81 id=81 data-nosnippet>81</a></span><span class="kw">pub enum </span>SlurpError {
<a href=#82 id=82 data-nosnippet>82</a> <span class="attr">#[error(<span class="string">"Graph error: {0}"</span>)]
<a href=#83 id=83 data-nosnippet>83</a> </span>Graph(<span class="attr">#[from] </span>GraphError),
<a href=#84 id=84 data-nosnippet>84</a> <span class="attr">#[error(<span class="string">"Serialization error: {0}"</span>)]
<a href=#85 id=85 data-nosnippet>85</a> </span>Serde(<span class="attr">#[from] </span>serde_json::Error),
<a href=#86 id=86 data-nosnippet>86</a> <span class="attr">#[error(<span class="string">"Validation error: {0}"</span>)]
<a href=#87 id=87 data-nosnippet>87</a> </span>ValidationError(String),
<a href=#88 id=88 data-nosnippet>88</a>}
<a href=#89 id=89 data-nosnippet>89</a>
<a href=#90 id=90 data-nosnippet>90</a><span class="doccomment">/// Core engine that validates and persists `DecisionRecord`s into the
<a href=#91 id=91 data-nosnippet>91</a>/// Doltbacked graph.
<a href=#92 id=92 data-nosnippet>92</a>///
<a href=#93 id=93 data-nosnippet>93</a>/// # Why
<a href=#94 id=94 data-nosnippet>94</a>///
<a href=#95 id=95 data-nosnippet>95</a>/// Centralising curation logic ensures a single place for validation and
<a href=#96 id=96 data-nosnippet>96</a>/// storage semantics, keeping the rest of the codebase agnostic of the graph
<a href=#97 id=97 data-nosnippet>97</a>/// implementation details.
<a href=#98 id=98 data-nosnippet>98</a></span><span class="kw">pub struct </span>CurationEngine {
<a href=#99 id=99 data-nosnippet>99</a> graph: DoltGraph,
<a href=#100 id=100 data-nosnippet>100</a>}
<a href=#101 id=101 data-nosnippet>101</a>
<a href=#102 id=102 data-nosnippet>102</a><span class="kw">impl </span>CurationEngine {
<a href=#103 id=103 data-nosnippet>103</a> <span class="doccomment">/// Creates a new `CurationEngine` bound to the supplied `DoltGraph`.
<a href=#104 id=104 data-nosnippet>104</a> ///
<a href=#105 id=105 data-nosnippet>105</a> /// The engine holds a reference to the graph for the lifetime of the
<a href=#106 id=106 data-nosnippet>106</a> /// instance; callers are responsible for providing a correctly initialised
<a href=#107 id=107 data-nosnippet>107</a> /// graph.
<a href=#108 id=108 data-nosnippet>108</a> </span><span class="kw">pub fn </span>new(graph: DoltGraph) -&gt; <span class="self">Self </span>{
<a href=#109 id=109 data-nosnippet>109</a> <span class="self">Self </span>{ graph }
<a href=#110 id=110 data-nosnippet>110</a> }
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a> <span class="doccomment">/// Validates the citations in `dr` and persists the decision into the
<a href=#113 id=113 data-nosnippet>113</a> /// graph.
<a href=#114 id=114 data-nosnippet>114</a> ///
<a href=#115 id=115 data-nosnippet>115</a> /// The method performs three steps:
<a href=#116 id=116 data-nosnippet>116</a> /// 1. **Citation validation** each citation string is parsed into a
<a href=#117 id=117 data-nosnippet>117</a> /// `UCXLAddress`. Invalid citations produce a `ValidationError`.
<a href=#118 id=118 data-nosnippet>118</a> /// 2. **Table assurance** attempts to create the `curated_decisions`
<a href=#119 id=119 data-nosnippet>119</a> /// table if it does not already exist. Errors are ignored because the
<a href=#120 id=120 data-nosnippet>120</a> /// table may already be present.
<a href=#121 id=121 data-nosnippet>121</a> /// 3. **Insertion &amp; commit** the decision is serialised to JSON and
<a href=#122 id=122 data-nosnippet>122</a> /// inserted as a node, then the graph transaction is committed.
<a href=#123 id=123 data-nosnippet>123</a> ///
<a href=#124 id=124 data-nosnippet>124</a> /// # Errors
<a href=#125 id=125 data-nosnippet>125</a> /// Propagates any `GraphError`, `serde_json::Error`, or custom
<a href=#126 id=126 data-nosnippet>126</a> /// validation failures.
<a href=#127 id=127 data-nosnippet>127</a> </span><span class="kw">pub fn </span>curate_decision(<span class="kw-2">&amp;</span><span class="self">self</span>, dr: DecisionRecord) -&gt; <span class="prelude-ty">Result</span>&lt;(), SlurpError&gt; {
<a href=#128 id=128 data-nosnippet>128</a> <span class="comment">// 1. Validate Citations
<a href=#129 id=129 data-nosnippet>129</a> </span><span class="kw">for </span>citation <span class="kw">in </span><span class="kw-2">&amp;</span>dr.citations {
<a href=#130 id=130 data-nosnippet>130</a> <span class="kw">use </span>std::str::FromStr;
<a href=#131 id=131 data-nosnippet>131</a> UCXLAddress::from_str(citation).map_err(|e| {
<a href=#132 id=132 data-nosnippet>132</a> SlurpError::ValidationError(<span class="macro">format!</span>(<span class="string">"Invalid citation {}: {}"</span>, citation, e))
<a href=#133 id=133 data-nosnippet>133</a> })<span class="question-mark">?</span>;
<a href=#134 id=134 data-nosnippet>134</a> }
<a href=#135 id=135 data-nosnippet>135</a>
<a href=#136 id=136 data-nosnippet>136</a> <span class="comment">// 2. Ensure the table exists; ignore error if it already does.
<a href=#137 id=137 data-nosnippet>137</a> </span><span class="kw">let _ </span>= <span class="self">self</span>.graph.create_table(
<a href=#138 id=138 data-nosnippet>138</a> <span class="string">"curated_decisions"</span>,
<a href=#139 id=139 data-nosnippet>139</a> <span class="string">"id VARCHAR(255) PRIMARY KEY, author TEXT, reasoning TEXT, citations TEXT, curated_at TEXT"</span>,
<a href=#140 id=140 data-nosnippet>140</a> );
<a href=#141 id=141 data-nosnippet>141</a>
<a href=#142 id=142 data-nosnippet>142</a> <span class="comment">// 3. Serialize the record and insert it.
<a href=#143 id=143 data-nosnippet>143</a> </span><span class="kw">let </span>data = <span class="macro">serde_json::json!</span>({
<a href=#144 id=144 data-nosnippet>144</a> <span class="string">"id"</span>: dr.id.to_string(),
<a href=#145 id=145 data-nosnippet>145</a> <span class="string">"author"</span>: dr.author,
<a href=#146 id=146 data-nosnippet>146</a> <span class="string">"reasoning"</span>: dr.reasoning,
<a href=#147 id=147 data-nosnippet>147</a> <span class="string">"citations"</span>: serde_json::to_string(<span class="kw-2">&amp;</span>dr.citations)<span class="question-mark">?</span>,
<a href=#148 id=148 data-nosnippet>148</a> <span class="string">"curated_at"</span>: dr.timestamp.to_rfc3339(),
<a href=#149 id=149 data-nosnippet>149</a> });
<a href=#150 id=150 data-nosnippet>150</a>
<a href=#151 id=151 data-nosnippet>151</a> <span class="self">self</span>.graph.insert_node(<span class="string">"curated_decisions"</span>, data)<span class="question-mark">?</span>;
<a href=#152 id=152 data-nosnippet>152</a> <span class="self">self</span>.graph
<a href=#153 id=153 data-nosnippet>153</a> .commit(<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"Curation complete for DR: {}"</span>, dr.id))<span class="question-mark">?</span>;
<a href=#154 id=154 data-nosnippet>154</a> <span class="prelude-val">Ok</span>(())
<a href=#155 id=155 data-nosnippet>155</a> }
<a href=#156 id=156 data-nosnippet>156</a>}
<a href=#157 id=157 data-nosnippet>157</a>
<a href=#158 id=158 data-nosnippet>158</a><span class="attr">#[cfg(test)]
<a href=#159 id=159 data-nosnippet>159</a></span><span class="kw">mod </span>tests {
<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
<a href=#161 id=161 data-nosnippet>161</a> <span class="kw">use </span>tempfile::TempDir;
<a href=#162 id=162 data-nosnippet>162</a>
<a href=#163 id=163 data-nosnippet>163</a> <span class="doccomment">/// Integration test that exercises the full curation flow on a temporary
<a href=#164 id=164 data-nosnippet>164</a> /// Dolt graph.
<a href=#165 id=165 data-nosnippet>165</a> </span><span class="attr">#[test]
<a href=#166 id=166 data-nosnippet>166</a> </span><span class="kw">fn </span>test_curation_flow() {
<a href=#167 id=167 data-nosnippet>167</a> <span class="kw">let </span>dir = TempDir::new().unwrap();
<a href=#168 id=168 data-nosnippet>168</a> <span class="kw">let </span>graph = DoltGraph::init(dir.path()).expect(<span class="string">"graph init failed"</span>);
<a href=#169 id=169 data-nosnippet>169</a> <span class="kw">let </span>engine = CurationEngine::new(graph);
<a href=#170 id=170 data-nosnippet>170</a>
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">let </span>dr = DecisionRecord {
<a href=#172 id=172 data-nosnippet>172</a> id: Uuid::new_v4(),
<a href=#173 id=173 data-nosnippet>173</a> author: <span class="string">"agent-001"</span>.into(),
<a href=#174 id=174 data-nosnippet>174</a> reasoning: <span class="string">"Tested the implementation of SLURP."</span>.into(),
<a href=#175 id=175 data-nosnippet>175</a> citations: <span class="macro">vec!</span>[<span class="string">"ucxl://system:watcher@local:filesystem/#/UCXL/src/lib.rs"</span>.into()],
<a href=#176 id=176 data-nosnippet>176</a> timestamp: Utc::now(),
<a href=#177 id=177 data-nosnippet>177</a> };
<a href=#178 id=178 data-nosnippet>178</a>
<a href=#179 id=179 data-nosnippet>179</a> engine.curate_decision(dr).expect(<span class="string">"curation failed"</span>);
<a href=#180 id=180 data-nosnippet>180</a> }
<a href=#181 id=181 data-nosnippet>181</a>}</code></pre></div></section></main></body></html>

View File

@@ -0,0 +1,116 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `chrs-sync/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="chrs_sync" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../../static.files/storage-82c7156e.js"></script><script defer src="../../static.files/src-script-63605ae7.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">chrs_sync/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="kw">use </span>chrono::Utc;
<a href=#2 id=2 data-nosnippet>2</a><span class="doccomment">/// chrs-sync crate provides synchronization utilities for the CHORUS system.
<a href=#3 id=3 data-nosnippet>3</a>///
<a href=#4 id=4 data-nosnippet>4</a>/// It uses a `Mailbox` for message passing between peers and a Dolt repository
<a href=#5 id=5 data-nosnippet>5</a>/// to track state hashes. The primary abstraction is `SyncManager`, which can
<a href=#6 id=6 data-nosnippet>6</a>/// broadcast the current repository hash to peers and handle incoming sync
<a href=#7 id=7 data-nosnippet>7</a>/// signals.
<a href=#8 id=8 data-nosnippet>8</a></span><span class="kw">use </span>chrs_mail::{Mailbox, Message};
<a href=#9 id=9 data-nosnippet>9</a><span class="kw">use </span>std::path::PathBuf;
<a href=#10 id=10 data-nosnippet>10</a><span class="kw">use </span>std::process::Command;
<a href=#11 id=11 data-nosnippet>11</a><span class="kw">use </span>uuid::Uuid;
<a href=#12 id=12 data-nosnippet>12</a>
<a href=#13 id=13 data-nosnippet>13</a><span class="doccomment">/// Manages synchronization of a Dolt repository across peers.
<a href=#14 id=14 data-nosnippet>14</a>///
<a href=#15 id=15 data-nosnippet>15</a>/// # Fields
<a href=#16 id=16 data-nosnippet>16</a>/// * `mailbox` The `Mailbox` instance used to send and receive messages.
<a href=#17 id=17 data-nosnippet>17</a>/// * `repo_path` Filesystem path to the local Dolt repository.
<a href=#18 id=18 data-nosnippet>18</a>///
<a href=#19 id=19 data-nosnippet>19</a>/// # Rationale
<a href=#20 id=20 data-nosnippet>20</a>/// The CHORUS architecture relies on deterministic state replication. By
<a href=#21 id=21 data-nosnippet>21</a>/// broadcasting the latest commit hash (`sync_signal`) each peer can decide
<a href=#22 id=22 data-nosnippet>22</a>/// whether to pull updates. This struct encapsulates that behaviour, keeping the
<a href=#23 id=23 data-nosnippet>23</a>/// rest of the system agnostic of the underlying VCS commands.
<a href=#24 id=24 data-nosnippet>24</a></span><span class="kw">pub struct </span>SyncManager {
<a href=#25 id=25 data-nosnippet>25</a> mailbox: Mailbox,
<a href=#26 id=26 data-nosnippet>26</a> repo_path: PathBuf,
<a href=#27 id=27 data-nosnippet>27</a>}
<a href=#28 id=28 data-nosnippet>28</a>
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">impl </span>SyncManager {
<a href=#30 id=30 data-nosnippet>30</a> <span class="doccomment">/// Creates a new `SyncManager`.
<a href=#31 id=31 data-nosnippet>31</a> ///
<a href=#32 id=32 data-nosnippet>32</a> /// # Parameters
<a href=#33 id=33 data-nosnippet>33</a> /// * `mailbox` An alreadyopened `Mailbox` for peer communication.
<a href=#34 id=34 data-nosnippet>34</a> /// * `repo_path` Path to the Dolt repository that should be kept in sync.
<a href=#35 id=35 data-nosnippet>35</a> ///
<a href=#36 id=36 data-nosnippet>36</a> /// Returns a fullyinitialised manager ready to broadcast or handle sync
<a href=#37 id=37 data-nosnippet>37</a> /// signals.
<a href=#38 id=38 data-nosnippet>38</a> </span><span class="kw">pub fn </span>new(mailbox: Mailbox, repo_path: PathBuf) -&gt; <span class="self">Self </span>{
<a href=#39 id=39 data-nosnippet>39</a> <span class="self">Self </span>{ mailbox, repo_path }
<a href=#40 id=40 data-nosnippet>40</a> }
<a href=#41 id=41 data-nosnippet>41</a>
<a href=#42 id=42 data-nosnippet>42</a> <span class="doccomment">/// Broadcasts the current repository state to a remote peer.
<a href=#43 id=43 data-nosnippet>43</a> ///
<a href=#44 id=44 data-nosnippet>44</a> /// The method executes `dolt log -n 1 --format %H` to obtain the most recent
<a href=#45 id=45 data-nosnippet>45</a> /// commit hash, constructs a `Message` with topic `"sync_signal"` and sends it
<a href=#46 id=46 data-nosnippet>46</a> /// via the mailbox.
<a href=#47 id=47 data-nosnippet>47</a> ///
<a href=#48 id=48 data-nosnippet>48</a> /// * `from_peer` Identifier of the sender.
<a href=#49 id=49 data-nosnippet>49</a> /// * `to_peer` Identifier of the intended recipient.
<a href=#50 id=50 data-nosnippet>50</a> ///
<a href=#51 id=51 data-nosnippet>51</a> /// # Errors
<a href=#52 id=52 data-nosnippet>52</a> /// Returns any I/O or commandexecution error wrapped in a boxed `dyn
<a href=#53 id=53 data-nosnippet>53</a> /// Error`.
<a href=#54 id=54 data-nosnippet>54</a> </span><span class="kw">pub fn </span>broadcast_state(
<a href=#55 id=55 data-nosnippet>55</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#56 id=56 data-nosnippet>56</a> from_peer: <span class="kw-2">&amp;</span>str,
<a href=#57 id=57 data-nosnippet>57</a> to_peer: <span class="kw-2">&amp;</span>str,
<a href=#58 id=58 data-nosnippet>58</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;(), Box&lt;<span class="kw">dyn </span>std::error::Error&gt;&gt; {
<a href=#59 id=59 data-nosnippet>59</a> <span class="comment">// Get current dolt hash
<a href=#60 id=60 data-nosnippet>60</a> </span><span class="kw">let </span>output = Command::new(<span class="string">"dolt"</span>)
<a href=#61 id=61 data-nosnippet>61</a> .args(<span class="kw-2">&amp;</span>[<span class="string">"log"</span>, <span class="string">"-n"</span>, <span class="string">"1"</span>, <span class="string">"--format"</span>, <span class="string">"%H"</span>])
<a href=#62 id=62 data-nosnippet>62</a> .current_dir(<span class="kw-2">&amp;</span><span class="self">self</span>.repo_path)
<a href=#63 id=63 data-nosnippet>63</a> .output()<span class="question-mark">?</span>;
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">let </span>current_hash = String::from_utf8_lossy(<span class="kw-2">&amp;</span>output.stdout).trim().to_string();
<a href=#66 id=66 data-nosnippet>66</a>
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">let </span>msg = Message {
<a href=#68 id=68 data-nosnippet>68</a> id: Uuid::new_v4(),
<a href=#69 id=69 data-nosnippet>69</a> from_peer: from_peer.into(),
<a href=#70 id=70 data-nosnippet>70</a> to_peer: to_peer.into(),
<a href=#71 id=71 data-nosnippet>71</a> topic: <span class="string">"sync_signal"</span>.into(),
<a href=#72 id=72 data-nosnippet>72</a> payload: <span class="macro">serde_json::json!</span>({ <span class="string">"commit_hash"</span>: current_hash }),
<a href=#73 id=73 data-nosnippet>73</a> sent_at: Utc::now(),
<a href=#74 id=74 data-nosnippet>74</a> read_at: <span class="prelude-val">None</span>,
<a href=#75 id=75 data-nosnippet>75</a> };
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a> <span class="self">self</span>.mailbox.send(<span class="kw-2">&amp;</span>msg)<span class="question-mark">?</span>;
<a href=#78 id=78 data-nosnippet>78</a> <span class="macro">println!</span>(
<a href=#79 id=79 data-nosnippet>79</a> <span class="string">"Broadcasted sync signal: {} from {}"</span>,
<a href=#80 id=80 data-nosnippet>80</a> current_hash, from_peer
<a href=#81 id=81 data-nosnippet>81</a> );
<a href=#82 id=82 data-nosnippet>82</a> <span class="prelude-val">Ok</span>(())
<a href=#83 id=83 data-nosnippet>83</a> }
<a href=#84 id=84 data-nosnippet>84</a>
<a href=#85 id=85 data-nosnippet>85</a> <span class="doccomment">/// Handles an incoming `sync_signal` message.
<a href=#86 id=86 data-nosnippet>86</a> ///
<a href=#87 id=87 data-nosnippet>87</a> /// If the message topic is not `"sync_signal"` the function returns `Ok(())`
<a href=#88 id=88 data-nosnippet>88</a> /// immediately. Otherwise it extracts the remote commit hash and attempts a
<a href=#89 id=89 data-nosnippet>89</a> /// `dolt pull origin` to bring the local repository uptodate. In a real
<a href=#90 id=90 data-nosnippet>90</a> /// P2P deployment the remote URL would be derived from the sender, but the
<a href=#91 id=91 data-nosnippet>91</a> /// current implementation uses the default remote configuration.
<a href=#92 id=92 data-nosnippet>92</a> ///
<a href=#93 id=93 data-nosnippet>93</a> /// # Errors
<a href=#94 id=94 data-nosnippet>94</a> /// Propagates any command execution failures.
<a href=#95 id=95 data-nosnippet>95</a> </span><span class="kw">pub fn </span>handle_sync_signal(<span class="kw-2">&amp;</span><span class="self">self</span>, msg: <span class="kw-2">&amp;</span>Message) -&gt; <span class="prelude-ty">Result</span>&lt;(), Box&lt;<span class="kw">dyn </span>std::error::Error&gt;&gt; {
<a href=#96 id=96 data-nosnippet>96</a> <span class="kw">if </span>msg.topic != <span class="string">"sync_signal" </span>{
<a href=#97 id=97 data-nosnippet>97</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#98 id=98 data-nosnippet>98</a> }
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">let </span>remote_hash = msg.payload[<span class="string">"commit_hash"</span>].as_str().unwrap_or_default();
<a href=#101 id=101 data-nosnippet>101</a> <span class="macro">println!</span>(<span class="string">"Received sync signal for hash: {}"</span>, remote_hash);
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a> <span class="comment">// In a real P2P scenario, we would pull from the remote peer's URL.
<a href=#104 id=104 data-nosnippet>104</a> // For now, we simulate by attempting a 'dolt pull' if a remote is configured.
<a href=#105 id=105 data-nosnippet>105</a> </span><span class="kw">let </span>status = Command::new(<span class="string">"dolt"</span>)
<a href=#106 id=106 data-nosnippet>106</a> .args(<span class="kw-2">&amp;</span>[<span class="string">"pull"</span>, <span class="string">"origin"</span>])
<a href=#107 id=107 data-nosnippet>107</a> .current_dir(<span class="kw-2">&amp;</span><span class="self">self</span>.repo_path)
<a href=#108 id=108 data-nosnippet>108</a> .status()<span class="question-mark">?</span>;
<a href=#109 id=109 data-nosnippet>109</a>
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">if </span>status.success() {
<a href=#111 id=111 data-nosnippet>111</a> <span class="macro">println!</span>(<span class="string">"Successfully pulled updates for hash: {}"</span>, remote_hash);
<a href=#112 id=112 data-nosnippet>112</a> }
<a href=#113 id=113 data-nosnippet>113</a>
<a href=#114 id=114 data-nosnippet>114</a> <span class="prelude-val">Ok</span>(())
<a href=#115 id=115 data-nosnippet>115</a> }
<a href=#116 id=116 data-nosnippet>116</a>}</code></pre></div></section></main></body></html>

View File

@@ -0,0 +1,301 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `UCXL/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="ucxl" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../../static.files/storage-82c7156e.js"></script><script defer src="../../static.files/src-script-63605ae7.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">ucxl/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! UCXL core data structures and utilities.
<a href=#2 id=2 data-nosnippet>2</a>//!
<a href=#3 id=3 data-nosnippet>3</a>//! This module provides the fundamental types used throughout the CHORUS
<a href=#4 id=4 data-nosnippet>4</a>//! system for addressing resources (UCXL addresses), handling temporal axes,
<a href=#5 id=5 data-nosnippet>5</a>//! and storing lightweight metadata. The implementation is deliberately
<a href=#6 id=6 data-nosnippet>6</a>//! lightweight and inmemory to keep the core fast and dependencyfree.
<a href=#7 id=7 data-nosnippet>7</a>
<a href=#8 id=8 data-nosnippet>8</a></span><span class="kw">pub mod </span>watcher;
<a href=#9 id=9 data-nosnippet>9</a>
<a href=#10 id=10 data-nosnippet>10</a><span class="kw">use </span>std::collections::HashMap;
<a href=#11 id=11 data-nosnippet>11</a><span class="kw">use </span>std::fmt;
<a href=#12 id=12 data-nosnippet>12</a><span class="kw">use </span>std::str::FromStr;
<a href=#13 id=13 data-nosnippet>13</a>
<a href=#14 id=14 data-nosnippet>14</a><span class="doccomment">/// Represents the temporal axis in a UCXL address.
<a href=#15 id=15 data-nosnippet>15</a>///
<a href=#16 id=16 data-nosnippet>16</a>/// **What**: An enumeration of the three supported temporal positions
<a href=#17 id=17 data-nosnippet>17</a>/// present, past, and future each represented by a symbolic string in the
<a href=#18 id=18 data-nosnippet>18</a>/// address format.
<a href=#19 id=19 data-nosnippet>19</a>///
<a href=#20 id=20 data-nosnippet>20</a>/// **How**: The enum derives `Debug`, `PartialEq`, `Eq`, `Clone`, and `Copy`
<a href=#21 id=21 data-nosnippet>21</a>/// for ergonomic usage. Conversions to and from strings are provided via the
<a href=#22 id=22 data-nosnippet>22</a>/// `FromStr` and `fmt::Display` implementations.
<a href=#23 id=23 data-nosnippet>23</a>///
<a href=#24 id=24 data-nosnippet>24</a>/// **Why**: Temporal axes enable UCXL to refer to data at different points in
<a href=#25 id=25 data-nosnippet>25</a>/// time (e.g. versioned resources). The simple threestate model matches the
<a href=#26 id=26 data-nosnippet>26</a>/// CHURUS architectural decision to keep addressing lightweight while still
<a href=#27 id=27 data-nosnippet>27</a>/// supporting historical and speculative queries.
<a href=#28 id=28 data-nosnippet>28</a></span><span class="attr">#[derive(Debug, PartialEq, Eq, Clone, Copy)]
<a href=#29 id=29 data-nosnippet>29</a></span><span class="kw">pub enum </span>TemporalAxis {
<a href=#30 id=30 data-nosnippet>30</a> <span class="doccomment">/// Present ("#") the current version of a resource.
<a href=#31 id=31 data-nosnippet>31</a> </span>Present,
<a href=#32 id=32 data-nosnippet>32</a> <span class="doccomment">/// Past ("~~") a historical snapshot of a resource.
<a href=#33 id=33 data-nosnippet>33</a> </span>Past,
<a href=#34 id=34 data-nosnippet>34</a> <span class="doccomment">/// Future ("^^") a speculative or planned version of a resource.
<a href=#35 id=35 data-nosnippet>35</a> </span>Future,
<a href=#36 id=36 data-nosnippet>36</a>}
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">impl </span>FromStr <span class="kw">for </span>TemporalAxis {
<a href=#39 id=39 data-nosnippet>39</a> <span class="kw">type </span><span class="prelude-val">Err </span>= String;
<a href=#40 id=40 data-nosnippet>40</a> <span class="doccomment">/// Parses a temporal axis token from its textual representation.
<a href=#41 id=41 data-nosnippet>41</a> ///
<a href=#42 id=42 data-nosnippet>42</a> /// **What**: Accepts "#", "~~" or "^^" and maps them to the corresponding
<a href=#43 id=43 data-nosnippet>43</a> /// enum variant.
<a href=#44 id=44 data-nosnippet>44</a> ///
<a href=#45 id=45 data-nosnippet>45</a> /// **How**: A simple `match` statement is used; an error string is
<a href=#46 id=46 data-nosnippet>46</a> /// returned for any unrecognised token.
<a href=#47 id=47 data-nosnippet>47</a> ///
<a href=#48 id=48 data-nosnippet>48</a> /// **Why**: Centralises validation of temporal markers used throughout the
<a href=#49 id=49 data-nosnippet>49</a> /// address parsing logic, ensuring consistency.
<a href=#50 id=50 data-nosnippet>50</a> </span><span class="kw">fn </span>from_str(s: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, <span class="self">Self</span>::Err&gt; {
<a href=#51 id=51 data-nosnippet>51</a> <span class="kw">match </span>s {
<a href=#52 id=52 data-nosnippet>52</a> <span class="string">"#" </span>=&gt; <span class="prelude-val">Ok</span>(TemporalAxis::Present),
<a href=#53 id=53 data-nosnippet>53</a> <span class="string">"~~" </span>=&gt; <span class="prelude-val">Ok</span>(TemporalAxis::Past),
<a href=#54 id=54 data-nosnippet>54</a> <span class="string">"^^" </span>=&gt; <span class="prelude-val">Ok</span>(TemporalAxis::Future),
<a href=#55 id=55 data-nosnippet>55</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">Err</span>(<span class="macro">format!</span>(<span class="string">"Invalid temporal axis: {}"</span>, s)),
<a href=#56 id=56 data-nosnippet>56</a> }
<a href=#57 id=57 data-nosnippet>57</a> }
<a href=#58 id=58 data-nosnippet>58</a>}
<a href=#59 id=59 data-nosnippet>59</a>
<a href=#60 id=60 data-nosnippet>60</a><span class="kw">impl </span>fmt::Display <span class="kw">for </span>TemporalAxis {
<a href=#61 id=61 data-nosnippet>61</a> <span class="doccomment">/// Formats the temporal axis back to its string token.
<a href=#62 id=62 data-nosnippet>62</a> ///
<a href=#63 id=63 data-nosnippet>63</a> /// **What**: Returns "#", "~~" or "^^" depending on the variant.
<a href=#64 id=64 data-nosnippet>64</a> ///
<a href=#65 id=65 data-nosnippet>65</a> /// **How**: Matches on `self` and writes the corresponding string to the
<a href=#66 id=66 data-nosnippet>66</a> /// formatter.
<a href=#67 id=67 data-nosnippet>67</a> ///
<a href=#68 id=68 data-nosnippet>68</a> /// **Why**: Required for serialising a `UCXLAddress` back to its textual
<a href=#69 id=69 data-nosnippet>69</a> /// representation.
<a href=#70 id=70 data-nosnippet>70</a> </span><span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; fmt::Result {
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">let </span>s = <span class="kw">match </span><span class="self">self </span>{
<a href=#72 id=72 data-nosnippet>72</a> TemporalAxis::Present =&gt; <span class="string">"#"</span>,
<a href=#73 id=73 data-nosnippet>73</a> TemporalAxis::Past =&gt; <span class="string">"~~"</span>,
<a href=#74 id=74 data-nosnippet>74</a> TemporalAxis::Future =&gt; <span class="string">"^^"</span>,
<a href=#75 id=75 data-nosnippet>75</a> };
<a href=#76 id=76 data-nosnippet>76</a> <span class="macro">write!</span>(f, <span class="string">"{}"</span>, s)
<a href=#77 id=77 data-nosnippet>77</a> }
<a href=#78 id=78 data-nosnippet>78</a>}
<a href=#79 id=79 data-nosnippet>79</a>
<a href=#80 id=80 data-nosnippet>80</a><span class="doccomment">/// Represents a parsed UCXL address.
<a href=#81 id=81 data-nosnippet>81</a>///
<a href=#82 id=82 data-nosnippet>82</a>/// **What**: Holds the components extracted from a UCXL URI the agent, an
<a href=#83 id=83 data-nosnippet>83</a>/// optional role, the project identifier, task name, temporal axis, and the
<a href=#84 id=84 data-nosnippet>84</a>/// resource path within the project.
<a href=#85 id=85 data-nosnippet>85</a>///
<a href=#86 id=86 data-nosnippet>86</a>/// **How**: The struct is constructed via the `FromStr` implementation which
<a href=#87 id=87 data-nosnippet>87</a>/// validates the scheme, splits the address into its constituent parts and
<a href=#88 id=88 data-nosnippet>88</a>/// populates the fields. The `Display` implementation performs the inverse
<a href=#89 id=89 data-nosnippet>89</a>/// operation.
<a href=#90 id=90 data-nosnippet>90</a>///
<a href=#91 id=91 data-nosnippet>91</a>/// **Why**: UCXL addresses are the primary routing mechanism inside CHORUS.
<a href=#92 id=92 data-nosnippet>92</a>/// Encapsulating them in a dedicated type provides typesafety and makes it
<a href=#93 id=93 data-nosnippet>93</a>/// easy to work with address components in the rest of the codebase.
<a href=#94 id=94 data-nosnippet>94</a></span><span class="attr">#[derive(Debug, PartialEq, Eq, Clone)]
<a href=#95 id=95 data-nosnippet>95</a></span><span class="kw">pub struct </span>UCXLAddress {
<a href=#96 id=96 data-nosnippet>96</a> <span class="doccomment">/// The identifier of the agent (e.g., a user or system component).
<a href=#97 id=97 data-nosnippet>97</a> </span><span class="kw">pub </span>agent: String,
<a href=#98 id=98 data-nosnippet>98</a> <span class="doccomment">/// Optional role associated with the agent (e.g., "admin").
<a href=#99 id=99 data-nosnippet>99</a> </span><span class="kw">pub </span>role: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#100 id=100 data-nosnippet>100</a> <span class="doccomment">/// The project namespace this address belongs to.
<a href=#101 id=101 data-nosnippet>101</a> </span><span class="kw">pub </span>project: String,
<a href=#102 id=102 data-nosnippet>102</a> <span class="doccomment">/// The specific task within the project.
<a href=#103 id=103 data-nosnippet>103</a> </span><span class="kw">pub </span>task: String,
<a href=#104 id=104 data-nosnippet>104</a> <span class="doccomment">/// Temporal axis indicating present, past or future.
<a href=#105 id=105 data-nosnippet>105</a> </span><span class="kw">pub </span>temporal: TemporalAxis,
<a href=#106 id=106 data-nosnippet>106</a> <span class="doccomment">/// Path to the resource relative to the project root.
<a href=#107 id=107 data-nosnippet>107</a> </span><span class="kw">pub </span>path: String,
<a href=#108 id=108 data-nosnippet>108</a>}
<a href=#109 id=109 data-nosnippet>109</a>
<a href=#110 id=110 data-nosnippet>110</a><span class="kw">impl </span>FromStr <span class="kw">for </span>UCXLAddress {
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">type </span><span class="prelude-val">Err </span>= String;
<a href=#112 id=112 data-nosnippet>112</a> <span class="doccomment">/// Parses a full UCXL address string into a `UCXLAddress` value.
<a href=#113 id=113 data-nosnippet>113</a> ///
<a href=#114 id=114 data-nosnippet>114</a> /// **What**: Validates the scheme (`ucxl://`), extracts the agent, optional
<a href=#115 id=115 data-nosnippet>115</a> /// role, project, task, temporal axis and the trailing resource path.
<a href=#116 id=116 data-nosnippet>116</a> ///
<a href=#117 id=117 data-nosnippet>117</a> /// **How**: The implementation performs a series of `split` operations,
<a href=#118 id=118 data-nosnippet>118</a> /// handling optional components and converting the temporal token via
<a href=#119 id=119 data-nosnippet>119</a> /// `TemporalAxis::from_str`. Errors are surfaced as descriptive strings.
<a href=#120 id=120 data-nosnippet>120</a> ///
<a href=#121 id=121 data-nosnippet>121</a> /// **Why**: Centralises address parsing logic, ensuring that all parts of
<a href=#122 id=122 data-nosnippet>122</a> /// the system interpret UCXL URIs consistently.
<a href=#123 id=123 data-nosnippet>123</a> </span><span class="kw">fn </span>from_str(address: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, <span class="self">Self</span>::Err&gt; {
<a href=#124 id=124 data-nosnippet>124</a> <span class="comment">// Ensure the scheme is correct
<a href=#125 id=125 data-nosnippet>125</a> </span><span class="kw">let </span>scheme_split: Vec&lt;<span class="kw-2">&amp;</span>str&gt; = address.splitn(<span class="number">2</span>, <span class="string">"://"</span>).collect();
<a href=#126 id=126 data-nosnippet>126</a> <span class="kw">if </span>scheme_split.len() != <span class="number">2 </span>|| scheme_split[<span class="number">0</span>] != <span class="string">"ucxl" </span>{
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="string">"Address must start with 'ucxl://'"</span>.into());
<a href=#128 id=128 data-nosnippet>128</a> }
<a href=#129 id=129 data-nosnippet>129</a> <span class="kw">let </span>remainder = scheme_split[<span class="number">1</span>];
<a href=#130 id=130 data-nosnippet>130</a> <span class="comment">// Split at the first '@' to separate agent/role from project/task
<a href=#131 id=131 data-nosnippet>131</a> </span><span class="kw">let </span>parts: Vec&lt;<span class="kw-2">&amp;</span>str&gt; = remainder.splitn(<span class="number">2</span>, <span class="string">'@'</span>).collect();
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">if </span>parts.len() != <span class="number">2 </span>{
<a href=#133 id=133 data-nosnippet>133</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="string">"Missing '@' separating agent and project"</span>.into());
<a href=#134 id=134 data-nosnippet>134</a> }
<a href=#135 id=135 data-nosnippet>135</a> <span class="comment">// Agent and optional role
<a href=#136 id=136 data-nosnippet>136</a> </span><span class="kw">let </span>agent_part = parts[<span class="number">0</span>];
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">let </span><span class="kw-2">mut </span>agent_iter = agent_part.splitn(<span class="number">2</span>, <span class="string">':'</span>);
<a href=#138 id=138 data-nosnippet>138</a> <span class="kw">let </span>agent = agent_iter.next().unwrap().to_string();
<a href=#139 id=139 data-nosnippet>139</a> <span class="kw">let </span>role = agent_iter.next().map(|s| s.to_string());
<a href=#140 id=140 data-nosnippet>140</a> <span class="comment">// Project and task
<a href=#141 id=141 data-nosnippet>141</a> </span><span class="kw">let </span>project_task_part = parts[<span class="number">1</span>];
<a href=#142 id=142 data-nosnippet>142</a> <span class="comment">// Find the first '/' that starts the temporal segment and path
<a href=#143 id=143 data-nosnippet>143</a> </span><span class="kw">let </span>slash_idx = project_task_part
<a href=#144 id=144 data-nosnippet>144</a> .find(<span class="string">'/'</span>)
<a href=#145 id=145 data-nosnippet>145</a> .ok_or(<span class="string">"Missing '/' before temporal segment and path"</span>)<span class="question-mark">?</span>;
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">let </span>(proj_task, after_slash) = project_task_part.split_at(slash_idx);
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">let </span><span class="kw-2">mut </span>proj_task_iter = proj_task.splitn(<span class="number">2</span>, <span class="string">':'</span>);
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">let </span>project = proj_task_iter.next().ok_or(<span class="string">"Missing project"</span>)<span class="question-mark">?</span>.to_string();
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">let </span>task = proj_task_iter.next().ok_or(<span class="string">"Missing task"</span>)<span class="question-mark">?</span>.to_string();
<a href=#150 id=150 data-nosnippet>150</a> <span class="comment">// after_slash starts with '/', remove it
<a href=#151 id=151 data-nosnippet>151</a> </span><span class="kw">let </span>after = <span class="kw-2">&amp;</span>after_slash[<span class="number">1</span>..];
<a href=#152 id=152 data-nosnippet>152</a> <span class="comment">// Temporal segment is up to the next '/' if present
<a href=#153 id=153 data-nosnippet>153</a> </span><span class="kw">let </span>temporal_end = after
<a href=#154 id=154 data-nosnippet>154</a> .find(<span class="string">'/'</span>)
<a href=#155 id=155 data-nosnippet>155</a> .ok_or(<span class="string">"Missing '/' after temporal segment"</span>)<span class="question-mark">?</span>;
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">let </span>temporal_str = <span class="kw-2">&amp;</span>after[..temporal_end];
<a href=#157 id=157 data-nosnippet>157</a> <span class="kw">let </span>temporal = TemporalAxis::from_str(temporal_str)<span class="question-mark">?</span>;
<a href=#158 id=158 data-nosnippet>158</a> <span class="comment">// The rest is the resource path
<a href=#159 id=159 data-nosnippet>159</a> </span><span class="kw">let </span>path = after[temporal_end + <span class="number">1</span>..].to_string();
<a href=#160 id=160 data-nosnippet>160</a> <span class="prelude-val">Ok</span>(UCXLAddress {
<a href=#161 id=161 data-nosnippet>161</a> agent,
<a href=#162 id=162 data-nosnippet>162</a> role,
<a href=#163 id=163 data-nosnippet>163</a> project,
<a href=#164 id=164 data-nosnippet>164</a> task,
<a href=#165 id=165 data-nosnippet>165</a> temporal,
<a href=#166 id=166 data-nosnippet>166</a> path,
<a href=#167 id=167 data-nosnippet>167</a> })
<a href=#168 id=168 data-nosnippet>168</a> }
<a href=#169 id=169 data-nosnippet>169</a>}
<a href=#170 id=170 data-nosnippet>170</a>
<a href=#171 id=171 data-nosnippet>171</a><span class="kw">impl </span>fmt::Display <span class="kw">for </span>UCXLAddress {
<a href=#172 id=172 data-nosnippet>172</a> <span class="doccomment">/// Serialises the address back to its canonical string form.
<a href=#173 id=173 data-nosnippet>173</a> ///
<a href=#174 id=174 data-nosnippet>174</a> /// **What**: Constructs a `ucxl://` URI including optional role and path.
<a href=#175 id=175 data-nosnippet>175</a> ///
<a href=#176 id=176 data-nosnippet>176</a> /// **How**: Conditionally inserts the role component, then formats the
<a href=#177 id=177 data-nosnippet>177</a> /// project, task, temporal token and optional path using standard `write!`
<a href=#178 id=178 data-nosnippet>178</a> /// semantics.
<a href=#179 id=179 data-nosnippet>179</a> ///
<a href=#180 id=180 data-nosnippet>180</a> /// **Why**: Needed when emitting addresses (e.g., logging events or
<a href=#181 id=181 data-nosnippet>181</a> /// generating links) so that external tools can consume them.
<a href=#182 id=182 data-nosnippet>182</a> </span><span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; fmt::Result {
<a href=#183 id=183 data-nosnippet>183</a> <span class="kw">let </span>role_part = <span class="kw">if let </span><span class="prelude-val">Some</span>(r) = <span class="kw-2">&amp;</span><span class="self">self</span>.role {
<a href=#184 id=184 data-nosnippet>184</a> <span class="macro">format!</span>(<span class="string">":{}"</span>, r)
<a href=#185 id=185 data-nosnippet>185</a> } <span class="kw">else </span>{
<a href=#186 id=186 data-nosnippet>186</a> <span class="string">""</span>.to_string()
<a href=#187 id=187 data-nosnippet>187</a> };
<a href=#188 id=188 data-nosnippet>188</a> <span class="macro">write!</span>(
<a href=#189 id=189 data-nosnippet>189</a> f,
<a href=#190 id=190 data-nosnippet>190</a> <span class="string">"ucxl://{}{}@{}:{}/{}{}"</span>,
<a href=#191 id=191 data-nosnippet>191</a> <span class="self">self</span>.agent,
<a href=#192 id=192 data-nosnippet>192</a> role_part,
<a href=#193 id=193 data-nosnippet>193</a> <span class="self">self</span>.project,
<a href=#194 id=194 data-nosnippet>194</a> <span class="self">self</span>.task,
<a href=#195 id=195 data-nosnippet>195</a> <span class="self">self</span>.temporal,
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">if </span><span class="self">self</span>.path.is_empty() {
<a href=#197 id=197 data-nosnippet>197</a> <span class="string">""</span>.to_string()
<a href=#198 id=198 data-nosnippet>198</a> } <span class="kw">else </span>{
<a href=#199 id=199 data-nosnippet>199</a> <span class="macro">format!</span>(<span class="string">"/{}"</span>, <span class="self">self</span>.path)
<a href=#200 id=200 data-nosnippet>200</a> }
<a href=#201 id=201 data-nosnippet>201</a> )
<a href=#202 id=202 data-nosnippet>202</a> }
<a href=#203 id=203 data-nosnippet>203</a>}
<a href=#204 id=204 data-nosnippet>204</a>
<a href=#205 id=205 data-nosnippet>205</a><span class="doccomment">/// Trait defining a simple keyvalue metadata store.
<a href=#206 id=206 data-nosnippet>206</a>///
<a href=#207 id=207 data-nosnippet>207</a>/// **What**: Provides read, write and removal operations for associating a
<a href=#208 id=208 data-nosnippet>208</a>/// string of metadata with a filesystem path.
<a href=#209 id=209 data-nosnippet>209</a>///
<a href=#210 id=210 data-nosnippet>210</a>/// **How**: The trait abstracts over concrete storage implementations
<a href=#211 id=211 data-nosnippet>211</a>/// currently an inmemory `HashMap` allowing callers to depend on the trait
<a href=#212 id=212 data-nosnippet>212</a>/// rather than a specific type.
<a href=#213 id=213 data-nosnippet>213</a>///
<a href=#214 id=214 data-nosnippet>214</a>/// **Why**: CHORUS needs a lightweight way to attach auxiliary information to
<a href=#215 id=215 data-nosnippet>215</a>/// files without persisting to a database; the trait makes it easy to swap in a
<a href=#216 id=216 data-nosnippet>216</a>/// persistent backend later if required.
<a href=#217 id=217 data-nosnippet>217</a></span><span class="kw">pub trait </span>MetadataStore {
<a href=#218 id=218 data-nosnippet>218</a> <span class="doccomment">/// Retrieves the metadata for `path` if it exists.
<a href=#219 id=219 data-nosnippet>219</a> </span><span class="kw">fn </span>get(<span class="kw-2">&amp;</span><span class="self">self</span>, path: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>String&gt;;
<a href=#220 id=220 data-nosnippet>220</a> <span class="doccomment">/// Stores `metadata` for `path`, overwriting any existing value.
<a href=#221 id=221 data-nosnippet>221</a> </span><span class="kw">fn </span>set(<span class="kw-2">&amp;mut </span><span class="self">self</span>, path: <span class="kw-2">&amp;</span>str, metadata: String);
<a href=#222 id=222 data-nosnippet>222</a> <span class="doccomment">/// Removes the metadata entry for `path`, returning the old value if any.
<a href=#223 id=223 data-nosnippet>223</a> </span><span class="kw">fn </span>remove(<span class="kw-2">&amp;mut </span><span class="self">self</span>, path: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;String&gt; {
<a href=#224 id=224 data-nosnippet>224</a> <span class="prelude-val">None
<a href=#225 id=225 data-nosnippet>225</a> </span>}
<a href=#226 id=226 data-nosnippet>226</a>}
<a href=#227 id=227 data-nosnippet>227</a>
<a href=#228 id=228 data-nosnippet>228</a><span class="doccomment">/// Inmemory implementation of `MetadataStore` backed by a `HashMap`.
<a href=#229 id=229 data-nosnippet>229</a>///
<a href=#230 id=230 data-nosnippet>230</a>/// **What**: Holds metadata in a hash map where the key is the file path.
<a href=#231 id=231 data-nosnippet>231</a>///
<a href=#232 id=232 data-nosnippet>232</a>/// **How**: Provides a `new` constructor and implements the `MetadataStore`
<a href=#233 id=233 data-nosnippet>233</a>/// trait methods by delegating to the underlying map.
<a href=#234 id=234 data-nosnippet>234</a>///
<a href=#235 id=235 data-nosnippet>235</a>/// **Why**: Offers a zerocost, dependencyfree store suitable for unit tests
<a href=#236 id=236 data-nosnippet>236</a>/// and simple scenarios. It can be replaced with a persistent store without
<a href=#237 id=237 data-nosnippet>237</a>/// changing callers.
<a href=#238 id=238 data-nosnippet>238</a></span><span class="kw">pub struct </span>InMemoryMetadataStore {
<a href=#239 id=239 data-nosnippet>239</a> map: HashMap&lt;String, String&gt;,
<a href=#240 id=240 data-nosnippet>240</a>}
<a href=#241 id=241 data-nosnippet>241</a>
<a href=#242 id=242 data-nosnippet>242</a><span class="kw">impl </span>InMemoryMetadataStore {
<a href=#243 id=243 data-nosnippet>243</a> <span class="doccomment">/// Creates a fresh, empty `InMemoryMetadataStore`.
<a href=#244 id=244 data-nosnippet>244</a> ///
<a href=#245 id=245 data-nosnippet>245</a> /// **What**: Returns a struct with an empty internal map.
<a href=#246 id=246 data-nosnippet>246</a> ///
<a href=#247 id=247 data-nosnippet>247</a> /// **How**: Calls `HashMap::new`.
<a href=#248 id=248 data-nosnippet>248</a> ///
<a href=#249 id=249 data-nosnippet>249</a> /// **Why**: Convenience constructor for callers.
<a href=#250 id=250 data-nosnippet>250</a> </span><span class="kw">pub fn </span>new() -&gt; <span class="self">Self </span>{
<a href=#251 id=251 data-nosnippet>251</a> InMemoryMetadataStore {
<a href=#252 id=252 data-nosnippet>252</a> map: HashMap::new(),
<a href=#253 id=253 data-nosnippet>253</a> }
<a href=#254 id=254 data-nosnippet>254</a> }
<a href=#255 id=255 data-nosnippet>255</a>}
<a href=#256 id=256 data-nosnippet>256</a>
<a href=#257 id=257 data-nosnippet>257</a><span class="kw">impl </span>MetadataStore <span class="kw">for </span>InMemoryMetadataStore {
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">fn </span>get(<span class="kw-2">&amp;</span><span class="self">self</span>, path: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>String&gt; {
<a href=#259 id=259 data-nosnippet>259</a> <span class="self">self</span>.map.get(path)
<a href=#260 id=260 data-nosnippet>260</a> }
<a href=#261 id=261 data-nosnippet>261</a> <span class="kw">fn </span>set(<span class="kw-2">&amp;mut </span><span class="self">self</span>, path: <span class="kw-2">&amp;</span>str, metadata: String) {
<a href=#262 id=262 data-nosnippet>262</a> <span class="self">self</span>.map.insert(path.to_string(), metadata);
<a href=#263 id=263 data-nosnippet>263</a> }
<a href=#264 id=264 data-nosnippet>264</a> <span class="kw">fn </span>remove(<span class="kw-2">&amp;mut </span><span class="self">self</span>, path: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;String&gt; {
<a href=#265 id=265 data-nosnippet>265</a> <span class="self">self</span>.map.remove(path)
<a href=#266 id=266 data-nosnippet>266</a> }
<a href=#267 id=267 data-nosnippet>267</a>}
<a href=#268 id=268 data-nosnippet>268</a>
<a href=#269 id=269 data-nosnippet>269</a><span class="attr">#[cfg(test)]
<a href=#270 id=270 data-nosnippet>270</a></span><span class="kw">mod </span>tests {
<a href=#271 id=271 data-nosnippet>271</a> <span class="kw">use super</span>::<span class="kw-2">*</span>;
<a href=#272 id=272 data-nosnippet>272</a>
<a href=#273 id=273 data-nosnippet>273</a> <span class="attr">#[test]
<a href=#274 id=274 data-nosnippet>274</a> </span><span class="kw">fn </span>test_temporal_from_str() {
<a href=#275 id=275 data-nosnippet>275</a> <span class="macro">assert_eq!</span>(TemporalAxis::from_str(<span class="string">"#"</span>).unwrap(), TemporalAxis::Present);
<a href=#276 id=276 data-nosnippet>276</a> <span class="macro">assert_eq!</span>(TemporalAxis::from_str(<span class="string">"~~"</span>).unwrap(), TemporalAxis::Past);
<a href=#277 id=277 data-nosnippet>277</a> <span class="macro">assert_eq!</span>(TemporalAxis::from_str(<span class="string">"^^"</span>).unwrap(), TemporalAxis::Future);
<a href=#278 id=278 data-nosnippet>278</a> }
<a href=#279 id=279 data-nosnippet>279</a>
<a href=#280 id=280 data-nosnippet>280</a> <span class="attr">#[test]
<a href=#281 id=281 data-nosnippet>281</a> </span><span class="kw">fn </span>test_ucxl_address_parsing() {
<a href=#282 id=282 data-nosnippet>282</a> <span class="kw">let </span>addr_str = <span class="string">"ucxl://alice:admin@myproj:task1/#/docs/readme.md"</span>;
<a href=#283 id=283 data-nosnippet>283</a> <span class="kw">let </span>addr = UCXLAddress::from_str(addr_str).unwrap();
<a href=#284 id=284 data-nosnippet>284</a> <span class="macro">assert_eq!</span>(addr.agent, <span class="string">"alice"</span>);
<a href=#285 id=285 data-nosnippet>285</a> <span class="macro">assert_eq!</span>(addr.role, <span class="prelude-val">Some</span>(<span class="string">"admin"</span>.to_string()));
<a href=#286 id=286 data-nosnippet>286</a> <span class="macro">assert_eq!</span>(addr.project, <span class="string">"myproj"</span>);
<a href=#287 id=287 data-nosnippet>287</a> <span class="macro">assert_eq!</span>(addr.task, <span class="string">"task1"</span>);
<a href=#288 id=288 data-nosnippet>288</a> <span class="macro">assert_eq!</span>(addr.temporal, TemporalAxis::Present);
<a href=#289 id=289 data-nosnippet>289</a> <span class="macro">assert_eq!</span>(addr.path, <span class="string">"docs/readme.md"</span>);
<a href=#290 id=290 data-nosnippet>290</a> <span class="macro">assert_eq!</span>(addr.to_string(), addr_str);
<a href=#291 id=291 data-nosnippet>291</a> }
<a href=#292 id=292 data-nosnippet>292</a>
<a href=#293 id=293 data-nosnippet>293</a> <span class="attr">#[test]
<a href=#294 id=294 data-nosnippet>294</a> </span><span class="kw">fn </span>test_metadata_store() {
<a href=#295 id=295 data-nosnippet>295</a> <span class="kw">let </span><span class="kw-2">mut </span>store = InMemoryMetadataStore::new();
<a href=#296 id=296 data-nosnippet>296</a> store.set(<span class="string">"/foo.txt"</span>, <span class="string">"meta"</span>.into());
<a href=#297 id=297 data-nosnippet>297</a> <span class="macro">assert_eq!</span>(store.get(<span class="string">"/foo.txt"</span>), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="string">"meta"</span>.to_string()));
<a href=#298 id=298 data-nosnippet>298</a> store.remove(<span class="string">"/foo.txt"</span>);
<a href=#299 id=299 data-nosnippet>299</a> <span class="macro">assert!</span>(store.get(<span class="string">"/foo.txt"</span>).is_none());
<a href=#300 id=300 data-nosnippet>300</a> }
<a href=#301 id=301 data-nosnippet>301</a>}</code></pre></div></section></main></body></html>

View File

@@ -0,0 +1,91 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `UCXL/src/watcher.rs`."><title>watcher.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-916cea96.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="ucxl" data-themes="" data-resource-suffix="" data-rustdoc-version="1.87.0 (17067e9ac 2025-05-09)" data-channel="1.87.0" data-search-js="search-e7298875.js" data-settings-js="settings-d72f25bb.js" ><script src="../../static.files/storage-82c7156e.js"></script><script defer src="../../static.files/src-script-63605ae7.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-fb8c74a8.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer"></div><main><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1><div class="sub-heading">ucxl/</div>watcher.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="doccomment">//! UCXL filesystem watcher.
<a href=#2 id=2 data-nosnippet>2</a>//!
<a href=#3 id=3 data-nosnippet>3</a>//! This module provides a thin wrapper around the `notify` crate to watch a
<a href=#4 id=4 data-nosnippet>4</a>//! directory (or "project") for filesystem events. When a change is detected,
<a href=#5 id=5 data-nosnippet>5</a>//! the watcher attempts to construct a corresponding `UCXLAddress` using a
<a href=#6 id=6 data-nosnippet>6</a>//! simple heuristic and logs the event. This is primarily used by CHORUS for
<a href=#7 id=7 data-nosnippet>7</a>//! reactive workflows such as automatically updating metadata when files are
<a href=#8 id=8 data-nosnippet>8</a>//! added, modified or removed.
<a href=#9 id=9 data-nosnippet>9</a>
<a href=#10 id=10 data-nosnippet>10</a></span><span class="kw">use </span>notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
<a href=#11 id=11 data-nosnippet>11</a><span class="kw">use </span>std::path::Path;
<a href=#12 id=12 data-nosnippet>12</a><span class="kw">use </span>std::sync::mpsc::channel;
<a href=#13 id=13 data-nosnippet>13</a><span class="kw">use </span><span class="kw">crate</span>::UCXLAddress;
<a href=#14 id=14 data-nosnippet>14</a><span class="kw">use </span>std::str::FromStr;
<a href=#15 id=15 data-nosnippet>15</a>
<a href=#16 id=16 data-nosnippet>16</a><span class="doccomment">/// Represents a watcher rooted at a specific base path.
<a href=#17 id=17 data-nosnippet>17</a>///
<a href=#18 id=18 data-nosnippet>18</a>/// **What**: Holds the absolute path that the watcher monitors.
<a href=#19 id=19 data-nosnippet>19</a>///
<a href=#20 id=20 data-nosnippet>20</a>/// **How**: The path is stored as a `PathBuf`. The watcher is created via the
<a href=#21 id=21 data-nosnippet>21</a>/// `new` constructor which accepts any type that can be referenced as a `Path`.
<a href=#22 id=22 data-nosnippet>22</a>/// The underlying `notify::RecommendedWatcher` is configured with the default
<a href=#23 id=23 data-nosnippet>23</a>/// `Config` and set to watch recursively.
<a href=#24 id=24 data-nosnippet>24</a>///
<a href=#25 id=25 data-nosnippet>25</a>/// **Why**: Encapsulating the watcher logic in a dedicated struct makes it easy
<a href=#26 id=26 data-nosnippet>26</a>/// to instantiate multiple independent watchers and keeps the public API tidy.
<a href=#27 id=27 data-nosnippet>27</a></span><span class="kw">pub struct </span>UCXLWatcher {
<a href=#28 id=28 data-nosnippet>28</a> base_path: std::path::PathBuf,
<a href=#29 id=29 data-nosnippet>29</a>}
<a href=#30 id=30 data-nosnippet>30</a>
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">impl </span>UCXLWatcher {
<a href=#32 id=32 data-nosnippet>32</a> <span class="doccomment">/// Creates a new `UCXLWatcher` for the given path.
<a href=#33 id=33 data-nosnippet>33</a> ///
<a href=#34 id=34 data-nosnippet>34</a> /// **What**: Accepts any generic `AsRef&lt;Path&gt;` so callers can pass a `&amp;str`,
<a href=#35 id=35 data-nosnippet>35</a> /// `Path`, or `PathBuf`.
<a href=#36 id=36 data-nosnippet>36</a> ///
<a href=#37 id=37 data-nosnippet>37</a> /// **How**: The provided path is converted to a `PathBuf` and stored.
<a href=#38 id=38 data-nosnippet>38</a> ///
<a href=#39 id=39 data-nosnippet>39</a> /// **Why**: Convenience constructor used throughout CHORUS when a watcher is
<a href=#40 id=40 data-nosnippet>40</a> /// needed for a project directory.
<a href=#41 id=41 data-nosnippet>41</a> </span><span class="kw">pub fn </span>new&lt;P: AsRef&lt;Path&gt;&gt;(path: P) -&gt; <span class="self">Self </span>{
<a href=#42 id=42 data-nosnippet>42</a> <span class="self">Self </span>{
<a href=#43 id=43 data-nosnippet>43</a> base_path: path.as_ref().to_path_buf(),
<a href=#44 id=44 data-nosnippet>44</a> }
<a href=#45 id=45 data-nosnippet>45</a> }
<a href=#46 id=46 data-nosnippet>46</a>
<a href=#47 id=47 data-nosnippet>47</a> <span class="doccomment">/// Starts the watch loop, blocking indefinitely while handling events.
<a href=#48 id=48 data-nosnippet>48</a> ///
<a href=#49 id=49 data-nosnippet>49</a> /// **What**: Sets up a channel, creates a `RecommendedWatcher`, and begins
<a href=#50 id=50 data-nosnippet>50</a> /// watching the `base_path` recursively. For each incoming event, it
<a href=#51 id=51 data-nosnippet>51</a> /// attempts to map the filesystem path to a UCXL address and prints a log.
<a href=#52 id=52 data-nosnippet>52</a> ///
<a href=#53 id=53 data-nosnippet>53</a> /// **How**: Uses the `notify` crate's event API. The heuristic address
<a href=#54 id=54 data-nosnippet>54</a> /// format is `ucxl://system:watcher@local:filesystem/#/&lt;relative_path&gt;`.
<a href=#55 id=55 data-nosnippet>55</a> /// It parses this string with `UCXLAddress::from_str` and logs the result.
<a href=#56 id=56 data-nosnippet>56</a> /// Errors from parsing are ignored (they simply aren't printed).
<a href=#57 id=57 data-nosnippet>57</a> ///
<a href=#58 id=58 data-nosnippet>58</a> /// **Why**: Provides a simple, observable bridge between raw filesystem
<a href=#59 id=59 data-nosnippet>59</a> /// changes and the UCXL addressing scheme, allowing other components to react
<a href=#60 id=60 data-nosnippet>60</a> /// to changes using a uniform identifier.
<a href=#61 id=61 data-nosnippet>61</a> </span><span class="kw">pub fn </span>watch_loop(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), Box&lt;<span class="kw">dyn </span>std::error::Error&gt;&gt; {
<a href=#62 id=62 data-nosnippet>62</a> <span class="kw">let </span>(tx, rx) = channel();
<a href=#63 id=63 data-nosnippet>63</a>
<a href=#64 id=64 data-nosnippet>64</a> <span class="kw">let </span><span class="kw-2">mut </span>watcher = RecommendedWatcher::new(tx, Config::default())<span class="question-mark">?</span>;
<a href=#65 id=65 data-nosnippet>65</a> watcher.watch(<span class="kw-2">&amp;</span><span class="self">self</span>.base_path, RecursiveMode::Recursive)<span class="question-mark">?</span>;
<a href=#66 id=66 data-nosnippet>66</a>
<a href=#67 id=67 data-nosnippet>67</a> <span class="macro">println!</span>(<span class="string">"UCXL Watcher started on {:?}"</span>, <span class="self">self</span>.base_path);
<a href=#68 id=68 data-nosnippet>68</a>
<a href=#69 id=69 data-nosnippet>69</a> <span class="kw">for </span>res <span class="kw">in </span>rx {
<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">match </span>res {
<a href=#71 id=71 data-nosnippet>71</a> <span class="prelude-val">Ok</span>(event) =&gt; {
<a href=#72 id=72 data-nosnippet>72</a> <span class="kw">for </span>path <span class="kw">in </span>event.paths {
<a href=#73 id=73 data-nosnippet>73</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(rel_path) = path.strip_prefix(<span class="kw-2">&amp;</span><span class="self">self</span>.base_path).ok() {
<a href=#74 id=74 data-nosnippet>74</a> <span class="kw">let </span>rel_str = rel_path.to_string_lossy();
<a href=#75 id=75 data-nosnippet>75</a> <span class="comment">// Heuristic address mapping: ucxl://system:watcher@local:filesystem/#/path
<a href=#76 id=76 data-nosnippet>76</a> </span><span class="kw">let </span>addr_str = <span class="macro">format!</span>(
<a href=#77 id=77 data-nosnippet>77</a> <span class="string">"ucxl://system:watcher@local:filesystem/#/{}"</span>,
<a href=#78 id=78 data-nosnippet>78</a> rel_str
<a href=#79 id=79 data-nosnippet>79</a> );
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">if let </span><span class="prelude-val">Ok</span>(addr) = UCXLAddress::from_str(<span class="kw-2">&amp;</span>addr_str) {
<a href=#81 id=81 data-nosnippet>81</a> <span class="macro">println!</span>(<span class="string">"[UCXL EVENT] {:?} -&gt; {}"</span>, event.kind, addr);
<a href=#82 id=82 data-nosnippet>82</a> }
<a href=#83 id=83 data-nosnippet>83</a> }
<a href=#84 id=84 data-nosnippet>84</a> }
<a href=#85 id=85 data-nosnippet>85</a> }
<a href=#86 id=86 data-nosnippet>86</a> <span class="prelude-val">Err</span>(e) =&gt; <span class="macro">println!</span>(<span class="string">"watch error: {:?}"</span>, e),
<a href=#87 id=87 data-nosnippet>87</a> }
<a href=#88 id=88 data-nosnippet>88</a> }
<a href=#89 id=89 data-nosnippet>89</a> <span class="prelude-val">Ok</span>(())
<a href=#90 id=90 data-nosnippet>90</a> }
<a href=#91 id=91 data-nosnippet>91</a>}</code></pre></div></section></main></body></html>

View File

@@ -0,0 +1,71 @@
# REUSE-IgnoreStart
These documentation pages include resources by third parties. This copyright
file applies only to those resources. The following third party resources are
included, and carry their own copyright notices and license terms:
* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2):
Copyright (c) 2014, Mozilla Foundation https://mozilla.org/
with Reserved Font Name Fira Sans.
Copyright (c) 2014, Telefonica S.A.
Licensed under the SIL Open Font License, Version 1.1.
See FiraSans-LICENSE.txt.
* rustdoc.css, main.js, and playpen.js:
Copyright 2015 The Rust Developers.
Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or
the MIT license (LICENSE-MIT.txt) at your option.
* normalize.css:
Copyright (c) Nicolas Gallagher and Jonathan Neal.
Licensed under the MIT license (see LICENSE-MIT.txt).
* Source Code Pro (SourceCodePro-Regular.ttf.woff2,
SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2):
Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/),
with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark
of Adobe Systems Incorporated in the United States and/or other countries.
Licensed under the SIL Open Font License, Version 1.1.
See SourceCodePro-LICENSE.txt.
* Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2,
SourceSerif4-It.ttf.woff2, SourceSerif4-Semibold.ttf.woff2):
Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name
'Source'. All Rights Reserved. Source is a trademark of Adobe in the United
States and/or other countries.
Licensed under the SIL Open Font License, Version 1.1.
See SourceSerif4-LICENSE.md.
* Nanum Barun Gothic Font (NanumBarunGothic.woff2)
Copyright 2010, NAVER Corporation (http://www.nhncorp.com)
with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic,
NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen,
Naver NanumPen, Naver NanumGothicEco, NanumGothicEco,
Naver NanumMyeongjoEco, NanumMyeongjoEco, Naver NanumGothicLight,
NanumGothicLight, NanumBarunGothic, Naver NanumBarunGothic.
https://hangeul.naver.com/2017/nanum
https://github.com/hiun/NanumBarunGothic
Licensed under the SIL Open Font License, Version 1.1.
See NanumBarunGothic-LICENSE.txt.
* Rust logos (rust-logo.svg, favicon.svg, favicon-32x32.png)
Copyright 2025 Rust Foundation.
Licensed under the Creative Commons Attribution license (CC-BY).
https://rustfoundation.org/policy/rust-trademark-policy/
This copyright file is intended to be distributed with rustdoc output.
# REUSE-IgnoreEnd

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,98 @@
// REUSE-IgnoreStart
Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
with Reserved Font Name < Fira >,
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
// REUSE-IgnoreEnd

Binary file not shown.

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,23 @@
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,103 @@
// REUSE-IgnoreStart
Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/),
with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic,
NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen,
Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco,
NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic,
Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
// REUSE-IgnoreEnd

View File

@@ -0,0 +1,97 @@
// REUSE-IgnoreStart
Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
// REUSE-IgnoreEnd

View File

@@ -0,0 +1,98 @@
<!-- REUSE-IgnoreStart -->
Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
Copyright 2014 - 2023 Adobe (http://www.adobe.com/), with Reserved Font Name Source. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
<!-- REUSE-IgnoreEnd -->

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;">
<defs>
<style type="text/css"><![CDATA[
#logo {
fill-rule: nonzero;
}
#logo-teeth {
stroke: #000000;
stroke-width: 0.92px;
}
@media (prefers-color-scheme: dark) {
#logo {
fill: #FFFFFF;
fill-rule: nonzero;
}
#logo-teeth {
fill: #FFFFFF;
stroke: #FFFFFF;
stroke-width: 0.92px;
}
}
]]></style>
</defs>
<path id="logo" d="M15.993,1.54c-7.972,0 -14.461,6.492 -14.461,14.462c0,7.969 6.492,14.461 14.461,14.461c7.97,0 14.462,-6.492 14.462,-14.461c0,-7.97 -6.492,-14.462 -14.462,-14.462Zm-0.021,1.285c0.511,0.013 0.924,0.439 0.924,0.951c0,0.522 -0.43,0.952 -0.952,0.952c-0.522,0 -0.951,-0.43 -0.951,-0.952c0,0 0,0 0,0c0,-0.522 0.429,-0.952 0.951,-0.952c0.01,0 0.019,0.001 0.028,0.001Zm2.178,1.566c3.379,0.633 6.313,2.723 8.016,5.709l-1.123,2.533c-0.193,0.438 0.006,0.952 0.44,1.147l2.16,0.958c0.067,0.675 0.076,1.355 0.025,2.031l-1.202,0c-0.12,0 -0.169,0.08 -0.169,0.196l0,0.551c0,1.297 -0.731,1.582 -1.373,1.652c-0.612,0.07 -1.288,-0.257 -1.374,-0.63c-0.361,-2.029 -0.961,-2.46 -1.909,-3.21c1.178,-0.746 2.401,-1.85 2.401,-3.325c0,-1.594 -1.092,-2.597 -1.835,-3.09c-1.046,-0.688 -2.203,-0.826 -2.515,-0.826l-12.421,0c1.717,-1.918 4.02,-3.218 6.55,-3.696l1.466,1.536c0.33,0.346 0.878,0.361 1.223,0.028l1.64,-1.564Zm-13.522,7.043c0.511,0.015 0.924,0.44 0.924,0.951c0,0.522 -0.43,0.952 -0.952,0.952c-0.522,0 -0.951,-0.43 -0.951,-0.952c0,0 0,0 0,0c0,-0.522 0.429,-0.951 0.951,-0.951c0.009,0 0.019,0 0.028,0Zm22.685,0.043c0.511,0.015 0.924,0.44 0.924,0.951c0,0.522 -0.43,0.952 -0.952,0.952c-0.522,0 -0.951,-0.43 -0.951,-0.952c0,0 0,0 0,0c0,-0.522 0.429,-0.952 0.951,-0.952c0.01,0 0.019,0 0.028,0.001Zm-20.892,0.153l1.658,0l0,7.477l-3.347,0c-0.414,-1.452 -0.542,-2.97 -0.38,-4.47l2.05,-0.912c0.438,-0.195 0.637,-0.706 0.441,-1.144l-0.422,-0.951Zm6.92,0.079l3.949,0c0.205,0 1.441,0.236 1.441,1.163c0,0.768 -0.948,1.043 -1.728,1.043l-3.665,0l0.003,-2.206Zm0,5.373l3.026,0c0.275,0 1.477,0.079 1.86,1.615c0.119,0.471 0.385,2.007 0.566,2.499c0.18,0.551 0.911,1.652 1.691,1.652l4.938,0c-0.331,0.444 -0.693,0.863 -1.083,1.255l-2.01,-0.432c-0.468,-0.101 -0.93,0.199 -1.031,0.667l-0.477,2.228c-3.104,1.406 -6.672,1.389 -9.762,-0.046l-0.478,-2.228c-0.101,-0.468 -0.56,-0.767 -1.028,-0.667l-1.967,0.423c-0.365,-0.377 -0.704,-0.778 -1.016,-1.2l9.567,0c0.107,0 0.181,-0.018 0.181,-0.119l0,-3.384c0,-0.097 -0.074,-0.119 -0.181,-0.119l-2.799,0l0.003,-2.144Zm-4.415,7.749c0.512,0.015 0.924,0.44 0.924,0.951c0,0.522 -0.429,0.952 -0.951,0.952c-0.522,0 -0.952,-0.43 -0.952,-0.952c0,0 0,0 0,0c0,-0.522 0.43,-0.952 0.952,-0.952c0.009,0 0.018,0.001 0.027,0.001Zm14.089,0.043c0.511,0.015 0.924,0.439 0.923,0.951c0,0.522 -0.429,0.952 -0.951,0.952c-0.522,0 -0.951,-0.43 -0.951,-0.952c0,0 0,0 0,0c0,-0.522 0.429,-0.952 0.951,-0.952c0.009,0 0.018,0 0.028,0.001Z"/><path id="logo-teeth" d="M29.647,16.002c0,7.49 -6.163,13.653 -13.654,13.653c-7.49,0 -13.654,-6.163 -13.654,-13.653c0,-7.491 6.164,-13.654 13.654,-13.654c7.491,0 13.654,6.163 13.654,13.654Zm-0.257,-1.319l2.13,1.319l-2.13,1.318l1.83,1.71l-2.344,0.878l1.463,2.035l-2.475,0.404l1.04,2.282l-2.506,-0.089l0.575,2.442l-2.441,-0.576l0.089,2.506l-2.283,-1.04l-0.403,2.475l-2.035,-1.462l-0.878,2.343l-1.71,-1.829l-1.319,2.129l-1.318,-2.129l-1.71,1.829l-0.878,-2.343l-2.035,1.462l-0.404,-2.475l-2.282,1.04l0.089,-2.506l-2.442,0.576l0.575,-2.442l-2.505,0.089l1.04,-2.282l-2.475,-0.404l1.462,-2.035l-2.343,-0.878l1.829,-1.71l-2.129,-1.318l2.129,-1.319l-1.829,-1.71l2.343,-0.878l-1.462,-2.035l2.475,-0.404l-1.04,-2.282l2.505,0.089l-0.575,-2.441l2.442,0.575l-0.089,-2.506l2.282,1.04l0.404,-2.475l2.035,1.463l0.878,-2.344l1.71,1.83l1.318,-2.13l1.319,2.13l1.71,-1.83l0.878,2.344l2.035,-1.463l0.403,2.475l2.283,-1.04l-0.089,2.506l2.441,-0.575l-0.575,2.441l2.506,-0.089l-1.04,2.282l2.475,0.404l-1.463,2.035l2.344,0.878l-1.83,1.71Z"/></svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type="button"],[type="reset"],[type="submit"],button{-webkit-appearance:button}[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,61 @@
<svg version="1.1" height="106" width="106" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="logo" transform="translate(53, 53)">
<path id="r" transform="translate(0.5, 0.5)" stroke="black" stroke-width="1" stroke-linejoin="round" d="
M -9,-15 H 4 C 12,-15 12,-7 4,-7 H -9 Z
M -40,22 H 0 V 11 H -9 V 3 H 1 C 12,3 6,22 15,22 H 40
V 3 H 34 V 5 C 34,13 25,12 24,7 C 23,2 19,-2 18,-2 C 33,-10 24,-26 12,-26 H -35
V -15 H -25 V 11 H -40 Z" />
<g id="gear" mask="url(#holes)">
<circle r="43" fill="none" stroke="black" stroke-width="9" />
<g id="cogs">
<polygon id="cog" stroke="black" stroke-width="3" stroke-linejoin="round" points="46,3 51,0 46,-3" />
<use xlink:href="#cog" transform="rotate(11.25)" />
<use xlink:href="#cog" transform="rotate(22.50)" />
<use xlink:href="#cog" transform="rotate(33.75)" />
<use xlink:href="#cog" transform="rotate(45.00)" />
<use xlink:href="#cog" transform="rotate(56.25)" />
<use xlink:href="#cog" transform="rotate(67.50)" />
<use xlink:href="#cog" transform="rotate(78.75)" />
<use xlink:href="#cog" transform="rotate(90.00)" />
<use xlink:href="#cog" transform="rotate(101.25)" />
<use xlink:href="#cog" transform="rotate(112.50)" />
<use xlink:href="#cog" transform="rotate(123.75)" />
<use xlink:href="#cog" transform="rotate(135.00)" />
<use xlink:href="#cog" transform="rotate(146.25)" />
<use xlink:href="#cog" transform="rotate(157.50)" />
<use xlink:href="#cog" transform="rotate(168.75)" />
<use xlink:href="#cog" transform="rotate(180.00)" />
<use xlink:href="#cog" transform="rotate(191.25)" />
<use xlink:href="#cog" transform="rotate(202.50)" />
<use xlink:href="#cog" transform="rotate(213.75)" />
<use xlink:href="#cog" transform="rotate(225.00)" />
<use xlink:href="#cog" transform="rotate(236.25)" />
<use xlink:href="#cog" transform="rotate(247.50)" />
<use xlink:href="#cog" transform="rotate(258.75)" />
<use xlink:href="#cog" transform="rotate(270.00)" />
<use xlink:href="#cog" transform="rotate(281.25)" />
<use xlink:href="#cog" transform="rotate(292.50)" />
<use xlink:href="#cog" transform="rotate(303.75)" />
<use xlink:href="#cog" transform="rotate(315.00)" />
<use xlink:href="#cog" transform="rotate(326.25)" />
<use xlink:href="#cog" transform="rotate(337.50)" />
<use xlink:href="#cog" transform="rotate(348.75)" />
</g>
<g id="mounts">
<polygon id="mount" stroke="black" stroke-width="6" stroke-linejoin="round" points="-7,-42 0,-35 7,-42" />
<use xlink:href="#mount" transform="rotate(72)" />
<use xlink:href="#mount" transform="rotate(144)" />
<use xlink:href="#mount" transform="rotate(216)" />
<use xlink:href="#mount" transform="rotate(288)" />
</g>
</g>
<mask id="holes">
<rect x="-60" y="-60" width="120" height="120" fill="white"/>
<circle id="hole" cy="-40" r="3" />
<use xlink:href="#hole" transform="rotate(72)" />
<use xlink:href="#hole" transform="rotate(144)" />
<use xlink:href="#hole" transform="rotate(216)" />
<use xlink:href="#hole" transform="rotate(288)" />
</mask>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
"use strict";(function(){const DEFAULT_MAX_LINES=5;const HIDDEN_MAX_LINES=10;function scrollToLoc(elt,loc,isHidden){const lines=elt.querySelectorAll("[data-nosnippet]");let scrollOffset;const maxLines=isHidden?HIDDEN_MAX_LINES:DEFAULT_MAX_LINES;if(loc[1]-loc[0]>maxLines){const line=Math.max(0,loc[0]-1);scrollOffset=lines[line].offsetTop}else{const halfHeight=elt.offsetHeight/2;const offsetTop=lines[loc[0]].offsetTop;const lastLine=lines[loc[1]];const offsetBot=lastLine.offsetTop+lastLine.offsetHeight;const offsetMid=(offsetTop+offsetBot)/2;scrollOffset=offsetMid-halfHeight}lines[0].parentElement.scrollTo(0,scrollOffset);elt.querySelector(".rust").scrollTo(0,scrollOffset)}function createScrapeButton(parent,className,content){const button=document.createElement("button");button.className=className;button.title=content;parent.insertBefore(button,parent.firstChild);return button}window.updateScrapedExample=(example,buttonHolder)=>{let locIndex=0;const highlights=Array.prototype.slice.call(example.querySelectorAll(".highlight"));const link=example.querySelector(".scraped-example-title a");let expandButton=null;if(!example.classList.contains("expanded")){expandButton=createScrapeButton(buttonHolder,"expand","Show all")}const isHidden=example.parentElement.classList.contains("more-scraped-examples");const locs=example.locs;if(locs.length>1){const next=createScrapeButton(buttonHolder,"next","Next usage");const prev=createScrapeButton(buttonHolder,"prev","Previous usage");const onChangeLoc=changeIndex=>{removeClass(highlights[locIndex],"focus");changeIndex();scrollToLoc(example,locs[locIndex][0],isHidden);addClass(highlights[locIndex],"focus");const url=locs[locIndex][1];const title=locs[locIndex][2];link.href=url;link.innerHTML=title};prev.addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex-1+locs.length)%locs.length})});next.addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex+1)%locs.length})})}if(expandButton){expandButton.addEventListener("click",()=>{if(hasClass(example,"expanded")){removeClass(example,"expanded");removeClass(expandButton,"collapse");expandButton.title="Show all";scrollToLoc(example,locs[0][0],isHidden)}else{addClass(example,"expanded");addClass(expandButton,"collapse");expandButton.title="Show single example"}})}};function setupLoc(example,isHidden){example.locs=JSON.parse(example.attributes.getNamedItem("data-locs").textContent);scrollToLoc(example,example.locs[0][0],isHidden)}const firstExamples=document.querySelectorAll(".scraped-example-list > .scraped-example");onEachLazy(firstExamples,el=>setupLoc(el,false));onEachLazy(document.querySelectorAll(".more-examples-toggle"),toggle=>{onEachLazy(toggle.querySelectorAll(".toggle-line, .hide-more"),button=>{button.addEventListener("click",()=>{toggle.open=false})});const moreExamples=toggle.querySelectorAll(".scraped-example");toggle.querySelector("summary").addEventListener("click",()=>{setTimeout(()=>{onEachLazy(moreExamples,el=>setupLoc(el,true))})},{once:true})})})()

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
"use strict";(function(){const isSettingsPage=window.location.pathname.endsWith("/settings.html");function changeSetting(settingName,value){if(settingName==="theme"){const useSystem=value==="system preference"?"true":"false";updateLocalStorage("use-system-theme",useSystem)}updateLocalStorage(settingName,value);switch(settingName){case"theme":case"preferred-dark-theme":case"preferred-light-theme":updateTheme();updateLightAndDark();break;case"line-numbers":if(value===true){window.rustdoc_add_line_numbers_to_examples()}else{window.rustdoc_remove_line_numbers_from_examples()}break;case"hide-sidebar":if(value===true){addClass(document.documentElement,"hide-sidebar")}else{removeClass(document.documentElement,"hide-sidebar")}break;case"hide-toc":if(value===true){addClass(document.documentElement,"hide-toc")}else{removeClass(document.documentElement,"hide-toc")}break;case"hide-modnav":if(value===true){addClass(document.documentElement,"hide-modnav")}else{removeClass(document.documentElement,"hide-modnav")}break;case"sans-serif-fonts":if(value===true){addClass(document.documentElement,"sans-serif")}else{removeClass(document.documentElement,"sans-serif")}break;case"word-wrap-source-code":if(value===true){addClass(document.documentElement,"word-wrap-source-code")}else{removeClass(document.documentElement,"word-wrap-source-code")}break}}function showLightAndDark(){removeClass(document.getElementById("preferred-light-theme"),"hidden");removeClass(document.getElementById("preferred-dark-theme"),"hidden")}function hideLightAndDark(){addClass(document.getElementById("preferred-light-theme"),"hidden");addClass(document.getElementById("preferred-dark-theme"),"hidden")}function updateLightAndDark(){const useSystem=getSettingValue("use-system-theme");if(useSystem==="true"||(useSystem===null&&getSettingValue("theme")===null)){showLightAndDark()}else{hideLightAndDark()}}function setEvents(settingsElement){updateLightAndDark();onEachLazy(settingsElement.querySelectorAll("input[type=\"checkbox\"]"),toggle=>{const settingId=toggle.id;const settingValue=getSettingValue(settingId);if(settingValue!==null){toggle.checked=settingValue==="true"}toggle.onchange=()=>{changeSetting(toggle.id,toggle.checked)}});onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"),elem=>{const settingId=elem.name;let settingValue=getSettingValue(settingId);if(settingId==="theme"){const useSystem=getSettingValue("use-system-theme");if(useSystem==="true"||settingValue===null){settingValue=useSystem==="false"?"light":"system preference"}}if(settingValue!==null&&settingValue!=="null"){elem.checked=settingValue===elem.value}elem.addEventListener("change",ev=>{changeSetting(ev.target.name,ev.target.value)})})}function buildSettingsPageSections(settings){let output="";for(const setting of settings){if(setting==="hr"){output+="<hr>";continue}const js_data_name=setting["js_name"];const setting_name=setting["name"];if(setting["options"]!==undefined){output+=`\
<div class="setting-line" id="${js_data_name}">
<div class="setting-radio-name">${setting_name}</div>
<div class="setting-radio-choices">`;onEach(setting["options"],option=>{const checked=option===setting["default"]?" checked":"";const full=`${js_data_name}-${option.replace(/ /g,"-")}`;output+=`\
<label for="${full}" class="setting-radio">
<input type="radio" name="${js_data_name}"
id="${full}" value="${option}"${checked}>
<span>${option}</span>
</label>`});output+=`\
</div>
</div>`}else{const checked=setting["default"]===true?" checked":"";output+=`\
<div class="setting-line">\
<label class="setting-check">\
<input type="checkbox" id="${js_data_name}"${checked}>\
<span>${setting_name}</span>\
</label>\
</div>`}}return output}function buildSettingsPage(){const theme_names=getVar("themes").split(",").filter(t=>t);theme_names.push("light","dark","ayu");const settings=[{"name":"Theme","js_name":"theme","default":"system preference","options":theme_names.concat("system preference"),},{"name":"Preferred light theme","js_name":"preferred-light-theme","default":"light","options":theme_names,},{"name":"Preferred dark theme","js_name":"preferred-dark-theme","default":"dark","options":theme_names,},{"name":"Auto-hide item contents for large items","js_name":"auto-hide-large-items","default":true,},{"name":"Auto-hide item methods' documentation","js_name":"auto-hide-method-docs","default":false,},{"name":"Auto-hide trait implementation documentation","js_name":"auto-hide-trait-implementations","default":false,},{"name":"Directly go to item in search if there is only one result","js_name":"go-to-only-result","default":false,},{"name":"Show line numbers on code examples","js_name":"line-numbers","default":false,},{"name":"Hide persistent navigation bar","js_name":"hide-sidebar","default":false,},{"name":"Hide table of contents","js_name":"hide-toc","default":false,},{"name":"Hide module navigation","js_name":"hide-modnav","default":false,},{"name":"Disable keyboard shortcuts","js_name":"disable-shortcuts","default":false,},{"name":"Use sans serif fonts","js_name":"sans-serif-fonts","default":false,},{"name":"Word wrap source code","js_name":"word-wrap-source-code","default":false,},];const elementKind=isSettingsPage?"section":"div";const innerHTML=`<div class="settings">${buildSettingsPageSections(settings)}</div>`;const el=document.createElement(elementKind);el.id="settings";if(!isSettingsPage){el.className="popover"}el.innerHTML=innerHTML;if(isSettingsPage){document.getElementById(MAIN_ID).appendChild(el)}else{el.setAttribute("tabindex","-1");getSettingsButton().appendChild(el)}return el}const settingsMenu=buildSettingsPage();function displaySettings(){settingsMenu.style.display="";onEachLazy(settingsMenu.querySelectorAll("input[type='checkbox']"),el=>{const val=getSettingValue(el.id);const checked=val==="true";if(checked!==el.checked&&val!==null){el.checked=checked}})}function settingsBlurHandler(event){if(!getHelpButton().contains(document.activeElement)&&!getHelpButton().contains(event.relatedTarget)&&!getSettingsButton().contains(document.activeElement)&&!getSettingsButton().contains(event.relatedTarget)){window.hidePopoverMenus()}}if(!isSettingsPage){const settingsButton=getSettingsButton();const settingsMenu=document.getElementById("settings");settingsButton.onclick=event=>{if(settingsMenu.contains(event.target)){return}event.preventDefault();const shouldDisplaySettings=settingsMenu.style.display==="none";window.hideAllModals();if(shouldDisplaySettings){displaySettings()}};settingsButton.onblur=settingsBlurHandler;settingsButton.querySelector("a").onblur=settingsBlurHandler;onEachLazy(settingsMenu.querySelectorAll("input"),el=>{el.onblur=settingsBlurHandler});settingsMenu.onblur=settingsBlurHandler}setTimeout(()=>{setEvents(settingsMenu);if(!isSettingsPage){displaySettings()}removeClass(getSettingsButton(),"rotate")},0)})()

View File

@@ -0,0 +1 @@
"use strict";(function(){const rootPath=getVar("root-path");const NAME_OFFSET=0;const DIRS_OFFSET=1;const FILES_OFFSET=2;const RUSTDOC_MOBILE_BREAKPOINT=700;function closeSidebarIfMobile(){if(window.innerWidth<RUSTDOC_MOBILE_BREAKPOINT){updateLocalStorage("source-sidebar-show","false")}}function createDirEntry(elem,parent,fullPath,hasFoundFile){const dirEntry=document.createElement("details");const summary=document.createElement("summary");dirEntry.className="dir-entry";fullPath+=elem[NAME_OFFSET]+"/";summary.innerText=elem[NAME_OFFSET];dirEntry.appendChild(summary);const folders=document.createElement("div");folders.className="folders";if(elem[DIRS_OFFSET]){for(const dir of elem[DIRS_OFFSET]){if(createDirEntry(dir,folders,fullPath,false)){dirEntry.open=true;hasFoundFile=true}}}dirEntry.appendChild(folders);const files=document.createElement("div");files.className="files";if(elem[FILES_OFFSET]){const w=window.location.href.split("#")[0];for(const file_text of elem[FILES_OFFSET]){const file=document.createElement("a");file.innerText=file_text;file.href=rootPath+"src/"+fullPath+file_text+".html";file.addEventListener("click",closeSidebarIfMobile);if(!hasFoundFile&&w===file.href){file.className="selected";dirEntry.open=true;hasFoundFile=true}files.appendChild(file)}}dirEntry.appendChild(files);parent.appendChild(dirEntry);return hasFoundFile}window.rustdocCloseSourceSidebar=()=>{removeClass(document.documentElement,"src-sidebar-expanded");updateLocalStorage("source-sidebar-show","false")};window.rustdocShowSourceSidebar=()=>{addClass(document.documentElement,"src-sidebar-expanded");updateLocalStorage("source-sidebar-show","true")};window.rustdocToggleSrcSidebar=()=>{if(document.documentElement.classList.contains("src-sidebar-expanded")){window.rustdocCloseSourceSidebar()}else{window.rustdocShowSourceSidebar()}};function createSrcSidebar(){const container=nonnull(document.querySelector("nav.sidebar"));const sidebar=document.createElement("div");sidebar.id="src-sidebar";let hasFoundFile=false;for(const[key,source]of srcIndex){source[NAME_OFFSET]=key;hasFoundFile=createDirEntry(source,sidebar,"",hasFoundFile)}container.appendChild(sidebar);const selected_elem=sidebar.getElementsByClassName("selected")[0];if(typeof selected_elem!=="undefined"){selected_elem.focus()}}function highlightSrcLines(){const match=window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);if(!match){return}let from=parseInt(match[1],10);let to=from;if(typeof match[2]!=="undefined"){to=parseInt(match[2],10)}if(to<from){const tmp=to;to=from;from=tmp}const from_s=""+from;let elem=document.getElementById(from_s);if(!elem){return}const x=document.getElementById(from_s);if(x){x.scrollIntoView()}onEachLazy(document.querySelectorAll("a[data-nosnippet]"),e=>{removeClass(e,"line-highlighted")});for(let i=from;i<=to;++i){elem=document.getElementById(""+i);if(!elem){break}addClass(elem,"line-highlighted")}}const handleSrcHighlight=(function(){let prev_line_id=0;const set_fragment=name=>{const x=window.scrollX,y=window.scrollY;if(browserSupportsHistoryApi()){history.replaceState(null,"","#"+name);highlightSrcLines()}else{location.replace("#"+name)}window.scrollTo(x,y)};return ev=>{let cur_line_id=parseInt(ev.target.id,10);if(isNaN(cur_line_id)||ev.ctrlKey||ev.altKey||ev.metaKey){return}ev.preventDefault();if(ev.shiftKey&&prev_line_id){if(prev_line_id>cur_line_id){const tmp=prev_line_id;prev_line_id=cur_line_id;cur_line_id=tmp}set_fragment(prev_line_id+"-"+cur_line_id)}else{prev_line_id=cur_line_id;set_fragment(""+cur_line_id)}}}());window.addEventListener("hashchange",highlightSrcLines);onEachLazy(document.querySelectorAll("a[data-nosnippet]"),el=>{el.addEventListener("click",handleSrcHighlight)});highlightSrcLines();window.createSrcSidebar=createSrcSidebar})()

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
(function() {
var implementors = Object.fromEntries([["chrs_bubble",[["impl <a class=\"trait\" href=\"https://doc.rust-lang.org/1.87.0/core/clone/trait.Clone.html\" title=\"trait core::clone::Clone\">Clone</a> for <a class=\"enum\" href=\"chrs_bubble/enum.ProvenanceEdge.html\" title=\"enum chrs_bubble::ProvenanceEdge\">ProvenanceEdge</a>"]]],["chrs_mail",[["impl <a class=\"trait\" href=\"https://doc.rust-lang.org/1.87.0/core/clone/trait.Clone.html\" title=\"trait core::clone::Clone\">Clone</a> for <a class=\"struct\" href=\"chrs_mail/struct.Message.html\" title=\"struct chrs_mail::Message\">Message</a>"]]],["chrs_slurp",[["impl <a class=\"trait\" href=\"https://doc.rust-lang.org/1.87.0/core/clone/trait.Clone.html\" title=\"trait core::clone::Clone\">Clone</a> for <a class=\"struct\" href=\"chrs_slurp/struct.DecisionRecord.html\" title=\"struct chrs_slurp::DecisionRecord\">DecisionRecord</a>"]]],["ucxl",[["impl <a class=\"trait\" href=\"https://doc.rust-lang.org/1.87.0/core/clone/trait.Clone.html\" title=\"trait core::clone::Clone\">Clone</a> for <a class=\"enum\" href=\"ucxl/enum.TemporalAxis.html\" title=\"enum ucxl::TemporalAxis\">TemporalAxis</a>"],["impl <a class=\"trait\" href=\"https://doc.rust-lang.org/1.87.0/core/clone/trait.Clone.html\" title=\"trait core::clone::Clone\">Clone</a> for <a class=\"struct\" href=\"ucxl/struct.UCXLAddress.html\" title=\"struct ucxl::UCXLAddress\">UCXLAddress</a>"]]]]);
if (window.register_implementors) {
window.register_implementors(implementors);
} else {
window.pending_implementors = implementors;
}
})()
//{"start":57,"fragment_lengths":[290,270,294,520]}

Some files were not shown because too many files have changed in this diff Show More