automerge/src/automerge/query/seek_op_with_patch.rs.html
2023-03-09 15:11:59 +00:00

585 lines
No EOL
32 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 `automerge/src/query/seek_op_with_patch.rs`."><meta name="keywords" content="rust, rustlang, rust-lang"><title>seek_op_with_patch.rs - source</title><link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/SourceSerif4-Regular-1f7d512b176f0f72.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/FiraSans-Regular-018c141bf0843ffd.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/FiraSans-Medium-8f9a781e4970d388.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/SourceSerif4-Bold-124a1ca42af929b6.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2"><link rel="stylesheet" href="../../../static.files/normalize-76eba96aa4d2e634.css"><link rel="stylesheet" href="../../../static.files/rustdoc-93196c7a1c3542a8.css" id="mainThemeStyle"><link rel="stylesheet" id="themeStyle" href="../../../static.files/light-4743e13df3dfe8c4.css"><link rel="stylesheet" disabled href="../../../static.files/dark-0e1b889528bd466b.css"><link rel="stylesheet" disabled href="../../../static.files/ayu-65289d5d067c7c66.css"><script id="default-settings" ></script><script src="../../../static.files/storage-d43fa987303ecbbb.js"></script><script defer src="../../../static.files/source-script-ea63cb6500f71309.js"></script><script defer src="../../../source-files.js"></script><script defer src="../../../static.files/main-3367e395607fafc1.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-13285aec31fa243e.css"></noscript><link rel="icon" href="https:///raw.githubusercontent.com/automerge/automerge-rs/main/img/favicon.ico"></head><body class="rustdoc source"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"></nav><main><nav class="sub"><a class="sub-logo-container" href="../../../automerge/index.html">
<img src="https://raw.githubusercontent.com/automerge/automerge-rs/main/img/brandmark.svg" alt="logo"></a><form class="search-form"><span></span><input class="search-input" name="search" aria-label="Run search in the documentation" autocomplete="off" spellcheck="false" placeholder="Click or press S to search, ? for more options…" type="search"><div id="help-button" title="help" tabindex="-1"><a href="../../../help.html">?</a></div><div id="settings-menu" tabindex="-1"><a href="../../../settings.html" title="settings"><img width="22" height="22" alt="Change settings" src="../../../static.files/wheel-5ec35bf9ca753509.svg"></a></div></form></nav><section id="main-content" class="content"><div class="example-wrap"><pre class="src-line-numbers"><a href="#1" id="1">1</a>
<a href="#2" id="2">2</a>
<a href="#3" id="3">3</a>
<a href="#4" id="4">4</a>
<a href="#5" id="5">5</a>
<a href="#6" id="6">6</a>
<a href="#7" id="7">7</a>
<a href="#8" id="8">8</a>
<a href="#9" id="9">9</a>
<a href="#10" id="10">10</a>
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
<a href="#14" id="14">14</a>
<a href="#15" id="15">15</a>
<a href="#16" id="16">16</a>
<a href="#17" id="17">17</a>
<a href="#18" id="18">18</a>
<a href="#19" id="19">19</a>
<a href="#20" id="20">20</a>
<a href="#21" id="21">21</a>
<a href="#22" id="22">22</a>
<a href="#23" id="23">23</a>
<a href="#24" id="24">24</a>
<a href="#25" id="25">25</a>
<a href="#26" id="26">26</a>
<a href="#27" id="27">27</a>
<a href="#28" id="28">28</a>
<a href="#29" id="29">29</a>
<a href="#30" id="30">30</a>
<a href="#31" id="31">31</a>
<a href="#32" id="32">32</a>
<a href="#33" id="33">33</a>
<a href="#34" id="34">34</a>
<a href="#35" id="35">35</a>
<a href="#36" id="36">36</a>
<a href="#37" id="37">37</a>
<a href="#38" id="38">38</a>
<a href="#39" id="39">39</a>
<a href="#40" id="40">40</a>
<a href="#41" id="41">41</a>
<a href="#42" id="42">42</a>
<a href="#43" id="43">43</a>
<a href="#44" id="44">44</a>
<a href="#45" id="45">45</a>
<a href="#46" id="46">46</a>
<a href="#47" id="47">47</a>
<a href="#48" id="48">48</a>
<a href="#49" id="49">49</a>
<a href="#50" id="50">50</a>
<a href="#51" id="51">51</a>
<a href="#52" id="52">52</a>
<a href="#53" id="53">53</a>
<a href="#54" id="54">54</a>
<a href="#55" id="55">55</a>
<a href="#56" id="56">56</a>
<a href="#57" id="57">57</a>
<a href="#58" id="58">58</a>
<a href="#59" id="59">59</a>
<a href="#60" id="60">60</a>
<a href="#61" id="61">61</a>
<a href="#62" id="62">62</a>
<a href="#63" id="63">63</a>
<a href="#64" id="64">64</a>
<a href="#65" id="65">65</a>
<a href="#66" id="66">66</a>
<a href="#67" id="67">67</a>
<a href="#68" id="68">68</a>
<a href="#69" id="69">69</a>
<a href="#70" id="70">70</a>
<a href="#71" id="71">71</a>
<a href="#72" id="72">72</a>
<a href="#73" id="73">73</a>
<a href="#74" id="74">74</a>
<a href="#75" id="75">75</a>
<a href="#76" id="76">76</a>
<a href="#77" id="77">77</a>
<a href="#78" id="78">78</a>
<a href="#79" id="79">79</a>
<a href="#80" id="80">80</a>
<a href="#81" id="81">81</a>
<a href="#82" id="82">82</a>
<a href="#83" id="83">83</a>
<a href="#84" id="84">84</a>
<a href="#85" id="85">85</a>
<a href="#86" id="86">86</a>
<a href="#87" id="87">87</a>
<a href="#88" id="88">88</a>
<a href="#89" id="89">89</a>
<a href="#90" id="90">90</a>
<a href="#91" id="91">91</a>
<a href="#92" id="92">92</a>
<a href="#93" id="93">93</a>
<a href="#94" id="94">94</a>
<a href="#95" id="95">95</a>
<a href="#96" id="96">96</a>
<a href="#97" id="97">97</a>
<a href="#98" id="98">98</a>
<a href="#99" id="99">99</a>
<a href="#100" id="100">100</a>
<a href="#101" id="101">101</a>
<a href="#102" id="102">102</a>
<a href="#103" id="103">103</a>
<a href="#104" id="104">104</a>
<a href="#105" id="105">105</a>
<a href="#106" id="106">106</a>
<a href="#107" id="107">107</a>
<a href="#108" id="108">108</a>
<a href="#109" id="109">109</a>
<a href="#110" id="110">110</a>
<a href="#111" id="111">111</a>
<a href="#112" id="112">112</a>
<a href="#113" id="113">113</a>
<a href="#114" id="114">114</a>
<a href="#115" id="115">115</a>
<a href="#116" id="116">116</a>
<a href="#117" id="117">117</a>
<a href="#118" id="118">118</a>
<a href="#119" id="119">119</a>
<a href="#120" id="120">120</a>
<a href="#121" id="121">121</a>
<a href="#122" id="122">122</a>
<a href="#123" id="123">123</a>
<a href="#124" id="124">124</a>
<a href="#125" id="125">125</a>
<a href="#126" id="126">126</a>
<a href="#127" id="127">127</a>
<a href="#128" id="128">128</a>
<a href="#129" id="129">129</a>
<a href="#130" id="130">130</a>
<a href="#131" id="131">131</a>
<a href="#132" id="132">132</a>
<a href="#133" id="133">133</a>
<a href="#134" id="134">134</a>
<a href="#135" id="135">135</a>
<a href="#136" id="136">136</a>
<a href="#137" id="137">137</a>
<a href="#138" id="138">138</a>
<a href="#139" id="139">139</a>
<a href="#140" id="140">140</a>
<a href="#141" id="141">141</a>
<a href="#142" id="142">142</a>
<a href="#143" id="143">143</a>
<a href="#144" id="144">144</a>
<a href="#145" id="145">145</a>
<a href="#146" id="146">146</a>
<a href="#147" id="147">147</a>
<a href="#148" id="148">148</a>
<a href="#149" id="149">149</a>
<a href="#150" id="150">150</a>
<a href="#151" id="151">151</a>
<a href="#152" id="152">152</a>
<a href="#153" id="153">153</a>
<a href="#154" id="154">154</a>
<a href="#155" id="155">155</a>
<a href="#156" id="156">156</a>
<a href="#157" id="157">157</a>
<a href="#158" id="158">158</a>
<a href="#159" id="159">159</a>
<a href="#160" id="160">160</a>
<a href="#161" id="161">161</a>
<a href="#162" id="162">162</a>
<a href="#163" id="163">163</a>
<a href="#164" id="164">164</a>
<a href="#165" id="165">165</a>
<a href="#166" id="166">166</a>
<a href="#167" id="167">167</a>
<a href="#168" id="168">168</a>
<a href="#169" id="169">169</a>
<a href="#170" id="170">170</a>
<a href="#171" id="171">171</a>
<a href="#172" id="172">172</a>
<a href="#173" id="173">173</a>
<a href="#174" id="174">174</a>
<a href="#175" id="175">175</a>
<a href="#176" id="176">176</a>
<a href="#177" id="177">177</a>
<a href="#178" id="178">178</a>
<a href="#179" id="179">179</a>
<a href="#180" id="180">180</a>
<a href="#181" id="181">181</a>
<a href="#182" id="182">182</a>
<a href="#183" id="183">183</a>
<a href="#184" id="184">184</a>
<a href="#185" id="185">185</a>
<a href="#186" id="186">186</a>
<a href="#187" id="187">187</a>
<a href="#188" id="188">188</a>
<a href="#189" id="189">189</a>
<a href="#190" id="190">190</a>
<a href="#191" id="191">191</a>
<a href="#192" id="192">192</a>
<a href="#193" id="193">193</a>
<a href="#194" id="194">194</a>
<a href="#195" id="195">195</a>
<a href="#196" id="196">196</a>
<a href="#197" id="197">197</a>
<a href="#198" id="198">198</a>
<a href="#199" id="199">199</a>
<a href="#200" id="200">200</a>
<a href="#201" id="201">201</a>
<a href="#202" id="202">202</a>
<a href="#203" id="203">203</a>
<a href="#204" id="204">204</a>
<a href="#205" id="205">205</a>
<a href="#206" id="206">206</a>
<a href="#207" id="207">207</a>
<a href="#208" id="208">208</a>
<a href="#209" id="209">209</a>
<a href="#210" id="210">210</a>
<a href="#211" id="211">211</a>
<a href="#212" id="212">212</a>
<a href="#213" id="213">213</a>
<a href="#214" id="214">214</a>
<a href="#215" id="215">215</a>
<a href="#216" id="216">216</a>
<a href="#217" id="217">217</a>
<a href="#218" id="218">218</a>
<a href="#219" id="219">219</a>
<a href="#220" id="220">220</a>
<a href="#221" id="221">221</a>
<a href="#222" id="222">222</a>
<a href="#223" id="223">223</a>
<a href="#224" id="224">224</a>
<a href="#225" id="225">225</a>
<a href="#226" id="226">226</a>
<a href="#227" id="227">227</a>
<a href="#228" id="228">228</a>
<a href="#229" id="229">229</a>
<a href="#230" id="230">230</a>
<a href="#231" id="231">231</a>
<a href="#232" id="232">232</a>
<a href="#233" id="233">233</a>
<a href="#234" id="234">234</a>
<a href="#235" id="235">235</a>
<a href="#236" id="236">236</a>
<a href="#237" id="237">237</a>
<a href="#238" id="238">238</a>
<a href="#239" id="239">239</a>
<a href="#240" id="240">240</a>
<a href="#241" id="241">241</a>
<a href="#242" id="242">242</a>
<a href="#243" id="243">243</a>
<a href="#244" id="244">244</a>
<a href="#245" id="245">245</a>
<a href="#246" id="246">246</a>
<a href="#247" id="247">247</a>
<a href="#248" id="248">248</a>
<a href="#249" id="249">249</a>
<a href="#250" id="250">250</a>
<a href="#251" id="251">251</a>
<a href="#252" id="252">252</a>
<a href="#253" id="253">253</a>
<a href="#254" id="254">254</a>
<a href="#255" id="255">255</a>
<a href="#256" id="256">256</a>
<a href="#257" id="257">257</a>
<a href="#258" id="258">258</a>
<a href="#259" id="259">259</a>
<a href="#260" id="260">260</a>
<a href="#261" id="261">261</a>
<a href="#262" id="262">262</a>
<a href="#263" id="263">263</a>
<a href="#264" id="264">264</a>
<a href="#265" id="265">265</a>
<a href="#266" id="266">266</a>
<a href="#267" id="267">267</a>
<a href="#268" id="268">268</a>
<a href="#269" id="269">269</a>
<a href="#270" id="270">270</a>
<a href="#271" id="271">271</a>
<a href="#272" id="272">272</a>
<a href="#273" id="273">273</a>
<a href="#274" id="274">274</a>
<a href="#275" id="275">275</a>
<a href="#276" id="276">276</a>
<a href="#277" id="277">277</a>
<a href="#278" id="278">278</a>
<a href="#279" id="279">279</a>
<a href="#280" id="280">280</a>
<a href="#281" id="281">281</a>
<a href="#282" id="282">282</a>
<a href="#283" id="283">283</a>
<a href="#284" id="284">284</a>
<a href="#285" id="285">285</a>
<a href="#286" id="286">286</a>
<a href="#287" id="287">287</a>
<a href="#288" id="288">288</a>
<a href="#289" id="289">289</a>
<a href="#290" id="290">290</a>
<a href="#291" id="291">291</a>
</pre><pre class="rust"><code><span class="kw">use </span><span class="kw">crate</span>::op_tree::{OpSetMetadata, OpTreeNode};
<span class="kw">use </span><span class="kw">crate</span>::query::{binary_search_by, QueryResult, TreeQuery};
<span class="kw">use </span><span class="kw">crate</span>::types::{Key, ListEncoding, Op, HEAD};
<span class="kw">use </span>std::cmp::Ordering;
<span class="kw">use </span>std::fmt::Debug;
<span class="attr">#[derive(Debug, Clone, PartialEq)]
</span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>SeekOpWithPatch&lt;<span class="lifetime">&#39;a</span>&gt; {
op: Op,
<span class="kw">pub</span>(<span class="kw">crate</span>) pos: usize,
<span class="kw">pub</span>(<span class="kw">crate</span>) succ: Vec&lt;usize&gt;,
found: bool,
encoding: ListEncoding,
<span class="kw">pub</span>(<span class="kw">crate</span>) seen: usize,
<span class="kw">pub</span>(<span class="kw">crate</span>) last_width: usize,
last_seen: <span class="prelude-ty">Option</span>&lt;Key&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) values: Vec&lt;<span class="kw-2">&amp;</span><span class="lifetime">&#39;a </span>Op&gt;,
<span class="kw">pub</span>(<span class="kw">crate</span>) had_value_before: bool,
}
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;a</span>&gt; SeekOpWithPatch&lt;<span class="lifetime">&#39;a</span>&gt; {
<span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(op: <span class="kw-2">&amp;</span>Op, encoding: ListEncoding) -&gt; <span class="self">Self </span>{
SeekOpWithPatch {
op: op.clone(),
succ: <span class="macro">vec!</span>[],
pos: <span class="number">0</span>,
found: <span class="bool-val">false</span>,
encoding,
seen: <span class="number">0</span>,
last_width: <span class="number">0</span>,
last_seen: <span class="prelude-val">None</span>,
values: <span class="macro">vec!</span>[],
had_value_before: <span class="bool-val">false</span>,
}
}
<span class="kw">fn </span>lesser_insert(<span class="kw-2">&amp;</span><span class="self">self</span>, op: <span class="kw-2">&amp;</span>Op, m: <span class="kw-2">&amp;</span>OpSetMetadata) -&gt; bool {
op.insert &amp;&amp; m.lamport_cmp(op.id, <span class="self">self</span>.op.id) == Ordering::Less
}
<span class="kw">fn </span>greater_opid(<span class="kw-2">&amp;</span><span class="self">self</span>, op: <span class="kw-2">&amp;</span>Op, m: <span class="kw-2">&amp;</span>OpSetMetadata) -&gt; bool {
m.lamport_cmp(op.id, <span class="self">self</span>.op.id) == Ordering::Greater
}
<span class="kw">fn </span>is_target_insert(<span class="kw-2">&amp;</span><span class="self">self</span>, op: <span class="kw-2">&amp;</span>Op) -&gt; bool {
op.insert &amp;&amp; op.elemid() == <span class="self">self</span>.op.key.elemid()
}
<span class="doccomment">/// Keeps track of the number of visible list elements we have seen. Increments `self.seen` if
/// operation `e` associates a visible value with a list element, and if we have not already
/// counted that list element (this ensures that if a list element has several values, i.e.
/// a conflict, then it is still only counted once).
</span><span class="kw">fn </span>count_visible(<span class="kw-2">&amp;mut </span><span class="self">self</span>, e: <span class="kw-2">&amp;</span>Op) {
<span class="kw">if </span>e.elemid() == <span class="self">self</span>.op.elemid() {
<span class="kw">return</span>;
}
<span class="kw">if </span>e.insert {
<span class="self">self</span>.last_seen = <span class="prelude-val">None
</span>}
<span class="kw">if </span>e.visible() &amp;&amp; <span class="self">self</span>.last_seen.is_none() {
<span class="self">self</span>.seen += e.width(<span class="self">self</span>.encoding);
<span class="self">self</span>.last_seen = <span class="prelude-val">Some</span>(e.elemid_or_key())
}
}
}
<span class="kw">impl</span>&lt;<span class="lifetime">&#39;a</span>&gt; TreeQuery&lt;<span class="lifetime">&#39;a</span>&gt; <span class="kw">for </span>SeekOpWithPatch&lt;<span class="lifetime">&#39;a</span>&gt; {
<span class="kw">fn </span>query_node_with_metadata(
<span class="kw-2">&amp;mut </span><span class="self">self</span>,
child: <span class="kw-2">&amp;</span><span class="lifetime">&#39;a </span>OpTreeNode,
m: <span class="kw-2">&amp;</span>OpSetMetadata,
ops: <span class="kw-2">&amp;</span>[Op],
) -&gt; QueryResult {
<span class="kw">if </span><span class="self">self</span>.found {
<span class="kw">return </span>QueryResult::Descend;
}
<span class="kw">match </span><span class="self">self</span>.op.key {
<span class="comment">// Special case for insertion at the head of the list (`e == HEAD` is only possible for
// an insertion operation). Skip over any list elements whose elemId is greater than
// the opId of the operation being inserted.
</span>Key::Seq(e) <span class="kw">if </span>e == HEAD =&gt; {
<span class="kw">while </span><span class="self">self</span>.pos &lt; child.len() {
<span class="kw">let </span>op = <span class="kw-2">&amp;</span>ops[child.get(<span class="self">self</span>.pos).unwrap()];
<span class="kw">if </span>op.insert &amp;&amp; m.lamport_cmp(op.id, <span class="self">self</span>.op.id) == Ordering::Less {
<span class="kw">break</span>;
}
<span class="self">self</span>.count_visible(op);
<span class="self">self</span>.pos += <span class="number">1</span>;
}
QueryResult::Finish
}
<span class="comment">// Updating a list: search for the tree node that contains the new operation&#39;s
// reference element (i.e. the element we&#39;re updating or inserting after)
</span>Key::Seq(e) =&gt; {
<span class="kw">if </span><span class="self">self</span>.found || child.index.ops.contains(<span class="kw-2">&amp;</span>e.<span class="number">0</span>) {
QueryResult::Descend
} <span class="kw">else </span>{
<span class="self">self</span>.pos += child.len();
<span class="comment">// When we skip over a subtree, we need to count the number of visible list
// elements we&#39;re skipping over. Each node stores the number of visible
// elements it contains. However, it could happen that a visible element is
// split across two tree nodes. To avoid double-counting in this situation, we
// subtract one if the last visible element also appears in this tree node.
</span><span class="kw">let </span><span class="kw-2">mut </span>num_vis = child.index.visible_len(<span class="self">self</span>.encoding);
<span class="kw">if </span>num_vis &gt; <span class="number">0 </span>{
<span class="comment">// FIXME: I think this is wrong: we should subtract one only if this
// subtree contains a *visible* (i.e. empty succs) operation for the list
// element with elemId `last_seen`; this will subtract one even if all
// values for this list element have been deleted in this subtree.
</span><span class="kw">if let </span><span class="prelude-val">Some</span>(last_seen) = <span class="self">self</span>.last_seen {
<span class="kw">if </span>child.index.has_visible(<span class="kw-2">&amp;</span>last_seen) {
num_vis -= <span class="number">1</span>;
}
}
<span class="self">self</span>.seen += num_vis;
<span class="comment">// FIXME: this is also wrong: `last_seen` needs to be the elemId of the
// last *visible* list element in this subtree, but I think this returns
// the last operation&#39;s elemId regardless of whether it&#39;s visible or not.
// This will lead to incorrect counting if `last_seen` is not visible: it&#39;s
// not counted towards `num_vis`, so we shouldn&#39;t be subtracting 1.
</span><span class="self">self</span>.last_seen = <span class="prelude-val">Some</span>(ops[child.last()].elemid_or_key());
}
QueryResult::Next
}
}
<span class="comment">// Updating a map: operations appear in sorted order by key
</span>Key::Map(<span class="kw">_</span>) =&gt; {
<span class="kw">let </span>start = binary_search_by(child, ops, |op| m.key_cmp(<span class="kw-2">&amp;</span>op.key, <span class="kw-2">&amp;</span><span class="self">self</span>.op.key));
<span class="self">self</span>.pos = start;
QueryResult::Skip(start)
}
}
}
<span class="comment">// Only called when operating on a sequence (list/text) object, since updates of a map are
// handled in `query_node_with_metadata`.
</span><span class="kw">fn </span>query_element_with_metadata(<span class="kw-2">&amp;mut </span><span class="self">self</span>, e: <span class="kw-2">&amp;</span><span class="lifetime">&#39;a </span>Op, m: <span class="kw-2">&amp;</span>OpSetMetadata) -&gt; QueryResult {
<span class="kw">match </span><span class="self">self</span>.op.key {
Key::Map(<span class="kw">_</span>) =&gt; {
<span class="kw">if </span>!<span class="self">self</span>.found {
<span class="comment">// Iterate over any existing operations for the same key; stop when we reach an
// operation with a different key
</span><span class="kw">if </span>e.key != <span class="self">self</span>.op.key {
<span class="kw">return </span>QueryResult::Finish;
}
<span class="comment">// Keep track of any ops we&#39;re overwriting and any conflicts on this key
</span><span class="kw">if </span><span class="self">self</span>.op.overwrites(e) {
<span class="comment">// when we encounter an increment op we also want to find the counter for
// it.
</span><span class="kw">if </span><span class="self">self</span>.op.is_inc() &amp;&amp; e.is_counter() &amp;&amp; e.visible() {
<span class="self">self</span>.values.push(e);
}
<span class="self">self</span>.succ.push(<span class="self">self</span>.pos);
<span class="self">self</span>.last_width = e.width(<span class="self">self</span>.encoding);
<span class="kw">if </span>e.visible() {
<span class="self">self</span>.had_value_before = <span class="bool-val">true</span>;
}
} <span class="kw">else if </span>e.visible() {
<span class="self">self</span>.values.push(e);
}
<span class="comment">// Ops for the same key should be in ascending order of opId, so we break when
// we reach an op with an opId greater than that of the new operation
</span><span class="kw">if </span>m.lamport_cmp(e.id, <span class="self">self</span>.op.id) == Ordering::Greater {
<span class="self">self</span>.found = <span class="bool-val">true</span>;
<span class="kw">return </span>QueryResult::Next;
}
<span class="self">self</span>.pos += <span class="number">1</span>;
} <span class="kw">else </span>{
<span class="comment">// For the purpose of reporting conflicts, we also need to take into account any
// ops for the same key that appear after the new operation
</span><span class="kw">if </span>e.key != <span class="self">self</span>.op.key {
<span class="kw">return </span>QueryResult::Finish;
}
<span class="comment">// No need to check if `self.op.overwrites(op)` because an operation&#39;s `preds`
// must always have lower Lamport timestamps than that op itself, and the ops
// here all have greater opIds than the new op
</span><span class="kw">if </span>e.visible() {
<span class="self">self</span>.values.push(e);
}
}
QueryResult::Next
}
Key::Seq(<span class="kw">_</span>) =&gt; {
<span class="kw">let </span>result = <span class="kw">if </span>!<span class="self">self</span>.found {
<span class="comment">// First search for the referenced list element (i.e. the element we&#39;re updating, or
// after which we&#39;re inserting)
</span><span class="kw">if </span><span class="self">self</span>.is_target_insert(e) {
<span class="self">self</span>.found = <span class="bool-val">true</span>;
<span class="kw">if </span><span class="self">self</span>.op.overwrites(e) {
<span class="comment">// when we encounter an increment op we also want to find the counter for
// it.
</span><span class="kw">if </span><span class="self">self</span>.op.is_inc() &amp;&amp; e.is_counter() &amp;&amp; e.visible() {
<span class="self">self</span>.values.push(e);
}
<span class="self">self</span>.succ.push(<span class="self">self</span>.pos);
<span class="self">self</span>.last_width = e.width(<span class="self">self</span>.encoding);
}
<span class="kw">if </span>e.visible() {
<span class="self">self</span>.had_value_before = <span class="bool-val">true</span>;
}
}
<span class="self">self</span>.pos += <span class="number">1</span>;
QueryResult::Next
} <span class="kw">else </span>{
<span class="comment">// Once we&#39;ve found the reference element, keep track of any ops that we&#39;re overwriting
</span><span class="kw">let </span>overwritten = <span class="self">self</span>.op.overwrites(e);
<span class="kw">if </span>overwritten {
<span class="comment">// when we encounter an increment op we also want to find the counter for
// it.
</span><span class="kw">if </span><span class="self">self</span>.op.is_inc() &amp;&amp; e.is_counter() &amp;&amp; e.visible() {
<span class="self">self</span>.values.push(e);
}
<span class="self">self</span>.succ.push(<span class="self">self</span>.pos);
<span class="self">self</span>.last_width = e.width(<span class="self">self</span>.encoding);
}
<span class="comment">// If the new op is an insertion, skip over any existing list elements whose elemId is
// greater than the ID of the new insertion
</span><span class="kw">if </span><span class="self">self</span>.op.insert {
<span class="kw">if </span><span class="self">self</span>.lesser_insert(e, m) {
<span class="comment">// Insert before the first existing list element whose elemId is less than that
// of the new insertion
</span>QueryResult::Finish
} <span class="kw">else </span>{
<span class="self">self</span>.pos += <span class="number">1</span>;
QueryResult::Next
}
} <span class="kw">else if </span>e.insert {
<span class="comment">// If the new op is an update of an existing list element, the first insertion op
// we encounter after the reference element indicates the end of the reference elem
</span>QueryResult::Finish
} <span class="kw">else </span>{
<span class="comment">// When updating an existing list element, keep track of any conflicts on this list
// element. We also need to remember if the list element had any visible elements
// prior to applying the new operation: if not, the new operation is resurrecting
// a deleted list element, so it looks like an insertion in the patch.
</span><span class="kw">if </span>e.visible() {
<span class="self">self</span>.had_value_before = <span class="bool-val">true</span>;
<span class="kw">if </span>!overwritten {
<span class="self">self</span>.values.push(e);
}
}
<span class="comment">// We now need to put the ops for the same list element into ascending order, so we
// skip over any ops whose ID is less than that of the new operation.
</span><span class="kw">if </span>!<span class="self">self</span>.greater_opid(e, m) {
<span class="self">self</span>.pos += <span class="number">1</span>;
}
QueryResult::Next
}
};
<span class="comment">// The patch needs to know the list index of each operation, so we count the number of
// visible list elements up to the insertion position of the new operation
</span><span class="kw">if </span>result == QueryResult::Next {
<span class="self">self</span>.count_visible(e);
}
result
}
}
}
}
<span class="attr">#[cfg(test)]
</span><span class="kw">mod </span>tests {
<span class="kw">use super</span>::{<span class="kw">super</span>::seek_op::tests::optree_with_only_internally_visible_ops, SeekOpWithPatch};
<span class="kw">use crate</span>::{
op_tree::B,
types::{ListEncoding, ObjId},
};
<span class="attr">#[test]
</span><span class="kw">fn </span>test_insert_on_internal_only_nodes() {
<span class="kw">let </span>(set, new_op) = optree_with_only_internally_visible_ops();
<span class="kw">let </span>q = SeekOpWithPatch::new(<span class="kw-2">&amp;</span>new_op, ListEncoding::List);
<span class="kw">let </span>q = set.search(<span class="kw-2">&amp;</span>ObjId::root(), q);
<span class="comment">// we&#39;ve inserted `B - 1` elements for &quot;a&quot;, so the index should be `B`
</span><span class="macro">assert_eq!</span>(q.pos, B);
}
}
</code></pre></div>
</section></main><div id="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="automerge" data-themes="" data-resource-suffix="" data-rustdoc-version="1.68.0 (2c8cc3432 2023-03-06)" data-search-js="search-98d53477a794af0b.js" data-settings-js="settings-c3c521c753752a1a.js" data-settings-css="settings-08ddfdda51b8ee2e.css" ></div></body></html>