﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-金庆的专栏</title><link>http://www.cppblog.com/jinq0123/</link><description /><language>zh-cn</language><lastBuildDate>Tue, 14 Apr 2026 08:20:08 GMT</lastBuildDate><pubDate>Tue, 14 Apr 2026 08:20:08 GMT</pubDate><ttl>60</ttl><item><title>Fix navmesh countour</title><link>http://www.cppblog.com/jinq0123/archive/2023/01/01/229602.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 01 Jan 2023 02:37:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2023/01/01/229602.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229602.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2023/01/01/229602.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229602.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229602.html</trackback:ping><description><![CDATA[<h1>Fix navmesh countour</h1><div></div><div>(Jin Qing's Column, Jan., 2023)</div><div></div><div>After changing some parameters of watershed region partition algorithm,</div><div>my test mesh generated an odd region shape, which caused a wrong contour.</div><div></div><div>Wrong contour:</div><div><img src="http://www.cppblog.com/images/cppblog_com/jinq0123/wrong_contour3.jpg" width="951" height="611" alt="" /></div><div>Wrong navmesh:</div><div><img src="http://www.cppblog.com/images/cppblog_com/jinq0123/contour_wrong.jpg" width="1830" height="1072" alt="" /></div><div>There are 2 regions, the big region with red contour forms a C shape,</div><div>which is closed at one point.</div><div>The error is caused by the closing point, which should be a vertex in the simplified contour</div><div>of the small blue region but not.</div><div></div><div>In simplifyContour(), the closing point is incorrectly regarded as the edge point between 2 regions,</div><div>and is skipped, but it is accurately a vertex among 3 regions and must be a contour vertex.</div><div></div><div>To fix the problem, each vertex of the raw contour should count the regions around the vertex.</div><div>If the regions count is 3 or 4, then it must be a contour vertex of the simplified contour.</div><div></div><div>Fixed contour:</div><div><img src="http://www.cppblog.com/images/cppblog_com/jinq0123/FixedContour.jpg" width="1484" height="1009" alt="" /></div><div>Code:</div><div>```</div><div><span style="color: #800000; font-family: Courier;">// Returns the regions count of the contour vertex's 4 cells.</span></div><div><span style="color: #800000; font-family: Courier;">// The contour vertex is the front-right of the current span.</span></div><div><span style="color: #800000; font-family: Courier;">// This vertex must be the simplified contour's vertex.</span></div><div><span style="color: #800000; font-family: Courier;">// The non-region(0) is count as a region.</span></div><div><span style="color: #800000; font-family: Courier;">//</span></div><div><span style="color: #800000; font-family: Courier;">// reg is 4 region IDs of 4 cells in clockwise order: 0-current, 1-dir, 2-diagonal, 3-dirp</span></div><div><span style="color: #800000; font-family: Courier;">//</span></div><div><span style="color: #800000; font-family: Courier;">// Diagonal cells are not connected, so these 4 cells have regions count 4,</span></div><div><span style="color: #800000; font-family: Courier;">//&nbsp; &nbsp;because region a and b are separated from each other:</span></div><div><span style="color: #800000; font-family: Courier;">//&nbsp; &nbsp;```</span></div><div><span style="color: #800000; font-family: Courier;">//&nbsp; &nbsp;a|b</span></div><div><span style="color: #800000; font-family: Courier;">//&nbsp; &nbsp;-+-</span></div><div><span style="color: #800000; font-family: Courier;">//&nbsp; &nbsp;b|a</span></div><div><span style="color: #800000; font-family: Courier;">// ```</span></div><div><span style="color: #800000; font-family: Courier;">size_t getRegionsCount(const rcRegionId reg[4])</span></div><div><span style="color: #800000; font-family: Courier;">{</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">size_t diffCount = 0;</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">for (size_t i = 0, j = 3; i &lt; 4; j = i++)</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">{</span></div><div><span style="white-space:pre">		</span><span style="color: #800000; font-family: Courier;">if (reg[i] != reg[j])</span></div><div><span style="white-space:pre">			</span><span style="color: #800000; font-family: Courier;">++diffCount;</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">}</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">assert(diffCount &lt;= 4);</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">assert(diffCount != 1);</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">if (0 == diffCount)</span></div><div><span style="white-space:pre">		</span><span style="color: #800000; font-family: Courier;">return 1;</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">return diffCount;</span></div><div><span style="color: #800000; font-family: Courier;">}</span></div><div></div><div><span style="color: #800000; font-family: Courier;">void testGetRegionsCount()</span></div><div><span style="color: #800000; font-family: Courier;">{</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">assert(1 == getRegionsCount4(1, 1, 1, 1));</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">assert(2 == getRegionsCount4(1, 0, 0, 0));</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">assert(2 == getRegionsCount4(1, 1, 0, 0));</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">assert(3 == getRegionsCount4(0, 1, 2, 0));</span></div><div></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">assert(4 == getRegionsCount4(0, 1, 2, 3));</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">assert(4 == getRegionsCount4(1, 0, 1, 0));</span></div><div><span style="white-space:pre">	</span><span style="color: #800000; font-family: Courier;">assert(4 == getRegionsCount4(1, 0, 2, 0));</span></div><div><span style="color: #800000;">}</span></div><div>```</div><div><br />test.obj:&nbsp;<a href="/Files/jinq0123/test.zip">/Files/jinq0123/test.zip</a></div><div><a></a></div><img src ="http://www.cppblog.com/jinq0123/aggbug/229602.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2023-01-01 10:37 <a href="http://www.cppblog.com/jinq0123/archive/2023/01/01/229602.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>How are dtLinks created in NavMesh</title><link>http://www.cppblog.com/jinq0123/archive/2022/11/18/229525.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 18 Nov 2022 02:03:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/11/18/229525.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229525.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/11/18/229525.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229525.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229525.html</trackback:ping><description><![CDATA[<h1 id="how-are-dtlinks-created-in-navmesh">How are dtLinks created in NavMesh</h1>
<p>(Jin Qing's Column, Nov., 2022)</p>
<h2 id="dtlink"><code>dtLink</code></h2>
<p><code>dtLink</code> defines a link between 2 polygons.
It is an internal data structure.</p>
<p>A <code>dtLink</code> is owned by its source polygon.</p>
<h3 id="how-link-is-used">How link is used</h3>
<p>The links are used in <code>findPath()</code>, to search
all the neighbor polygons, from the current best polygon.</p>
<h3 id="fields-of-dtlink">fields of <code>dtLink</code></h3>
<p><code>dtLink</code> has 2 required fields:</p>
<ul>
<li>neighbor: the neighbor polygon reference that is linked to.</li>
<li>edge: index of the polygon edge that owns this link.
It is used in getPortalPoints() and raycast().</li>
</ul>
<p>If the link is a boundary link, which links to other tile, then it has more fields:</p>
<ul>
<li>side: defines on which side the link is. 8 sides.
It is used in findPath() and raycast().</li>
<li>bmin: defines the minimum sub-edge area.</li>
<li>bmax: defines the maximum sub-edge area.
bmin and bmax are used in portal finding.</li>
</ul>
<h2 id="how-are-links-created">How are links created</h2>
<p>Links are not saved to navmesh file. They are created on navmesh loading in <code>addTile()</code>.</p>
<p><code>dtNavMesh::addTile()</code> add a tile to the navmesh. A tile is a square block of the map.</p>
<p>The main job of <code>dtNavMesh::addTile()</code> is to create links inside this tile and between this tile and other tiles.
Actually a block indexed by (x, y) of constant size has many layers for multi-floor map.
A <code>dtMeshTile</code> is actually a layer with an index of (x, y, layer).</p>
<p>5 steps to create all links:</p>
<h3 id="1-connect-internal-links">1. Connect internal links</h3>
<p><code>connectIntLinks()</code> iterates all the polygons in the tile and create links for them
by the help of neighbors information of the polygons.</p>
<h3 id="2-base-off-mesh-connections">2. Base off-mesh connections</h3>
<p><code>baseOffMeshLinks()</code> bases off-mesh connections to their starting polygons and connect connections inside the tile.</p>
<p>Off-mesh connection is between 2 points which are inside a tile or between 2 adjacent tiles.</p>
<p>For each off-mesh connection, there creates a specific polygon consisting of 2 vertices.
See <code>DT_POLYTYPE_OFFMESH_CONNECTION</code>.</p>
<p><code>baseOffMeshLinks()</code> creates 2 links for each off-mesh connection:</p>
<ul>
<li>From the off-mesh connection polygon to the source polygon</li>
<li>From the source polygon to the off-mesh connection polygon</li>
</ul>
<p>The destinaton polygon of the off-mesh connection is skipped here.</p>
<h3 id="3-connect-external-off-mesn-links-within-this-tile">3. Connect external off-mesn links within this tile</h3>
<p><code>connectExtOffMeshLinks()</code> with the source and target tile be this tile.</p>
<p><code>connectExtOffMeshLinks()</code> searches off-mesh connections that are from this tile to the target tile
by checking the side direction of the connection.</p>
<p>It creates a link from off-mesh connection polygon to the target tile.
For bidirectional connection, it also creates a link from the target polygon to the off-mesh connection polygon.</p>
<p>So for each off-mesh connection of this tile, 3 or 4 links are created by baseOffMeshLinks() and connectExtOffMeshLinks(),
one on the source polygon, one on the destination polygon and 1/2 on the off-mesh connection polygon.</p>
<h3 id="4-connect-with-layers-in-current-tile">4. Connect with layers in current tile</h3>
<p>For each layer other than this layer in this tile:</p>
<ul>
<li>Create links from this layer to other layer</li>
<li>Create links from other layer to this layer</li>
<li>Create links of the off-mesh connection from this layer to other layer</li>
<li>Create links of the off-mesh connection from other layer to this layer</li>
</ul>
<h3 id="5-connect-with-neighbour-tiles">5. Connect with neighbour tiles</h3>
<p>Check 9 neighbor tiles' layers, and create links just like previous step:</p>
<ul>
<li>Create links from this layer to neighnor layer</li>
<li>Create links from neighnor layer to this layer</li>
<li>Create links of the off-mesh connection from this layer to neighnor layer</li>
<li>Create links of the off-mesh connection from neighnor layer to this layer</li>
</ul>
<p>By now, for every off-mesh connection of all the loaded tiles, 3/4 links are created.</p>
<h2 id="reference">Reference</h2>
<ul>
<li>https://blog.csdn.net/icebergliu1234/article/details/80322392</li>
</ul>
<img src ="http://www.cppblog.com/jinq0123/aggbug/229525.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-11-18 10:03 <a href="http://www.cppblog.com/jinq0123/archive/2022/11/18/229525.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ parameter passing rules</title><link>http://www.cppblog.com/jinq0123/archive/2022/10/29/229466.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sat, 29 Oct 2022 03:01:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/10/29/229466.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229466.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/10/29/229466.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229466.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229466.html</trackback:ping><description><![CDATA[<h1>C++ parameter passing rules</h1><p style="box-sizing: border-box; outline: 0px; margin: 0px 0px 16px; padding: 0px; font-size: 16px; color: #4d4d4d; line-height: 26px; overflow: auto hidden; overflow-wrap: break-word; font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-variant-ligatures: no-common-ligatures; background-color: #ffffff;">From: https://www.modernescpp.com/index.php/c-core-guidelines-how-to-pass-function-parameters</p><p style="box-sizing: border-box; outline: 0px; margin: 0px 0px 16px; padding: 0px; font-size: 16px; color: #4d4d4d; line-height: 26px; overflow: auto hidden; overflow-wrap: break-word; font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-variant-ligatures: no-common-ligatures; background-color: #ffffff;">Parameter passing expression rules:</p><ul style="box-sizing: border-box; outline: 0px; margin: 0px 0px 24px; padding: 0px; list-style-position: initial; list-style-image: initial; font-size: 16px; overflow: auto hidden; overflow-wrap: break-word; color: rgba(0, 0, 0, 0.75); font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-variant-ligatures: no-common-ligatures; background-color: #ffffff;"><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.15: Prefer simple and conventional ways of passing information</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.16: For &#8220;in&#8221; parameters, pass cheaply-copied types by value and others by reference to const</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.17: For &#8220;in-out&#8221; parameters, pass by reference to non-const</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.18: For &#8220;consume&#8221; parameters, pass by X&amp;&amp; and std::move the parameter</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.19: For &#8220;forward&#8221; parameters, pass by TP&amp;&amp; and only std::forward the parameter</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.20: For &#8220;out&#8221; output values, prefer return values to output parameters</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.21: To return multiple &#8220;out&#8221; values, prefer returning a tuple or struct</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.60: Prefer T* over T&amp; when &#8220;no argument&#8221; is a valid option</li></ul><img src ="http://www.cppblog.com/jinq0123/aggbug/229466.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-10-29 11:01 <a href="http://www.cppblog.com/jinq0123/archive/2022/10/29/229466.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Implementation of user data in cursive::Cursive</title><link>http://www.cppblog.com/jinq0123/archive/2022/10/02/229436.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 02 Oct 2022 08:38:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/10/02/229436.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229436.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/10/02/229436.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229436.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229436.html</trackback:ping><description><![CDATA[        <h1 id="implementation-of-user-data-in-cursivecursive">Implementation of user data in cursive::Cursive</h1>
<p>(Jin Qing's Column, Oct., 2022)</p>
<p>cursive::Cursive can store any user data:</p>
<pre><code class="language-Rust"><div><span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Cursive</span></span> {
    ...
    <span class="hljs-comment">// User-provided data.</span>
    user_data: <span class="hljs-built_in">Box</span>&lt;<span class="hljs-keyword">dyn</span> Any&gt;,
}
<span class="hljs-keyword">impl</span> Cursive {
    ...
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">set_user_data</span></span>&lt;T: Any&gt;(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, user_data: T) {
        <span class="hljs-keyword">self</span>.user_data = <span class="hljs-built_in">Box</span>::new(user_data);
    }
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">user_data</span></span>&lt;T: Any&gt;(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;&amp;<span class="hljs-keyword">mut</span> T&gt; {
        <span class="hljs-keyword">self</span>.user_data.downcast_mut()
    }
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">take_user_data</span></span>&lt;T: Any&gt;(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Option</span>&lt;T&gt; {
        ...
    }
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">with_user_data</span></span>&lt;F, T, R&gt;(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-keyword">self</span>, f: F) -&gt; <span class="hljs-built_in">Option</span>&lt;R&gt;
    <span class="hljs-keyword">where</span>
        F: <span class="hljs-built_in">FnOnce</span>(&amp;<span class="hljs-keyword">mut</span> T) -&gt; R,
        T: Any,
    {
        <span class="hljs-keyword">self</span>.user_data().map(f)
    }
</div></code></pre>
<p>Example:</p>
<pre><code class="language-Rust"><div><span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> siv = cursive_core::Cursive::new();
<span class="hljs-comment">// Start with a simple `Vec&lt;i32&gt;` as user data.</span>
siv.set_user_data(<span class="hljs-built_in">vec!</span>[<span class="hljs-number">1i32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]);
<span class="hljs-built_in">assert_eq!</span>(siv.user_data::&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">i32</span>&gt;&gt;(), <span class="hljs-literal">Some</span>(&amp;<span class="hljs-keyword">mut</span> <span class="hljs-built_in">vec!</span>[<span class="hljs-number">1i32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]));
<span class="hljs-comment">// Let&#x27;s mutate the data a bit.</span>
siv.with_user_data(|numbers: &amp;<span class="hljs-keyword">mut</span> <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">i32</span>&gt;| numbers.push(<span class="hljs-number">4</span>));
<span class="hljs-comment">// If mutable reference is not enough, we can take the data by value.</span>
<span class="hljs-keyword">let</span> data: <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">i32</span>&gt; = siv.take_user_data().unwrap();
<span class="hljs-built_in">assert_eq!</span>(data, <span class="hljs-built_in">vec!</span>[<span class="hljs-number">1i32</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>]);
<span class="hljs-comment">// At this point the user data was removed and is no longer available.</span>
<span class="hljs-built_in">assert_eq!</span>(siv.user_data::&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">i32</span>&gt;&gt;(), <span class="hljs-literal">None</span>);
</div></code></pre>
<img src ="http://www.cppblog.com/jinq0123/aggbug/229436.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-10-02 16:38 <a href="http://www.cppblog.com/jinq0123/archive/2022/10/02/229436.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Naming Conventions for Accessors</title><link>http://www.cppblog.com/jinq0123/archive/2022/09/22/229427.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 22 Sep 2022 08:02:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/09/22/229427.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229427.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/09/22/229427.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229427.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229427.html</trackback:ping><description><![CDATA[<h1>Naming Conventions for Accessors<br />
</h1>
<p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1rem; hyphens: auto;">from:&nbsp;<a href="http://cginternals.github.io/guidelines/articles/">C++ Programming Guidelines (cginternals.github.io)</a><br />
<br />
</p>
<p>
When naming accessors within classes, non-trivial getters and queries, i.e., those that perform calculations, you should prepended&nbsp;<code style="box-sizing: inherit; font-family: &quot;Source Code Pro&quot;, monospace; font-size: 14.4px; padding: 0.2rem 0.4rem; color: #186d94; background-color: #f7f7f9; border-radius: 0.25rem;">get</code>. All other getters have no prefix and setters have the&nbsp;<code style="box-sizing: inherit; font-family: &quot;Source Code Pro&quot;, monospace; font-size: 14.4px; padding: 0.2rem 0.4rem; color: #186d94; background-color: #f7f7f9; border-radius: 0.25rem;">set</code>&nbsp;prefix.<br />
<br />
</p><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all;"><span style="color: #0000ff;">class</span>&nbsp;Object<br />{<br /><span style="color: #0000FF; ">public</span>:<br />&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;radius()&nbsp;<span style="color: #0000FF; ">const</span>;<br />&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;setRadius(<span style="color: #0000FF; ">int</span>&nbsp;value);<br /><br />&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getPerimeter();<br /><br /><span style="color: #0000FF; ">private</span>:<br />&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;m_radius;<br />};<br /><br /><span style="color: #0000FF; ">int</span>&nbsp;Object::radius()&nbsp;<span style="color: #0000FF; ">const</span><br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;m_radius;<br />}<br /><br /><span style="color: #0000FF; ">void</span>&nbsp;Object::setRadius(<span style="color: #0000FF; ">int</span>&nbsp;value)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;m_radius&nbsp;=&nbsp;value;<br />}<br /><br /><span style="color: #0000FF; ">int</span>&nbsp;Object::getPerimeter()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;2&nbsp;*&nbsp;pi&nbsp;*&nbsp;m_radius;<br />}</div><img src ="http://www.cppblog.com/jinq0123/aggbug/229427.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-09-22 16:02 <a href="http://www.cppblog.com/jinq0123/archive/2022/09/22/229427.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rust sometimes needs manual type annotation</title><link>http://www.cppblog.com/jinq0123/archive/2022/04/29/229301.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 29 Apr 2022 02:14:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/04/29/229301.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229301.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/04/29/229301.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229301.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229301.html</trackback:ping><description><![CDATA[    <h1 id="rust-sometimes-needs-manual-type-annotation">Rust sometimes needs manual type annotation</h1>
    <p>(Jin Qing's Column, Apr., 2022)</p>
    <p>This code compiles error:</p>
    <pre>
      <code>trait MyCallback: FnMut(&amp;u32) -&gt; () { }
impl&lt;F: FnMut(&amp;u32) -&gt; ()&gt; MyCallback for F { }
fn process_data(mut f: impl MyCallback) -&gt; () {
    f(&amp;0)
}
fn process_data_2(mut f: impl FnMut(&amp;u32) -&gt; ()) -&gt; () {
    f(&amp;0)
}
fn main() {
    // Doesn't compile
    process_data(|_| ());
    // Compiles
    process_data_2(|_| ());
}
</code>
    </pre>
    <pre>
      <code>expected type `for&lt;'r&gt; FnMut&lt;(&amp;'r u32,)&gt;`
              found type `FnMut&lt;(&amp;u32,)&gt;`
</code>
    </pre>
    <p>Fix:</p>
    <pre>
      <code>    process_data(|_: &amp;_| ());
</code>
    </pre>
    <p>See: <a href="https://stackoverflow.com/questions/61671460/rust-type-mismatch-resolving-forr-with-closure-trait-alias-argument">https://stackoverflow.com/questions/61671460/rust-type-mismatch-resolving-forr-with-closure-trait-alias-argument</a></p>
    <p>Also see: <a href="https://github.com/rust-lang/rust/issues/58639">https://github.com/rust-lang/rust/issues/58639</a></p>
    <p>Sometimes, Rust needs a type annotation in closure.</p>
<img src ="http://www.cppblog.com/jinq0123/aggbug/229301.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-04-29 10:14 <a href="http://www.cppblog.com/jinq0123/archive/2022/04/29/229301.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fix recastnavigation contour error</title><link>http://www.cppblog.com/jinq0123/archive/2022/04/28/229299.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 28 Apr 2022 05:34:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/04/28/229299.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229299.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/04/28/229299.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229299.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229299.html</trackback:ping><description><![CDATA[<h1 id="fix-recastnavigation-contour-error">ix recastnavigation contour error</h1>
    <p>(Jin Qing's Column, Apr., 2022)</p>
    <p>Using navmesh generated by recastnavigation,
we found the agent will collide into the wall
when it is walking along the navmesh path.</p>
    <p>After some inspection, we found the reason is that at the collision position,
the position on the path is simply too close to the wall, which is less than the agent radius.</p>
    <p>If the agent radius is zero, the navmesh contour may inside the wall.</p>
    <p><img src="http://www.cppblog.com/images/cppblog_com/jinq0123/navmesh/Screenshot_20220428_112322.png" width="1801" height="1008" alt="" /></p>
    <p>Displaying the raw contour and contour,
we can see the raw contour which is jigsaw shaped is right,
but the simplied contour uses a straight line to replace the jigsaw edge,
and causes the error.</p>
    <p><img src="http://www.cppblog.com/images/cppblog_com/jinq0123/navmesh/Screenshot_20220428_110659.png" width="1801" height="1008" alt="" /><br /></p>
    <p>The parameter "Max Edge Error" controls how the contour is simplified,
which default is 1.3, which means a vertex can deviate from the final contour
in the range of 1.3 times of cell size.</p>
    <p>We hope the error is on only one side of the contour instead of on both sides.
In other words, the contour should within the raw contour.</p>
    <p>walkContour() finds a raw contour which is a polygon.
simplifyContour() simplifies the raw contour resulting a simpler polygon.</p>
    <p>The steps of simplifyContour():</p>
    <ol>
      <li>Find lower-left and upper-right vertices of the contour to form the initial simplified polygon.</li>
      <li>For each edge of the simplified polygon
<ol><li>For each point between 2 points of the edge
<ol><li>Find the point that is the most distant from the edge</li></ol></li><li>If the distance is larger than the max error, add the point to the simplified polygon</li></ol></li>
      <li>Split too long edges.</li>
    </ol>
    <p>We make these modifications:</p>
    <ul>
      <li>The distance is signed
<ul><li>If the point is outside the walkable area, just make sure it is less than the max error</li><li>If the point is inside the walkable area
<ul><li>Add it to the simplified polygon to make sure the final contour is within the raw area</li></ul></li></ul></li>
    </ul>
    <p>There are 2 kinds of contour:</p>
    <ul>
      <li>Outline of a walkable area</li>
      <li>Hole of a walkable area</li>
    </ul>
    <p>We should decide the kind of the contour before simplifyContour().
If the start cell (x, y) is in the raw contour polygon, then it is an outline not a hole contour.
Because (x, y) may be one of the vetex of the polygon, we use (x + 0.5, y + 0.5) instead,
which is the center of the cell.</p>
    <p>The result will be like this:<br /><br /><img src="http://www.cppblog.com/images/cppblog_com/jinq0123/navmesh/Screenshot_20220428_104943.png" width="1801" height="1008" alt="" /></p>
    <p><img src="http://www.cppblog.com/images/cppblog_com/jinq0123/navmesh/Screenshot_20220428_104833.png" width="1801" height="1008" alt="" /><br />Compare with the orignal contour:<br /><img src="http://www.cppblog.com/images/cppblog_com/jinq0123/navmesh/Screenshot_20220428_105131.png" width="1801" height="1008" alt="" /><br /></p><img src ="http://www.cppblog.com/jinq0123/aggbug/229299.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-04-28 13:34 <a href="http://www.cppblog.com/jinq0123/archive/2022/04/28/229299.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>How to work around rustup-init failure</title><link>http://www.cppblog.com/jinq0123/archive/2022/04/24/229295.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 24 Apr 2022 06:09:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/04/24/229295.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229295.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/04/24/229295.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229295.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229295.html</trackback:ping><description><![CDATA[<h1id="how-to-work-around-rustup-init-failure">How to work around rustup-init failure</h1>
<p>(Jin Qing's Column, Mar., 2022)</p>
<p>rustup-init.exe may fail if some anti-virus software is running with realtime protection.</p>
<p>The error message is like this after many retries:</p>
<pre>
<code>error: could not rename component file from 'C:\.../rust/html' to 'C:\.../rust/html'
</code>
</pre>
<p>See: <ahref="https://github.com/rust-lang/rustup/issues/1912">https://github.com/rust-lang/rustup/issues/1912</a></p>
<p>And it is not possible to stop the anti-virus for a corporate laptop.</p>
<p>There is a way to workaround this. Here are the steps:</p>
<ol>
<li>Run <code>rustup-init</code> until it begins to retry renaming</li>
<li>Kill rustup-init when it is retrying
<ul><li><code>rustup</code> will be installed before the failure</li><li>do not let rustup-init do the cleanup after the final failure</li></ul></li>
<li>Run <code>rustup update</code> to install all.</li>
<li>Run <code>rustup-init</code> again to setup others.</li>
</ol>
<p>
<code>rustup update</code> will report that rustc was not found:</p>
<pre>
<code>C:\Users\jinqing01&gt;rustup update
info: syncing channel updates for 'stable-x86_64-pc-windows-msvc'
...
info: removing previous version of component 'rustc'
warning: during uninstall component rustc was not found
...
info: installing component 'rustc'
...  
info: checking for self-updates
  stable-x86_64-pc-windows-msvc updated - rustc 1.59.0 (9d1b2106e 2022-02-23) (from (rustc does not exist))
info: cleaning up downloads &amp; tmp directories
</code>
</pre>
<p>Rerun <code>rustup-init</code> to setup the toolchain:</p>
<pre>
<code>C:\Users\jinqing01&gt;cargo --version
error: no override and no default toolchain set
C:\Users\jinqing01&gt;d:
D:\&gt;cd tool
D:\Tool&gt;rustup-init.exe
Welcome to Rust!
This will download and install the official compiler for the Rust
programming language, and its package manager, Cargo.
...
Rust is installed now. Great!
Press the Enter key to continue.
D:\Tool&gt;cargo --version
cargo 1.59.0 (49d8809dc 2022-02-10)
</code>
</pre>
<img src ="http://www.cppblog.com/jinq0123/aggbug/229295.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-04-24 14:09 <a href="http://www.cppblog.com/jinq0123/archive/2022/04/24/229295.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Closure as the function parameter</title><link>http://www.cppblog.com/jinq0123/archive/2022/04/24/229294.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 24 Apr 2022 06:06:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/04/24/229294.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229294.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/04/24/229294.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229294.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229294.html</trackback:ping><description><![CDATA[    <h1 id="closure-as-the-function-parameter">Closure as the function parameter</h1>
    <p>(Jin Qing's Column, Mar., 2022)</p>
    <p>It is best to let the function take a closure trait as the parameter instead of a function pointer.</p>
    <pre>
      <code>fn foo(f: fn()) {
    f()
}
fn main() {
    foo(|| println!("hello"));
    let a = 123;
    foo(move || println!("{}", a))
}
</code>
    </pre>
    <p>compiles error:</p>
    <pre>
      <code>error[E0308]: mismatched types
 --&gt; src/main.rs:9:9
  |
9 |     foo(move || println!("{}", a))
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found closure
  |
  = note: expected fn pointer `fn()`
                found closure `[closure@src/main.rs:9:9: 9:34]`
note: closures can only be coerced to `fn` types if they do not capture any variables
 --&gt; src/main.rs:9:32
  |
9 |     foo(move || println!("{}", a))
  |                                ^ `a` captured here
For more information about this error, try `rustc --explain E0308`.
</code>
    </pre>
    <p>
      <a href="https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html">https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html</a>
    </p>
    <blockquote>
      <p>Function pointers implement all three of the closure traits (Fn, FnMut, and FnOnce), so you can always pass a function pointer as an argument for a function that expects a closure. It&#8217;s best to write functions using a generic type and one of the closure traits so your functions can accept either functions or closures.</p>
    </blockquote>
<img src ="http://www.cppblog.com/jinq0123/aggbug/229294.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-04-24 14:06 <a href="http://www.cppblog.com/jinq0123/archive/2022/04/24/229294.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Deadlock detection must not run as tokio task</title><link>http://www.cppblog.com/jinq0123/archive/2022/04/24/229293.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 24 Apr 2022 06:04:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/04/24/229293.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229293.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/04/24/229293.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229293.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229293.html</trackback:ping><description><![CDATA[<h1 id="deadlock-detection-must-not-run-as-tokio-task">deadlock detection must not run as tokio task</h1>
<p>(Jin Qing's Column, Feb., 2022)</p>
<p>parking_lot has an experimental feature: deadlock_detection.</p>
<p>See: <a href="https://amanieu.github.io/parking_lot/parking_lot/deadlock/index.html">https://amanieu.github.io/parking_lot/parking_lot/deadlock/index.html</a></p>
<pre>
<code>use std::thread;
use std::time::Duration;
use parking_lot::deadlock;
// Create a background thread which checks for deadlocks every 10s
thread::spawn(move || {
loop {
thread::sleep(Duration::from_secs(10));
let deadlocks = deadlock::check_deadlock();
if deadlocks.is_empty() {
continue;
}
println!("{} deadlocks detected", deadlocks.len());
for (i, threads) in deadlocks.iter().enumerate() {
println!("Deadlock #{}", i);
for t in threads {
println!("Thread Id {:#?}", t.thread_id());
println!("{:#?}", t.backtrace());
}
}
}
});
</code>
</pre>
<p>The output is like this:</p>
<pre>
<code>1 deadlocks detected
Deadlock #0
Thread Id 16072
0: 0x7ff985cb659d - backtrace::backtrace::dbghelp::trace
at d:\Users\jinqing\.cargo\registry\src\github.com-1ecc6299db9ec823\backtrace-0.3.63\src\backtrace\dbghelp.rs:98
...
13: 0x7ff985ae92f3 - lock_api::rwlock::RwLock&lt;parking_lot::raw_rwlock::RawRwLock,cgc::scene_template::SceneTemplate&gt;::read&lt;parking_lot::raw_rwlock::RawRwLock,cgc::scene_template::SceneTemplate&gt;
at d:\Users\jinqing\.cargo\registry\src\github.com-1ecc6299db9ec823\lock_api-0.4.6\src\rwlock.rs:448
14: 0x7ff985aeadf3 - cgc::scene::SceneData::check_body_collide
at E:\gitlab\yserver\gc\src\scene.rs:99
...
81: 0x7ff9f29b7034 - BaseThreadInitThunk
82: 0x7ff9f2b02651 - RtlUserThreadStart
</code>
</pre>
<p>But the deadlock detection thread can not be changed to a tokio task,
because if deadlock happens, all tasks may be blocked, including the deadlock detection,
causing no deadlock error output.</p>
<p>In the following example, if the number of the deadlock tasks is larger than the thread number of tokio runtime,
all tasks will be blocked.</p>
<pre>
<code>use std::{thread, time::Duration};
use parking_lot::RwLock;
use tokio::time;
#[tokio::main]
async fn main() {
tokio::spawn(async move {
for i in 0..999999 {
println!("{}", i);
time::sleep(Duration::from_secs(1)).await;
}
});
const MAX: i32 = 100;
for _ in 0..MAX {
tokio::spawn(async move {
{
// DEADLOCK!
let a = RwLock::new(());
let _g1 = a.write();
let _g2 = a.write();
}
time::sleep(Duration::from_secs(9999)).await;
});
}
println!("Hello, world!");
thread::sleep(Duration::from_secs(10));
}
</code>
</pre>
<p>The output is:</p>
<pre>
<code>0
Hello, world!
_
</code>
</pre>
<p>If no deadlock, or the number of deadlock tasks is small, the output should be:</p>
<pre>
<code>0
Hello, world!
1
2
3
...
</code>
</pre>
<img src ="http://www.cppblog.com/jinq0123/aggbug/229293.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-04-24 14:04 <a href="http://www.cppblog.com/jinq0123/archive/2022/04/24/229293.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TortoiseGit is OK but GitExtensions fails</title><link>http://www.cppblog.com/jinq0123/archive/2022/04/24/229292.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 24 Apr 2022 06:01:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/04/24/229292.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229292.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/04/24/229292.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229292.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229292.html</trackback:ping><description><![CDATA[    <h1 id="tortoisegit-is-ok-but-gitextensions-fails">TortoiseGit is OK but GitExtensions fails</h1>
    <p>GitExtensions and Git fail:</p>
    <pre>
      <code>"git" pull --progress "origin"
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
Done
Press Enter or Esc to exit...
</code>
    </pre>
    <p>But TortoiseGit is OK.</p>
    <pre>
      <code>git.exe pull --progress -v --no-rebase "origin"
From github.com:jinq0123/recastnavigation
= [up to date]      master      -&gt; origin/master
= [up to date]      release-2.0 -&gt; origin/release-2.0
Already up to date.
</code>
    </pre>
    <p>
      <code>ssh -T</code> shows that the reason is there is no id files:</p>
    <pre>
      <code>PS d:\github&gt; ssh -vT git@github.com
OpenSSH_for_Windows
debug1: Connecting to github.com [20.205.243.166] port 22.
debug1: Connection established.
debug1: identity file C:\\Users\\jinqing/.ssh/id_rsa type -1
debug1: identity file C:\\Users\\jinqing/.ssh/id_xmss-cert type -1
debug1: Authenticating to github.com:22 as 'git'
debug1: Host 'github.com' is known and matches the ED25519 host key.
debug1: Found key in C:\\Users\\jinqing/.ssh/known_hosts:2
debug1: Will attempt key: C:\\Users\\jinqing/.ssh/id_rsa
debug1: Will attempt key: C:\\Users\\jinqing/.ssh/id_xmss
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Trying private key: C:\\Users\\jinqing/.ssh/id_rsa
debug1: Trying private key: C:\\Users\\jinqing/.ssh/id_xmss
debug1: No more authentication methods to try.
git@github.com: Permission denied (publickey).
PS d:\github&gt;
</code>
    </pre>
    <p>Copy my RSA key file rsa.ppk that TortoiseGit uses as ~/.ssh/id_rsa:</p>
    <pre>
      <code>PS D:\jinqing\github_jinq\recastnavigation&gt; ssh -T git@github.com
Load key "C:\\Users\\jinqing/.ssh/id_rsa": invalid format
git@github.com: Permission denied (publickey).
PS D:\jinqing\github_jinq\recastnavigation&gt;
</code>
    </pre>
    <p>Open TortoiseGit/bin/puttygen.exe, load rsa.ppk, then Convensionis-&gt;Export OpenSSH key as ~/.ssh/id_rsa:</p>
    <pre>
      <code>PS D:\jinqing\github_jinq\recastnavigation&gt; ssh -T git@github.com
Hi jinq0123! You've successfully authenticated, ...
</code>
    </pre>
    <p>id_rsa begins with:</p>
    <pre>
      <code>-----BEGIN RSA PRIVATE KEY-----
</code>
    </pre>
<img src ="http://www.cppblog.com/jinq0123/aggbug/229292.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-04-24 14:01 <a href="http://www.cppblog.com/jinq0123/archive/2022/04/24/229292.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tracing usage</title><link>http://www.cppblog.com/jinq0123/archive/2022/01/02/218556.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 02 Jan 2022 04:38:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/01/02/218556.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/218556.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/01/02/218556.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/218556.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/218556.html</trackback:ping><description><![CDATA[<h1 id="tracing-usage">Tracing usage</h1>
    <p>(Jin Qing's Column, Jan., 2022)</p>
    <p>Tracing is Rust log crate: <a href="https://github.com/tokio-rs/tracing">https://github.com/tokio-rs/tracing</a></p>
    <p>This example code outputs log to stdout and a log file, using a log filter config file,
which can be automatically reloaded on change.</p>
    <p>
      <a href="https://gitee.com/jinq0123/tracing-example">https://gitee.com/jinq0123/tracing-example</a>
    </p>
    <h2 id="dependencies">Dependencies</h2>
    <p>Add these dependencies to Cargo.toml:</p>
    <pre>      <code>[dependencies]
anyhow = "1.0.52"
hotwatch = "0.4.6"
tracing = "0.1.29"
tracing-appender = "0.2.0"
tracing-subscriber = { version = "0.3.5", features = [ "env-filter", "json" ] }
</code>
    </pre>
    <h2 id="main.rs">main.rs</h2>
    <pre>      <code class="language-Rust">mod log;
use anyhow::Result;
use std::{thread, time::Duration};
use tracing::info;
fn main() -&gt; Result&lt;()&gt; {
    let _guard = log::init("./log", "example.log", "config/log_filter.txt")?;
    for i in 0..999 {
        info!(i, "Hello, world!");
        thread::sleep(Duration::from_secs(1));
    }
    Ok(())
}
</code>
    </pre>
    <h2 id="log.rs">log.rs</h2>
    <pre>      <code class="language-Rust">//! Init log.
//!
use anyhow::{anyhow, Context as _, Result};
use hotwatch::{Event, Hotwatch};
use std::fs;
use std::path::Path;
use tracing::{debug, warn, Subscriber};
use tracing_appender::{non_blocking::WorkerGuard, rolling};
use tracing_subscriber::{fmt, layer::SubscriberExt, reload::Handle, EnvFilter};
/// Inits log.
/// Returns a WorkerGuard to ensure buffered logs are flushed,
///  and a Hotwatch to watch the log filter file.
pub fn init(
    directory: impl AsRef&lt;Path&gt;,
    file_name_prefix: impl AsRef&lt;Path&gt;,
    log_filter_file: impl AsRef&lt;Path&gt;,
) -&gt; Result&lt;(WorkerGuard, Hotwatch)&gt; {
    let file_appender = rolling::daily(directory, file_name_prefix);
    let (non_blocking, worker_guard) = tracing_appender::non_blocking(file_appender);
    let file_layer = fmt::Layer::default()
        .with_writer(non_blocking)
        .json()
        .flatten_event(true)
        .with_ansi(false);
    let builder = tracing_subscriber::fmt()
        .pretty()
        .with_env_filter(EnvFilter::from_default_env())
        .with_filter_reloading();
    let handle = builder.reload_handle();
    let subscriber = builder.finish();
    let subscriber = subscriber.with(file_layer);
    tracing::subscriber::set_global_default(subscriber).context("set global default subscriber")?;
    reload_filter(handle.clone(), log_filter_file.as_ref());
    let log_filter_path_buf = log_filter_file.as_ref().to_path_buf();
    let mut hotwatch = Hotwatch::new().context("hotwatch failed to initialize!")?;
    hotwatch
        .watch(log_filter_file.as_ref(), move |event: Event| {
            debug!("log filter file event: {:?}", event);
            if let Event::Write(_) = event {
                reload_filter(handle.clone(), log_filter_path_buf.clone());
            }
        })
        .with_context(|| format!("failed to watch file: {:?}", log_filter_file.as_ref()))?;
    Ok((worker_guard, hotwatch))
}
fn reload_filter&lt;S: Subscriber + 'static&gt;(
    handle: Handle&lt;EnvFilter, S&gt;,
    log_filter_file: impl AsRef&lt;Path&gt;,
) {
    let res = try_reload_filter(handle, log_filter_file);
    match res {
        Ok(_) =&gt; debug!("reload log filter OK"),
        Err(e) =&gt; warn!("reload log filter error: {:?}", e),
    }
}
fn try_reload_filter&lt;S: Subscriber + 'static&gt;(
    handle: Handle&lt;EnvFilter, S&gt;,
    log_filter_file: impl AsRef&lt;Path&gt;,
) -&gt; Result&lt;()&gt; {
    let contents = fs::read_to_string(log_filter_file.as_ref()).with_context(|| {
        format!(
            "something went wrong reading the file: {:?}",
            log_filter_file.as_ref()
        )
    })?;
    let contents = contents.trim();
    debug!("reload log filter: {:?}", contents);
    let new_filter = contents
        .parse::&lt;EnvFilter&gt;()
        .map_err(|e| anyhow!(e))
        .context("failed to parse env filter")?;
    handle.reload(new_filter).context("handle reload error")
}
</code>
    </pre>
    <h2 id="log_filter.txt">log_filter.txt</h2>
    <p>log_filter.txt is the configure file for log.
The change of this file will trigger the reload.</p>
    <p>The log filter file must exist, otherwise it will be error:</p>
    <pre>      <code>Error: failed to watch file: "config/log_filter.txt"
Caused by:
    系统找不到指定的路径。 (os error 3)
</code>
    </pre>
    <p>The content of log_filter.txt is a single line of filter string.
A filter string consists of one or more comma-separated directives.
The directive syntax is similar to <a href="https://docs.rs/env_logger/0.9.0/env_logger/#enabling-logging">RUST_LOG env val of env_logger&#8217;s</a>.</p>
    <pre>      <code>target[span{field=value}]=level
</code>
    </pre>
    <p>See: <a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/struct.EnvFilter.html">https://docs.rs/tracing-subscriber/latest/tracing_subscriber/struct.EnvFilter.html</a></p>
    <h3 id="example">Example</h3>
    <ul>
      <li>
        <code>tracing_example</code> enables logs that:
<ul><li>target is modules of <code>tracing_example*</code></li></ul></li>
      <li>
        <code>info</code> will enable logs that:
<ul><li>level is <code>info</code></li></ul></li>
      <li>
        <code>tracing_ex=info</code> enables logs that:
<ul><li>target is modules of tracing_ex*</li><li>level is info or above</li></ul></li>
      <li>
        <code>info,tracing_ex=debug</code> enables logs that:
<ul><li>level is info or above</li><li>or target is tracing_ex* and level is debug</li></ul></li>
      <li>
        <code>[foo]=trace</code> enables logs that:
<ul><li>within the span <code>foo</code></li><li>level is trace or above</li></ul></li>
      <li>
        <code>[span_b{name=\"bob\"}]</code> enables logs that:
<ul><li>have any target,</li><li>are inside a span named span_b,</li><li>which has a field named name with value bob,</li><li>at any level.</li></ul></li>
    </ul>
    <p>Note: span filter directive will keep effective until it exits the span.</p><img src ="http://www.cppblog.com/jinq0123/aggbug/218556.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-01-02 12:38 <a href="http://www.cppblog.com/jinq0123/archive/2022/01/02/218556.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Try tracing</title><link>http://www.cppblog.com/jinq0123/archive/2022/01/01/218312.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sat, 01 Jan 2022 12:35:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/01/01/218312.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/218312.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/01/01/218312.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/218312.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/218312.html</trackback:ping><description><![CDATA[    <h1 id="try-tracing">Try tracing</h1>
    <p>(Jin Qing's Column, Dec., 2021)</p>
    <p>
      <a href="https://github.com/tokio-rs/tracing">https://github.com/tokio-rs/tracing</a>
    </p>
    <h2 id="usage-on-github">Usage on github</h2>
    <p>Switch to tag tracing-0.1.29 first. The master's examples can not build.
Subscriber is renaming to collector on master.</p>
    <p>tracing<span>subscriber in 0.1.29 has been renamed to tracing</span>collect on master.</p>
    <ul>
      <li>In Applications</li>
      <li>In Libraries</li>
      <li>In async</li>
    </ul>
    <p>The example is using tracing_subscriber::fmt, which can be configured by RUST_LOG env val.</p>
    <p>By default, no log is output. Set RUST_LOG=info before running, and the log is:</p>
    <pre>
      <code>Dec 25 10:23:11.200  INFO tracing_test: preparing to shave yaks number_of_yaks=3
Dec 25 10:23:11.203  INFO tracing_test: yak shaving completed. all_yaks_shaved=true
</code>
    </pre>
    <ul>
      <li>span</li>
      <li>set_global_default()</li>
      <li>tracing<span>collect</span>with_default()</li>
    </ul>
    <h4 id="usage-of-rust_log">Usage of RUST_LOG.</h4>
    <p>RUST_LOG is defined in <a href="https://docs.rs/env_logger/0.9.0/env_logger/">env_logger</a></p>
    <ul>
      <li>Default disabled except error</li>
      <li>RUST_LOG is comma-separated directives
<ul><li>Directive form: example<span>log</span>target=level
<ul><li>The log target is a prefix
<ul><li>If target is ommitted, then all modules are set</li></ul></li><li>The level is "all" if ommitted
<ul><li>off, error, warn, info, debug, trace</li></ul></li></ul></li><li>Regex filter: error,hello=warn/[0-9]scopes
<ul><li>For all directives</li></ul></li></ul></li>
    </ul>
    <h2 id="usage-on-crates.io">Usage on crates.io</h2>
    <p>It is slightly different from the github.</p>
    <ul>
      <li>Uses set_global_default()</li>
      <li>Explains some concepts
<ul><li>span</li><li>event</li></ul></li>
    </ul>
    <p>Span filter? [my_span]=info</p>
    <h2 id="document">Document</h2>
    <p>
      <a href="https://docs.rs/tracing/0.1.29/tracing/">https://docs.rs/tracing/0.1.29/tracing/</a>
    </p>
    <p>The document is much more detailed than github and crates.io.</p>
    <h2 id="code-examples">Code examples</h2>
    <p>Run example:</p>
    <pre>
      <code>cargo run --example counters
</code>
    </pre>
    <h3 id="write-to-file">Write to file</h3>
    <p>fmt-multiple-writers:</p>
    <ul>
      <li>Change to write to current dir
<ul><li><code>tracing_appender::rolling::hourly(".", ...</code></li></ul></li>
      <li>Do not write ANSI color to file
<ul><li><code>.with(fmt::Layer::new().with_writer(non_blocking).with_ansi(false));</code></li></ul></li>
    </ul>
    <h3 id="dynamic-level">Dynamic level</h3>
    <p>tower-load</p>
    <ul>
      <li>with_filter_reloading() -&gt; reload handl -&gt; handle.reload(new_filter)</li>
      <li>new filter is send through http</li>
    </ul>
    <p>
      <a href="https://github.com/tokio-rs/tracing/issues/1629">https://github.com/tokio-rs/tracing/issues/1629</a>
tracing_subscriber::reload</p>
    <p>They use the same <code>tracing_subscriber::reload::Handle::reload()</code></p>
    <h4 id="filters-and-layers">Filters and Layers</h4>
    <p>
      <a href="https://docs.rs/tracing-subscriber/0.3.4/tracing_subscriber/layer/index.html#filtering-with-layers">https://docs.rs/tracing-subscriber/0.3.4/tracing_subscriber/layer/index.html#filtering-with-layers</a>
    </p>
    <h2 id="reload-from-config-file">Reload from config file</h2>
    <p>It is desired to reconfigure the log filter in the runtime by SIGHUP, or watch configure file change.
It can use notify crate to watch file.</p>
    <pre>
      <code class="language-Rust">use anyhow::{anyhow, Context as _, Result};
use hotwatch::{Event, Hotwatch};
use std::{fs, thread, time::Duration};
use tracing::{debug, info, warn, Subscriber};
use tracing_subscriber::{reload::Handle, EnvFilter};
const CFG: &amp;str = "cfg.txt";
fn main() -&gt; Result&lt;()&gt; {
    let builder = tracing_subscriber::fmt()
        .with_env_filter(EnvFilter::from_default_env())
        .with_filter_reloading();
    let handle = builder.reload_handle();
    builder
        .try_init()
        .map_err(|e| anyhow!(e))
        .context("failed to init subscriber builder")?;
    tracing::info!("Before reload");
    reload_cfg(handle.clone());
    let mut hotwatch = Hotwatch::new().context("hotwatch failed to initialize!")?;
    hotwatch
        .watch(CFG, move |event: Event| {
            if let Event::Write(_) = event {
                reload_cfg(handle.clone());
            }
        })
        .context("failed to watch file")?;
    for i in 0..999 {
        info!(i);
        thread::sleep(Duration::from_secs(1));
    }
    Ok(())
}
fn reload_cfg&lt;S: Subscriber + 'static&gt;(handle: Handle&lt;EnvFilter, S&gt;) {
    let res = try_reload_cfg(handle);
    match res {
        Ok(_) =&gt; debug!("reload cfg OK"),
        Err(e) =&gt; warn!("reload cfg error: {:?}", e),
    }
}
fn try_reload_cfg&lt;S: Subscriber + 'static&gt;(handle: Handle&lt;EnvFilter, S&gt;) -&gt; Result&lt;()&gt; {
    let contents = fs::read_to_string(CFG).context("something went wrong reading the file")?;
    let contents = contents.trim();
    debug!("reload cfg: {:?}", contents);
    let new_filter = contents
        .parse::&lt;EnvFilter&gt;()
        .map_err(|e| anyhow!(e))
        .context("failed to parse env filter")?;
    handle.reload(new_filter).context("handle reload error")
}
</code>
    </pre>
    <h2 id="how-to-new-a-subscriber-with-tracing-subscriber">How to new a Subscriber with tracing-subscriber</h2>
    <ul>
      <li>SubscriberBuilder:
<ul><li>fmt().init()</li><li>with_env_filter()</li><li>with_filter_reloading()</li><li>reload_handle()</li><li>finish() to get a Subscriber and then add a file Layer?
<ul><li><a href="https://github.com/tokio-rs/tracing/issues/971">https://github.com/tokio-rs/tracing/issues/971</a></li></ul></li></ul></li>
      <li>Registry:
<ul><li>registry().with...()</li><li>Currently, the [<code>Registry</code>] type provided by this crate is the <strong>only</strong> [<code>Subscriber</code>] implementation capable of participating in per-layer filtering.</li></ul></li>
      <li>FmtSubscriber
<ul><li>new it manually</li><li>need SubscriberBuilder to configure</li></ul></li>
    </ul>
<img src ="http://www.cppblog.com/jinq0123/aggbug/218312.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-01-01 20:35 <a href="http://www.cppblog.com/jinq0123/archive/2022/01/01/218312.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Box&lt;dyn Trait&gt; doesn't implement the trait</title><link>http://www.cppblog.com/jinq0123/archive/2021/12/21/217886.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 21 Dec 2021 07:09:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/12/21/217886.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217886.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/12/21/217886.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217886.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217886.html</trackback:ping><description><![CDATA[<p>&nbsp;From:&nbsp;<a href="https://bennetthardwick.com/dont-use-boxed-trait-objects-for-struct-internals/">Don't use boxed trait objects (bennetthardwick.com)</a></p><p style="box-sizing: border-box; font-family: Rubik, &quot;PT Serif&quot;, system-ui, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Ubuntu, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif; font-size: 16px; background-color: #ffffff;">By default a&nbsp;<code style="box-sizing: border-box; font-family: monospace, monospace; font-size: 1em; background: rgba(0, 0, 0, 0.04); padding: 0.2em 0px;">Box&lt;dyn Trait&gt;</code>&nbsp;doesn't implement the trait of the object it contains. This means that trying to construct&nbsp;<code style="box-sizing: border-box; font-family: monospace, monospace; font-size: 1em; background: rgba(0, 0, 0, 0.04); padding: 0.2em 0px;">PeopleZoo&lt;Box&lt;dyn Person&gt;&gt;</code>&nbsp;won't work out of the box and will give a type error.</p><p style="box-sizing: border-box; font-family: Rubik, &quot;PT Serif&quot;, system-ui, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Ubuntu, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif; font-size: 16px; background-color: #ffffff;">Because of this, it's good practice to give a default implementation of your trait for it's boxed counterpart. This can be done by calling&nbsp;<code style="box-sizing: border-box; font-family: monospace, monospace; font-size: 1em; background: rgba(0, 0, 0, 0.04); padding: 0.2em 0px;">as_ref</code>&nbsp;or&nbsp;<code style="box-sizing: border-box; font-family: monospace, monospace; font-size: 1em; background: rgba(0, 0, 0, 0.04); padding: 0.2em 0px;">as_mut</code>&nbsp;on the&nbsp;<code style="box-sizing: border-box; font-family: monospace, monospace; font-size: 1em; background: rgba(0, 0, 0, 0.04); padding: 0.2em 0px;">Box</code>&nbsp;and calling the references relevant method.</p><p style="box-sizing: border-box; font-family: Rubik, &quot;PT Serif&quot;, system-ui, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Ubuntu, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif; font-size: 16px; background-color: #ffffff;">For just a small bit of effort you can help a bunch of people that may consume your struct.<br /><br /></p><p style="box-sizing: border-box; font-family: Rubik, &quot;PT Serif&quot;, system-ui, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Ubuntu, Cantarell, &quot;Fira Sans&quot;, &quot;Droid Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif; font-size: 16px; background-color: #ffffff;"></p><div style="display: inline-block;"><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">trait</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">Person</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">{</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
    </span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">fn</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token function-definition function" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">say_hello</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">(</span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">&amp;</span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">self</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">)</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">;</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">}</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">

</span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">impl</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">Person</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">for</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">Box</span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">&lt;</span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">dyn</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">Person</span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">&gt;</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">{</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
    </span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">fn</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token function-definition function" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">say_hello</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">(</span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">&amp;</span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">self</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">)</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">{</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
        </span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">self</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">.</span><span class="token function" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">as_ref</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">(</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">)</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">.</span><span class="token function" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">say_hello</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">(</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">)</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
    </span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">}</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">}</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
<br /></span></div><p>&nbsp;</p><pre class="language-rust" style="box-sizing: border-box; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; font-size: 16px; overflow: auto; padding: 1em; max-width: 100%; background: #fafafa; color: #383a42; direction: ltr; word-break: normal; line-height: 1.5; tab-size: 2; hyphens: none; margin-top: 0px; margin-bottom: 0px; border-radius: 0.3em;"><code class="language-rust" style="box-sizing: border-box; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; font-size: 1em; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; padding: 0.2em 0px; direction: ltr; word-spacing: normal; word-break: normal; line-height: 1.5; tab-size: 2; hyphens: none;"><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none;">struct</span> <span class="token type-definition class-name" style="box-sizing: border-box; color: #b76b01; background: none;">PeopleZoo</span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none;">&lt;</span><span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none;">P</span><span class="token punctuation" style="box-sizing: border-box; background: none;">:</span> <span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none;">Person</span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none;">&gt;</span> <span class="token punctuation" style="box-sizing: border-box; background: none;">{</span>
    people<span class="token punctuation" style="box-sizing: border-box; background: none;">:</span> <span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none;">Vec</span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none;">&lt;</span><span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none;">P</span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none;">&gt;</span><span class="token punctuation" style="box-sizing: border-box; background: none;">,</span>
<span class="token punctuation" style="box-sizing: border-box; background: none;">}</span></code></pre><div style="display: inline-block;"><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
</span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">fn</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token function-definition function" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">main</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">(</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">)</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">{</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
  </span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">let</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">mut</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> zoo</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">:</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">PeopleZoo</span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">&lt;</span><span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">Box</span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">&lt;</span><span class="token keyword" style="box-sizing: border-box; color: #a626a4; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">dyn</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">Person</span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">&gt;&gt;</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token operator" style="box-sizing: border-box; color: #4078f2; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">=</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token class-name" style="box-sizing: border-box; color: #b76b01; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">PeopleZoo</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">{</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
    people</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">:</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;"> </span><span class="token macro property" style="box-sizing: border-box; color: #e45649; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">vec!</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">[</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">]</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
  </span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">}</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">;</span><span style="color: #383a42; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre; background-color: #fafafa;">
</span><span class="token punctuation" style="box-sizing: border-box; color: #383a42; background: none; font-family: &quot;Fira Code&quot;, &quot;Fira Mono&quot;, Menlo, Consolas, &quot;DejaVu Sans Mono&quot;, monospace; white-space: pre;">}</span></div><img src ="http://www.cppblog.com/jinq0123/aggbug/217886.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-12-21 15:09 <a href="http://www.cppblog.com/jinq0123/archive/2021/12/21/217886.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>minikube DNS fails after SRV query</title><link>http://www.cppblog.com/jinq0123/archive/2021/12/10/217878.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 10 Dec 2021 02:46:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/12/10/217878.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217878.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/12/10/217878.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217878.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217878.html</trackback:ping><description><![CDATA[<h1id='minikube-dns-fails-after-srv-query'>minikube DNS fails after SRV query</h1>
<p>(Jin Qing&#39;s Column, Dec., 2021)</p>
<p>My program is using K8s DNS SRV query to discovery service, 
and when it&#39;s deployed on minikube, I find DNS failure.</p>
<p>I can use nslookup to reproduce the failure.</p>
<p>Querying a FQDN is OK. But after querying a non-existing SRV short name, the ping fails.</p>
<pre><code>root@web-0:/# ping google.com
PING google.com (142.250.66.110) 56(84) bytes of data.
64 bytes from hkg12s28-in-f14.1e100.net (142.250.66.110): icmp_seq=1 ttl=108 time=33.7 ms
64 bytes from hkg12s28-in-f14.1e100.net (142.250.66.110): icmp_seq=2 ttl=108 time=33.8 ms
^C
--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 33.779/33.834/33.889/0.055 ms
root@web-0:/# nslookup
&gt; set type=srv
&gt; nosuch-nosuch-nosuch-1234567890abcdefg.cn
Server:         10.96.0.10
Address:        10.96.0.10#53
** server can&#39;t find nosuch-nosuch-nosuch-1234567890abcdefg.cn: NXDOMAIN
&gt; exit
root@web-0:/# ping google.com
PING google.com (142.250.66.110) 56(84) bytes of data.
64 bytes from hkg12s28-in-f14.1e100.net (142.250.66.110): icmp_seq=1 ttl=108 time=33.7 ms
64 bytes from hkg12s28-in-f14.1e100.net (142.250.66.110): icmp_seq=2 ttl=108 time=33.7 ms
^C
--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 33.730/33.735/33.741/0.183 ms
root@web-0:/# nslookup
&gt; set type=srv
&gt; nginx-wrong
Server:         10.96.0.10
Address:        10.96.0.10#53
** server can&#39;t find nginx-wrong: SERVFAIL
&gt; exit
root@web-0:/# ping google.com
ping: unknown host google.com
root@web-0:/# 
</code></pre>
<p>The ping will recover to normal after about 1 minute.</p>
<p>If I query a existing internal service name, and nslookup returns correctly, then DNS is OK after I quit nslookup.</p>
<pre><code>root@web-0:/# ping google.com
PING google.com (142.250.66.110) 56(84) bytes of data.
64 bytes from hkg12s28-in-f14.1e100.net (142.250.66.110): icmp_seq=1 ttl=108 time=33.6 ms
64 bytes from hkg12s28-in-f14.1e100.net (142.250.66.110): icmp_seq=2 ttl=108 time=34.8 ms
^C
--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 33.648/34.260/34.872/0.612 ms
root@web-0:/# nslookup
&gt; set type=srv
&gt; nginx
Server:         10.96.0.10
Address:        10.96.0.10#53
nginx.default.svc.cluster.local service = 0 25 80 web-1.nginx.default.svc.cluster.local.
nginx.default.svc.cluster.local service = 0 25 80 web-2.nginx.default.svc.cluster.local.
nginx.default.svc.cluster.local service = 0 25 80 web-0.nginx.default.svc.cluster.local.
nginx.default.svc.cluster.local service = 0 25 80 web-3.nginx.default.svc.cluster.local.
&gt; exit
root@web-0:/# ping google.com
PING google.com (142.250.66.110) 56(84) bytes of data.
64 bytes from hkg12s28-in-f14.1e100.net (142.250.66.110): icmp_seq=1 ttl=108 time=33.5 ms
^C
--- google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 33.529/33.529/33.529/0.000 ms
root@web-0:/# 
</code></pre>
<p>When DNS fails, the whole cluster can not query any domain name outside,
but internal name is OK.</p>
<p><ahref='https://github.com/kubernetes/minikube/issues/13137'target='_blank'class='url'>https://github.com/kubernetes/minikube/issues/13137</a></p>
<img src ="http://www.cppblog.com/jinq0123/aggbug/217878.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-12-10 10:46 <a href="http://www.cppblog.com/jinq0123/archive/2021/12/10/217878.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DeathVoteExpirationTimeout in Orleans</title><link>http://www.cppblog.com/jinq0123/archive/2021/12/08/217872.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 08 Dec 2021 01:43:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/12/08/217872.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217872.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/12/08/217872.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217872.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217872.html</trackback:ping><description><![CDATA[<h1id='deathvoteexpirationtimeout-in-orleans'>DeathVoteExpirationTimeout in Orleans</h1>
<p>(Jin Qing&#39;s Column, Dec., 2021)</p>
<p>Try to find out why Orleans need a DeathVoteExpirationTimeout config.</p>
<p><ahref='https://dotnet.github.io/orleans/docs/implementation/cluster_management.html#extension-to-totally-order-membership-views'target='_blank'class='url'>https://dotnet.github.io/orleans/docs/implementation/cluster_management.html#extension-to-totally-order-membership-views</a></p>
<pre><code>DeathVoteExpirationTimeout - Expiration time in seconds for death vote in the membership table. Default is 120 seconds
</code></pre>
<h2id='getfreshvotes'><code>GetFreshVotes</code></h2>
<p>DeathVoteExpirationTimeout is only used by GetFreshVotes(), which has 3 occurence:</p>
<pre><code>    class ClusterHealthMonitor
    {
        ...
        private UpdateMonitoredSilos(...)
        {
            ...
            bool isSuspected = candidateEntry.GetFreshVotes(now, DeathVoteExpirationTimeout).Count &gt; 0;
            ...
        }
    }
</code></pre>
<pre><code>    class LocalSiloHealthMonitor
    {
        ...
        private int CheckSuspectingNodes(DateTime now, List&lt;string&gt; complaints)
        {
            ...
            var freshVotes = membershipEntry.GetFreshVotes(now, DeathVoteExpirationTimeout);
            ...
        }
        ...
    }
</code></pre>
<pre><code>    class MembershipTableManager
    {
        ...
        public TryToSuspectOrKill(SiloAddress silo)
        {
            ...
            // get all valid (non-expired) votes
            var freshVotes = entry.GetFreshVotes(DateTime.UtcNow, DeathVoteExpirationTimeout);
            ...
        }
        ...
    }
</code></pre>
<p>GetFreshVotes() uses this expiration time to ignore old voter:</p>
<pre><code>        internal GetFreshVotes(DateTime now, TimeSpan expiration)
        {
            ...
            foreach (var voter in this.SuspectTimes)
            {
                var otherVoterTime = voter.Item2;
                if (now.Subtract(otherVoterTime) &lt; expiration)
                {
                    result.Add(voter);
                }
            }
            return result.ToImmutable();
        }
</code></pre>
<img src ="http://www.cppblog.com/jinq0123/aggbug/217872.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-12-08 09:43 <a href="http://www.cppblog.com/jinq0123/archive/2021/12/08/217872.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>How to delete local branches of GitExtension</title><link>http://www.cppblog.com/jinq0123/archive/2021/12/07/217870.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 07 Dec 2021 09:04:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/12/07/217870.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217870.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/12/07/217870.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217870.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217870.html</trackback:ping><description><![CDATA[<h1id='how-to-delete-local-branches-of-gitextension'>How to delete local branches of GitExtension</h1>
<p>(Jin Qing&#39;s Column, Dec., 2021)</p>
<p>GitExtension is a good tool. After a long time of usage, my branch list finally reaches over a full screen, and it is hard to select the branch I want.</p>
<p>GitExtension always remembers all the branches of remote and local, even they have been deleted.</p>
<p>I tried to find a way to delete these branches which are already merged, but resulted in futile.</p>
<p>It has a plugin names &quot;Delete obsolete branches&quot;, but I don&#39;t know how to use it.</p>
<p>Finally I renamed the work directory, and cloned a new one, which clears all the branches.
It seems that these branches are stored in local .git directory.
If let GitExt open the renamed directory, these branches reappears.</p>
<p>Reference:</p>
<ul>
<li><ahref='https://talk.plesk.com/threads/git-extension-doesnt-remove-deleted-branches.351838/'target='_blank'class='url'>https://talk.plesk.com/threads/git-extension-doesnt-remove-deleted-branches.351838/</a></li>
<li><ahref='https://plesk.uservoice.com/forums/184549-feature-suggestions/suggestions/39296707-git-extension-option-to-delete-branches'target='_blank'class='url'>https://plesk.uservoice.com/forums/184549-feature-suggestions/suggestions/39296707-git-extension-option-to-delete-branches</a></li>
</ul>
<img src ="http://www.cppblog.com/jinq0123/aggbug/217870.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-12-07 17:04 <a href="http://www.cppblog.com/jinq0123/archive/2021/12/07/217870.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>建议日志 slog 改换 tracing</title><link>http://www.cppblog.com/jinq0123/archive/2021/11/24/217865.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 24 Nov 2021 10:18:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/11/24/217865.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217865.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/11/24/217865.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217865.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217865.html</trackback:ping><description><![CDATA[<h1 id='建议日志-slog-改换-tracing'>建议日志 slog 改换 tracing</h1>
<p>(金庆的专栏 2021.11)</p>
<ul>
<li><p>slog 不是立即写盘，最后的几行日志会丢失</p>
<ul>
<li>tracing 不会丢日志</li>
</ul>
</li>
<li><p>slog 不支持运行中动态更改日志等级</p>
<ul>
<li><p>tracing <a href='https://tracing.rs/tracing_subscriber/fmt/struct.collectorbuilder#method.with_filter_reloading'>with_filter_reloading()</a></p>
<ul>
<li>examples/tower-load</li>
</ul>
</li>
</ul>
</li>
<li><p>slog 不支持不同包设置不同日志等级</p>
<ul>
<li>tracing 可单独打开某个模块的日志</li>
</ul>
</li>
<li><p>发现一次 slog panic: <code>panicked at &#39;slog::Fuse Drain: Fatal(Custom { kind: BrokenPipe, error: &quot;The logger thread terminated&quot; })&#39;</code></p>
<ul>
<li><p>搜到相同错误：<a href='https://github.com/mimblewimble/grin/issues/946' target='_blank' class='url'>https://github.com/mimblewimble/grin/issues/946</a></p>
<ul>
<li>别人的解决方法是: 不用slog了</li>
</ul>
</li>
</ul>
</li>
<li><p>slog 主页10月添加推荐使用 tracing</p>
</li>
<li><p>slog 按线程保存上下文，tracing 按协程保存上下文</p>
</li>
<li><p>tracing github star 1.9K &gt; slog 1.2K</p>
</li>
<li><p>tracing crates 下载 21M &gt; sloggers 0.4M, slog-scope 2.6M, slog-stdlog 1.9M</p>
</li>
<li><p>tracing vs slog: <a href='https://www.reddit.com/r/rust/comments/kdo29n/slog_vs_tracing_which_one_do_you_prefer/' target='_blank' class='url'>https://www.reddit.com/r/rust/comments/kdo29n/slog_vs_tracing_which_one_do_you_prefer/</a></p>
</li>
<li><p>Rust compiler 2020年已改用 tracing：<a href='https://github.com/rust-lang/rust/pull/74726' target='_blank' class='url'>https://github.com/rust-lang/rust/pull/74726</a></p>
</li>
<li><p>tracing 更好用</p>
<ul>
<li>文档及示例更全</li>
<li>支持库更多</li>
</ul>
</li>
</ul>
<img src ="http://www.cppblog.com/jinq0123/aggbug/217865.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-11-24 18:18 <a href="http://www.cppblog.com/jinq0123/archive/2021/11/24/217865.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Named parameters in Rust</title><link>http://www.cppblog.com/jinq0123/archive/2021/11/18/217862.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 18 Nov 2021 05:14:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/11/18/217862.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217862.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/11/18/217862.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217862.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217862.html</trackback:ping><description><![CDATA[<h1 id='named-parameters-in-rust'>Named parameters in Rust</h1>
<p>(Jin Qing&#39;s Column, Nov. 18, 2021)</p>
<p>There is no &quot;named function parameters&quot; in Rust,
but there is an idiom for this case.
If a function needs many parameters, we can define a type
with all these parameters as fields, and implement <code>Default</code> trait for this type.
Then we can input this type as the function parameter, 
with some of the fields specified and others using default.</p>
<pre><code>foo(Config {
    a: 123,
    b: bool,
    ...Default::default(),
});
</code></pre>
<img src ="http://www.cppblog.com/jinq0123/aggbug/217862.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-11-18 13:14 <a href="http://www.cppblog.com/jinq0123/archive/2021/11/18/217862.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rust traits act as generic constraints</title><link>http://www.cppblog.com/jinq0123/archive/2021/11/18/217861.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 18 Nov 2021 04:51:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/11/18/217861.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217861.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/11/18/217861.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217861.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217861.html</trackback:ping><description><![CDATA[<h1 id='rust-traits-act-as-generic-constraints'>Rust traits act as generic constraints</h1>
<p>(Jin Qing&#39;s Column, Nov. 18, 2021)</p>
<p>Rust traits are different from interfaces of C++/Java/Go.</p>
<p>See: <a href='https://stevedonovan.github.io/rustifications/2018/09/08/common-rust-traits.html' target='_blank' class='url'>https://stevedonovan.github.io/rustifications/2018/09/08/common-rust-traits.html</a></p>
<p>Rust traits are mechanism for adding behavior to types.</p>
<p>Traits have 2 modes. One is interface as Java.</p>
<p>Another is generic constraint. Generic functions are defined over types that implemented specific traits.</p>
<p>The &quot;complie-time duck typing&quot; in C++ templates is avoided in Rust.
Rust will reject a type with quack() method as a Duck type.
We must pass a type which implements Duck trait.
But in Go, a type with quack() method is sufficient to be used as a Duck interface.</p>
<p>&nbsp;</p>
<img src ="http://www.cppblog.com/jinq0123/aggbug/217861.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-11-18 12:51 <a href="http://www.cppblog.com/jinq0123/archive/2021/11/18/217861.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GLIBC_2.29 not found</title><link>http://www.cppblog.com/jinq0123/archive/2021/11/05/217853.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 05 Nov 2021 01:42:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/11/05/217853.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217853.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/11/05/217853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217853.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217853.html</trackback:ping><description><![CDATA[<h1>GLIBC_2.29 not found</h1>
<p>(Jin Qing&#39;s Column, Nov. 4, 2021)</p>
<p>My Rust program failed when running in docker:</p>
<pre><code>root@a26b49c91efb:/myapp# ldd libmyapp_py.so
./libmyapp_py.so: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.29&#39; not found (required by ./libmyapp_py.so)
</code></pre>
<p>The problem is because I build in &quot;rust:1.56&quot;, and run in &quot;debian:buster-slim&quot; which is quite old. Run <code>dpkg -l libc-bin</code> shows the libc version is 2.28:</p>
<pre><code>C:\Users\jinqing01&gt;docker run debian:buster-slim dpkg -l libc-bin
Unable to find image &#39;debian:buster-slim&#39; locally
buster-slim: Pulling from library/debian
b380bbd43752: Already exists
Digest: sha256:544c93597c784cf68dbe492ef35c00de7f4f6a990955c7144a40b20d86a3475f
Status: Downloaded newer image for debian:buster-slim
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version      Architecture Description
+++-==============-============-============-=================================
ii  libc-bin       2.28-10      amd64        GNU C Library: Binaries
</code></pre>
<p>Using the latest &quot;debian:bookworm-slim&quot; solved the problem.</p>
<p>Dockerfile:</p>
<pre><code>FROM rust:1.56 as chef
RUN cargo install cargo-chef
WORKDIR /myapp
FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
FROM chef AS builder
COPY --from=planner /myapp/recipe.json recipe.json
# Build dependencies
RUN cargo chef cook --release --recipe-path recipe.json
# Build application
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim AS runtime
WORKDIR /myapp
RUN apt-get update &amp;&amp; apt-get install -y python3 python3-pip &amp;&amp; rm -rf /var/lib/apt/lists/*
RUN pip3 install protobuf
COPY --from=builder /myapp/target/release/*.so /myapp/
COPY --from=builder /myapp/target/release/myapp /myapp/
COPY --from=builder /myapp/tests /myapp/tests
CMD [&quot;myapp&quot;]
</code></pre>
<img src ="http://www.cppblog.com/jinq0123/aggbug/217853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-11-05 09:42 <a href="http://www.cppblog.com/jinq0123/archive/2021/11/05/217853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clustering provider in Orleans</title><link>http://www.cppblog.com/jinq0123/archive/2021/11/03/217852.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 03 Nov 2021 05:36:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/11/03/217852.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217852.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/11/03/217852.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217852.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217852.html</trackback:ping><description><![CDATA[<h1 id='clustering-provider-in-orleans'>Clustering provider in Orleans</h1>
<p>(Jin Qing&#39;s Column, Nov. 3, 2021)</p>
<p>When deployed to a cluster of nodes, 
Orleans internally implements a protocol to manage it&#39;s silos,
including discovery, failure and reconfigure, 
which is called cluster membership management.</p>
<p>Orleans has clustering membership providers for: Azure, SQL server, Zookeeper.</p>
<p>Clustering provider is one of key aspects of silo configuration.</p>
<h2 id='orleansclusteringkubernetes'>Orleans.Clustering.Kubernetes</h2>
<p><a href='https://github.com/OrleansContrib/Orleans.Clustering.Kubernetes'>OrleansContrib/Orleans.Clustering.Kubernetes</a>
is a clustering provider for running Orleans cluster on Kubernetes.</p>
<p>Tell silo to use Kubernetes as the Cluster Membership Provider:</p>
<pre><code class='language-c#' lang='c#'>var silo = new SiloBuilder()
        ...
        .UseKubeMembership()
        ...
        .Build();
</code></pre>
<h3 id='interface'>Interface</h3>
<p><code>UseKubeMembership()</code> instantiates a <code>KubeMembershipTable</code> which implements 
<a href='https://github.com/dotnet/orleans/blob/main/src/Orleans.Core/SystemTargetInterfaces/IMembershipTable.cs'><code>IMembershipTable</code></a>.</p>
<pre><code class='language-c#' lang='c#'>    public interface IMembershipTable
    {
        Task InitializeMembershipTable(bool tryInitTableVersion);
        Task DeleteMembershipTableEntries(string clusterId);
        Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate);
        Task&lt;MembershipTableData&gt; ReadRow(SiloAddress key);
        Task&lt;MembershipTableData&gt; ReadAll();
        Task&lt;bool&gt; InsertRow(MembershipEntry entry, TableVersion tableVersion);
        Task&lt;bool&gt; UpdateRow(MembershipEntry entry, string etag, TableVersion tableVersion);
        Task UpdateIAmAlive(MembershipEntry entry);
    }
</code></pre>
<h3 id='implement'>Implement</h3>
<p><a href='https://github.com/OrleansContrib/Orleans.Clustering.Kubernetes/blob/master/src/Orleans.Clustering.Kubernetes/KubeMembershipTable.cs'><code>KubeMembershipTable</code></a>
access Kubernetes API server to read and write silo entry CRD.</p>
<ul>
<li><p>InitializeMembershipTable()</p>
<ul>
<li><p>TryInitClusterVersion()</p>
<ul>
<li>_kubeClient.GetNamespacedCustomObjectAsync</li>
<li>_kubeClient.CreateNamespacedCustomObjectAsync</li>
</ul>
</li>
</ul>
</li>
<li><p>DeleteMembershipTableEntries(string clusterId)</p>
<ul>
<li>_kubeClient.DeleteNamespacedCustomObjectAsync</li>
</ul>
</li>
<li><p>InsertRow(...)</p>
<ul>
<li>_kubeClient.GetNamespacedCustomObjectAsync</li>
<li>_kubeClient.ReplaceNamespacedCustomObjectAsync</li>
<li>_kubeClient.CreateNamespacedCustomObjectAsync</li>
</ul>
</li>
<li><p>ReadAll()</p>
<ul>
<li><p>GetClusterVersion()</p>
<ul>
<li>_kubeClient.ListNamespacedCustomObjectAsync</li>
</ul>
</li>
<li><p>GetSilos()</p>
<ul>
<li>_kubeClient.ListNamespacedCustomObjectAsync</li>
</ul>
</li>
</ul>
</li>
<li><p>ReadRow(SiloAddress key)</p>
<ul>
<li>_kubeClient.GetNamespacedCustomObjectAsync</li>
</ul>
</li>
<li><p>UpdateIAmAlive(MembershipEntry entry)</p>
<ul>
<li>_kubeClient.GetNamespacedCustomObjectAsync</li>
<li>_kubeClient.ReplaceNamespacedCustomObjectAsync</li>
</ul>
</li>
<li><p>UpdateRow(...)</p>
<ul>
<li>_kubeClient.ReplaceNamespacedCustomObjectAsync</li>
</ul>
</li>
<li><p>CleanupDefunctSiloEntries(DateTimeOffset beforeDate)</p>
<ul>
<li>_kubeClient.DeleteNamespacedCustomObjectAsync</li>
</ul>
</li>
</ul>
<p>The operators to NamespacedCustomObject are:</p>
<ul>
<li>Delete</li>
<li>Get</li>
<li>Create</li>
<li>Replace</li>
<li>List</li>
</ul>
<h3 id='crd'>CRD</h3>
<p>Two CRDs, <code>ClusterVersion</code> and <code>Silo</code> are defined in files:</p>
<ul>
<li>ClusterVersionCRD.yaml</li>
<li>SiloEntryCRD.yaml</li>
</ul>
<p>Custom resource objects are stored in etcd of Kubernetes.</p>
<img src ="http://www.cppblog.com/jinq0123/aggbug/217852.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-11-03 13:36 <a href="http://www.cppblog.com/jinq0123/archive/2021/11/03/217852.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Why Orleans' actor is virutal</title><link>http://www.cppblog.com/jinq0123/archive/2021/11/02/217850.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 02 Nov 2021 07:27:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/11/02/217850.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217850.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/11/02/217850.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217850.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217850.html</trackback:ping><description><![CDATA[<h1 id="why-orleans-actor-is-virutal">Why Orleans' actor is virutal</h1>
<p>(Jin Qing's Column, Nov. 2, 2021)</p>
<p>Virtual Actor is a concept invented by Microsoft Orleans, which is a framework of distributed actor.</p>
<p><a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/Orleans-MSR-TR-2014-41.pdf">Orleans: Distributed Virtual Actors for Programmability and Scalability</a> describes the virtual programming model.</p>
<p>The virtual actor is analogous to virtual memory. Virtual actors are mapped to physical arctors instances in the running servers. Virtualization of actors in Orleans has 4 facets:</p>
<ol start="">
     <li>
     <p>Perpetual existence</p>
     <ul>
         <li>Actors always exist, virtually</li>
         <li>Actors can not be created or destroied explicitly</li>
         <li>Server failure does not affect the actors' existence</li>
     </ul>
     </li>
     <li>
     <p>Automatic instantiation</p>
     <ul>
         <li>Activation: Orleans automatically create an actor</li>
         <li>A request triggers an activation if the actor doesn't exist</li>
         <li>Unused actors are automatically reclaimed</li>
     </ul>
     </li>
     <li>
     <p>Location transparency</p>
     <ul>
         <li>Applications don't know where the physical actor is</li>
         <li>Similar to virtual memory's "paged out" and mapping </li>
     </ul>
     </li>
     <li>
     <p>Automatic scale out</p>
     <ul>
         <li>
         <p>2 activation modes:</p>
         <ul>
             <li>
             <p>Single activation (default): Only one simultaneous actor is allowed</p>
             </li>
             <li>
             <p>Stateless worker: Many activations of an actor are created</p>
             <ul>
                 <li>to increase throughput</li>
             </ul>
             </li>
         </ul>
         </li>
     </ul>
     </li>
</ol>
<p>Actor viruliaztion greatly simplifes the programming, since it gets rid of the burden of actor lifecycle control.</p>
<p>&nbsp;</p>
<p>&nbsp;</p><img src ="http://www.cppblog.com/jinq0123/aggbug/217850.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-11-02 15:27 <a href="http://www.cppblog.com/jinq0123/archive/2021/11/02/217850.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>What comes after microservice?</title><link>http://www.cppblog.com/jinq0123/archive/2021/10/29/217843.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 29 Oct 2021 03:16:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/10/29/217843.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217843.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/10/29/217843.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217843.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217843.html</trackback:ping><description><![CDATA[<h1 id="what-comes-after-microservice-1">What comes after microservice?</h1>
<p>(Jin Qing's Column, Oct. 25, 2021)</p>
<p>Reading "The Evolution of Distributed Systems on Kubernetes" from Bilgin Ibryam.</p>
<p><a href="https://www.infoq.com/articles/distributed-systems-kubernetes/" target="_blank" class="url">https://www.infoq.com/articles/distributed-systems-kubernetes/</a></p>
<p>What are the purpose of projects like Dapr, Istio, Knative? How can they change the world?</p>
<h2 id="modern-distributed-systems">Modern distributed systems</h2>
<p>The needs of distributed systems:</p>
<ul>
<li><p>Business logic</p>
</li>
<li><p>Other</p>
<ul>
<li>Lifecycle: deploy, rollback, upgrade, scale, stop, isolate, config</li>
<li>Network: connect, circuit break, retry, timeout, load balance, discover, security, trace</li>
<li>Resource binding: to API, protocol, message, data format</li>
<li>State: stateless, stateful, store</li>
</ul>
</li>
</ul>
<h3 id="monolithic-architecture">Monolithic architecture</h3>
<p>enterprise service bus (ESB): not distributed</p>
<h3 id="cloud-native-architecture">Cloud-native architecture</h3>
<p>Kubernetes: Lifecycle</p>
<h3 id="service-mesh">Service Mesh</h3>
<p>Istio: Networking</p>
<h3 id="serverless">Serverless</h3>
<p>Knative: scale</p>
<h3 id="dapr">Dapr</h3>
<p>Networking, resource binding, state</p>
<h2 id="trends">Trends</h2>
<ul>
<li>Lifecycle: Kubernetes + operator</li>
<li>Networking: Envoy</li>
<li>Binding: Apache Camel</li>
<li>State: Cloudstate</li>
</ul>
<h2 id="multi-runtime-microservice">Multi-runtime microservice</h2>
<p>Write business logic as another runtime. Here runtime is a process?</p>
<h2 id="what-comes-after-microservice-2">What comes after microservice</h2>
<p>Faas is not the best. Multi-runtime microservice maybe is.</p>
<p><a href="https://www.infoq.com/articles/multi-runtime-microservice-architecture/">Mecha architecture</a></p>
<p>&nbsp;</p><img src ="http://www.cppblog.com/jinq0123/aggbug/217843.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-10-29 11:16 <a href="http://www.cppblog.com/jinq0123/archive/2021/10/29/217843.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Display Non-UTF-8 output</title><link>http://www.cppblog.com/jinq0123/archive/2021/10/27/217841.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 27 Oct 2021 04:22:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/10/27/217841.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217841.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/10/27/217841.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217841.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217841.html</trackback:ping><description><![CDATA[<div>Display Non-UTF-8 output<br /></div><div></div><div>(Jin Qing's Column, Oct. 27, 2021)<br /></div><div></div><div>Cargo build output Non-UTF-8. Use python to decode it as gbk and print.</div><div></div><div>```</div><div><span style="color: #0000ff; font-family: Courier;">C:\Users\jinqing01&gt;python</span></div><div><span style="color: #0000ff; font-family: Courier;">&gt;&gt;&gt; s = b'Non-UTF-8 output:&nbsp; &nbsp;\xd5\xfd\xd4\xda\xb4\xb4\xbd\xa8\xbf\xe2 E:\\gitlab\\myproj\\target\\debug\\deps\\pyext.dll.lib \xba\xcd\xb6\xd4\xcf\xf3 E:\\gitlab\\myproj\\target\\debug\\deps\\pyext.dll.exp\r\npyext.2rtvxajnfydf6uo2.rcgu.o : error LNK2019: \xce\xde\xb7\xa8\xbd\xe2\xce\xf6\xb5\xc4\xcd\xe2\xb2\xbf\xb7\xfb\xba\xc5 __imp_PyUnicode_AsUTF8\xa3\xac\xba\xaf\xca\xfd _ZN116_$LT$pyext..script..pyext..py_object_proxy..PyNonTxnStates$u20$as$u20$pyext..object..state..NonTxnStates$GT$14to_mysql_value17h5dbfad19064f6106E \xd6\xd0\xd2\xfd\xd3\xc3\xc1\xcb\xb8\xc3\xb7\xfb\xba\xc5\r\npyext.3i2r75wtstbttq2v.rcgu.o : error LNK2001: \xce\xde\xb7\xa8\xbd\xe2\xce\xf6\xb5\xc4\xcd\xe2\xb2\xbf\xb7\xfb\xba\xc5 __imp_PyUnicode_AsUTF8\r\nlibpyutil-98f7dde2ceee0f61.rlib(pyutil-98f7dde2ceee0f61.2r21sryt0zfxlscx.rcgu.o) : error LNK2001: \xce\xde\xb7\xa8\xbd\xe2\xce\xf6\xb5\xc4\xcd\xe2\xb2\xbf\xb7\xfb\xba\xc5 __imp_PyUnicode_AsUTF8\r\nE:\\gitlab\\myproj\\target\\debug\\deps\\pyext.dll : fatal error LNK1120: 1 \xb8\xf6\xce\xde\xb7\xa8\xbd\xe2\xce\xf6\xb5\xc4\xcd\xe2\xb2\xbf\xc3\xfc\xc1\xee\r\n'</span></div><div><span style="color: #0000ff; font-family: Courier;">&gt;&gt;&gt; s.decode('gbk')</span></div><div><span style="color: #0000ff; font-family: Courier;">'Non-UTF-8 output:&nbsp; &nbsp;正在创建库 E:\\gitlab\\myproj\\target\\debug\\deps\\pyext.dll.lib 和对象 E:\\gitlab\\myproj\\target\\debug\\deps\\pyext.dll.exp\r\npyext.2rtvxajnfydf6uo2.rcgu.o : error LNK2019: 无法解析的外部 符号 __imp_PyUnicode_AsUTF8，函数 _ZN116_$LT$pyext..script..pyext..py_object_proxy..PyNonTxnStates$u20$as$u20$pyext..object..state..NonTxnStates$GT$14to_mysql_value17h5dbfad19064f6106E 中引用了该符号\r\npyext.3i2r75wtstbttq2v.rcgu.o : error LNK2001: 无法解析的外部符号 __imp_PyUnicode_AsUTF8\r\nlibpyutil-98f7dde2ceee0f61.rlib(pyutil-98f7dde2ceee0f61.2r21sryt0zfxlscx.rcgu.o) : error LNK2001: 无法解析的外部符号 __imp_PyUnicode_AsUTF8\r\nE:\\gitlab\\myproj\\target\\debug\\deps\\pyext.dll : fatal error LNK1120: 1 个无法解析的外部命令\r\n'</span></div><div><span style="color: #0000ff;">&gt;&gt;&gt;</span></div><div>```</div><img src ="http://www.cppblog.com/jinq0123/aggbug/217841.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-10-27 12:22 <a href="http://www.cppblog.com/jinq0123/archive/2021/10/27/217841.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Advice for Rust library writers about Error</title><link>http://www.cppblog.com/jinq0123/archive/2021/09/02/217805.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 02 Sep 2021 03:24:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/09/02/217805.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217805.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/09/02/217805.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217805.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217805.html</trackback:ping><description><![CDATA[<h3>Advice for library writers</h3><p style="margin-top: 0px; margin-bottom: 1rem; font-size: 1.125rem; line-height: 1.5; font-family: system-ui, &quot;Helvetica Neue&quot;, Helvetica, sans-serif; background-color: #ffffff;">Idioms for Rust libraries are still forming, but if your library needs to report custom errors, then you should probably define your own error type. It&#8217;s up to you whether or not to expose its representation (like&nbsp;<a href="http://doc.rust-lang.org/std/io/enum.ErrorKind.html" style="color: #0096cc; text-decoration-line: none;"><code>ErrorKind</code></a>) or keep it hidden (like&nbsp;<a href="http://doc.rust-lang.org/std/num/struct.ParseIntError.html" style="color: #0096cc; text-decoration-line: none;"><code>ParseIntError</code></a>). Regardless of how you do it, it&#8217;s usually good practice to at least provide some information about the error beyond just its&nbsp;<code style="color: #222222;">String</code>&nbsp;representation. But certainly, this will vary depending on use cases.</p><p style="margin-top: 0px; margin-bottom: 1rem; font-size: 1.125rem; line-height: 1.5; font-family: system-ui, &quot;Helvetica Neue&quot;, Helvetica, sans-serif; background-color: #ffffff;">At a minimum, you should probably implement the&nbsp;<a href="http://doc.rust-lang.org/std/error/trait.Error.html" style="color: #0096cc; text-decoration-line: none;"><code>Error</code></a>&nbsp;trait. This will give users of your library some minimum flexibility for&nbsp;<a href="https://blog.burntsushi.net/rust-error-handling/#the-real-try-macro" style="color: #0096cc; text-decoration-line: none;">composing errors</a>. Implementing the&nbsp;<code style="color: #222222;">Error</code>&nbsp;trait also means that users are guaranteed the ability to obtain a string representation of an error (because it requires impls for both&nbsp;<code style="color: #222222;">fmt::Debug</code>&nbsp;and&nbsp;<code style="color: #222222;">fmt::Display</code>).</p><p style="margin-top: 0px; margin-bottom: 1rem; font-size: 1.125rem; line-height: 1.5; font-family: system-ui, &quot;Helvetica Neue&quot;, Helvetica, sans-serif; background-color: #ffffff;">Beyond that, it can also be useful to provide implementations of&nbsp;<code style="color: #222222;">From</code>&nbsp;on your error types. This allows you (the library author) and your users to&nbsp;<a href="https://blog.burntsushi.net/rust-error-handling/#composing-custom-error-types" style="color: #0096cc; text-decoration-line: none;">compose more detailed errors</a>. For example,&nbsp;<a href="https://burntsushi.net/rustdoc/csv/1.0.0-beta.5/enum.Error.html" style="color: #0096cc; text-decoration-line: none;"><code>csv::Error</code></a>&nbsp;provides&nbsp;<code style="color: #222222;">From</code>&nbsp;impls for both&nbsp;<code style="color: #222222;">io::Error</code>&nbsp;and&nbsp;<code style="color: #222222;">byteorder::Error</code>.</p><p style="margin-top: 0px; margin-bottom: 1rem; font-size: 1.125rem; line-height: 1.5; font-family: system-ui, &quot;Helvetica Neue&quot;, Helvetica, sans-serif; background-color: #ffffff;">Finally, depending on your tastes, you may also want to define a&nbsp;<a href="https://blog.burntsushi.net/rust-error-handling/#the-result-type-alias-idiom" style="color: #0096cc; text-decoration-line: none;"><code>Result</code>&nbsp;type alias</a>, particularly if your library defines a single error type. This is used in the standard library for&nbsp;<a href="http://doc.rust-lang.org/std/io/type.Result.html" style="color: #0096cc; text-decoration-line: none;"><code>io::Result</code></a>&nbsp;and&nbsp;<a href="http://doc.rust-lang.org/std/fmt/type.Result.html" style="color: #0096cc; text-decoration-line: none;"><code>fmt::Result</code></a>.<br /><br />From:&nbsp;<a href="https://blog.burntsushi.net/rust-error-handling/" style="font-family: verdana, &quot;courier new&quot;; font-size: 14px;">Error Handling in Rust - Andrew Gallant's Blog (burntsushi.net)</a></p><img src ="http://www.cppblog.com/jinq0123/aggbug/217805.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-09-02 11:24 <a href="http://www.cppblog.com/jinq0123/archive/2021/09/02/217805.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>How to show the first few errors of rustc</title><link>http://www.cppblog.com/jinq0123/archive/2021/09/01/217804.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 01 Sep 2021 02:55:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/09/01/217804.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217804.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/09/01/217804.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217804.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217804.html</trackback:ping><description><![CDATA[<div style="background-color: #ffffff; font-family: Consolas, &quot;Courier New&quot;, monospace; line-height: 19px; white-space: pre;"><div><span style="color: #800000;font-weight: bold;">#&nbsp;How&nbsp;to&nbsp;show&nbsp;the&nbsp;first&nbsp;few&nbsp;errors&nbsp;of&nbsp;rustc</span></div><br /><div>(Jin&nbsp;Qing's&nbsp;Column,&nbsp;Sep.&nbsp;1,&nbsp;2021)</div><br /><div>When&nbsp;using&nbsp;VS&nbsp;Code&nbsp;to&nbsp;develop&nbsp;Rust,&nbsp;"cargo&nbsp;check"&nbsp;output&nbsp;maybe&nbsp;thousands&nbsp;of&nbsp;lines.</div><div>Use&nbsp;"cargo&nbsp;check&nbsp;--color=always&nbsp;2&gt;&amp;1&nbsp;|&nbsp;head&nbsp;-n100"&nbsp;to&nbsp;limit&nbsp;the&nbsp;output.</div><br /><div><span style="color: #0451a5;">1.</span>&nbsp;Change&nbsp;powershell&nbsp;terminal&nbsp;to&nbsp;cmd,&nbsp;because&nbsp;powershell&nbsp;fails&nbsp;to&nbsp;use&nbsp;pipe</div><div>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0451a5;">*</span>&nbsp;Terminal&nbsp;-&gt;&nbsp;New&nbsp;Terminal&nbsp;to&nbsp;open&nbsp;a&nbsp;terminal</div><div>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0451a5;">*</span>&nbsp;Open&nbsp;the&nbsp;dropdown&nbsp;list&nbsp;by&nbsp;click&nbsp;the&nbsp;down&nbsp;arrow&nbsp;of&nbsp;"+"&nbsp;on&nbsp;the&nbsp;top-left&nbsp;of&nbsp;terminal</div><div>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0451a5;">*</span>&nbsp;Select&nbsp;"Command&nbsp;Prompt"</div><div><span style="color: #0451a5;">2.</span>&nbsp;Type&nbsp;and&nbsp;run&nbsp;command:&nbsp;<span style="color: #800000;">`cargo&nbsp;test&nbsp;2&gt;&amp;1&nbsp;--color&nbsp;always&nbsp;|&nbsp;"d:\Program&nbsp;Files\Git\usr\bin\head.exe"&nbsp;-n100`</span></div><div>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0451a5;">*</span>&nbsp;You&nbsp;should&nbsp;change&nbsp;the&nbsp;path&nbsp;of&nbsp;head.exe</div></div><img src ="http://www.cppblog.com/jinq0123/aggbug/217804.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-09-01 10:55 <a href="http://www.cppblog.com/jinq0123/archive/2021/09/01/217804.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>&amp;'a mut self is restrictive</title><link>http://www.cppblog.com/jinq0123/archive/2021/08/25/217794.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 25 Aug 2021 05:32:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/08/25/217794.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217794.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/08/25/217794.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217794.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217794.html</trackback:ping><description><![CDATA[<div style="background-color: #ffffff; font-family: Consolas, &quot;Courier New&quot;, monospace; line-height: 19px; white-space: pre;"><div><span style="color: #800000;font-weight: bold;">#&nbsp;&amp;'a&nbsp;mut&nbsp;self&nbsp;is&nbsp;restrictive</span></div><br /><div>From&nbsp;https://github.com/pretzelhammer/rust-blog/blob/master/posts/common-rust-lifetime-misconceptions.md#5-if-it-compiles-then-my-lifetime-annotations-are-correct</div><br /><div>```</div><div>#[derive(Debug)]</div><div>struct&nbsp;NumRef&lt;'a&gt;(&amp;'a&nbsp;i32);</div><br /><div>impl&lt;'a&gt;&nbsp;NumRef&lt;'a&gt;&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;my&nbsp;struct&nbsp;is&nbsp;generic&nbsp;over&nbsp;'a&nbsp;so&nbsp;that&nbsp;means&nbsp;I&nbsp;need&nbsp;to&nbsp;annotate</div><div>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;my&nbsp;self&nbsp;parameters&nbsp;with&nbsp;'a&nbsp;too,&nbsp;right?&nbsp;(answer:&nbsp;no,&nbsp;not&nbsp;right)</div><div>&nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;some_method(&amp;'a&nbsp;mut&nbsp;self)&nbsp;{}</div><div>}</div><br /><div>fn&nbsp;main()&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;mut&nbsp;num_ref&nbsp;=&nbsp;NumRef(&amp;5);</div><div>&nbsp;&nbsp;&nbsp;&nbsp;num_ref.some_method();&nbsp;//&nbsp;mutably&nbsp;borrows&nbsp;num_ref&nbsp;for&nbsp;the&nbsp;rest&nbsp;of&nbsp;its&nbsp;lifetime</div><div>&nbsp;&nbsp;&nbsp;&nbsp;num_ref.some_method();&nbsp;//&nbsp;❌</div><div>&nbsp;&nbsp;&nbsp;&nbsp;println!("{:?}",&nbsp;num_ref);&nbsp;//&nbsp;❌</div><div>}</div><div>```</div><br /><div>If&nbsp;we&nbsp;have&nbsp;some&nbsp;struct&nbsp;generic&nbsp;over&nbsp;'a&nbsp;we&nbsp;almost&nbsp;never&nbsp;want&nbsp;to&nbsp;write&nbsp;a&nbsp;method&nbsp;with&nbsp;a&nbsp;&amp;'a&nbsp;mut&nbsp;self&nbsp;receiver.&nbsp;<br />What&nbsp;we're&nbsp;communicating&nbsp;to&nbsp;Rust&nbsp;is&nbsp;"this&nbsp;method&nbsp;will&nbsp;mutably&nbsp;borrow&nbsp;the&nbsp;struct&nbsp;for&nbsp;the&nbsp;entirety&nbsp;of&nbsp;the&nbsp;struct's&nbsp;lifetime".&nbsp;<br />In&nbsp;practice&nbsp;this&nbsp;means&nbsp;Rust's&nbsp;borrow&nbsp;checker&nbsp;will&nbsp;only&nbsp;allow&nbsp;at&nbsp;most&nbsp;one&nbsp;call&nbsp;to&nbsp;some_method&nbsp;<br />before&nbsp;the&nbsp;struct&nbsp;becomes&nbsp;permanently&nbsp;mutably&nbsp;borrowed&nbsp;and&nbsp;thus&nbsp;unusable.&nbsp;<br />The&nbsp;use-cases&nbsp;for&nbsp;this&nbsp;are&nbsp;extremely&nbsp;rare&nbsp;but&nbsp;the&nbsp;code&nbsp;above&nbsp;is&nbsp;very&nbsp;easy&nbsp;for&nbsp;confused&nbsp;beginners&nbsp;to&nbsp;write&nbsp;and&nbsp;it&nbsp;compiles.&nbsp;<br />The&nbsp;fix&nbsp;is&nbsp;to&nbsp;not&nbsp;add&nbsp;unnecessary&nbsp;explicit&nbsp;lifetime&nbsp;annotations&nbsp;and&nbsp;let&nbsp;Rust's&nbsp;lifetime&nbsp;elision&nbsp;rules&nbsp;handle&nbsp;it:</div><br /><div>```</div><div>#[derive(Debug)]</div><div>struct&nbsp;NumRef&lt;'a&gt;(&amp;'a&nbsp;i32);</div><br /><div>impl&lt;'a&gt;&nbsp;NumRef&lt;'a&gt;&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;no&nbsp;more&nbsp;'a&nbsp;on&nbsp;mut&nbsp;self</div><div>&nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;some_method(&amp;mut&nbsp;self)&nbsp;{}</div><br /><div>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;above&nbsp;line&nbsp;desugars&nbsp;to</div><div>&nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;some_method_desugared&lt;'b&gt;(&amp;'b&nbsp;mut&nbsp;self){}</div><div>}</div><br /><div>fn&nbsp;main()&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;mut&nbsp;num_ref&nbsp;=&nbsp;NumRef(&amp;5);</div><div>&nbsp;&nbsp;&nbsp;&nbsp;num_ref.some_method();</div><div>&nbsp;&nbsp;&nbsp;&nbsp;num_ref.some_method();&nbsp;//&nbsp;✅</div><div>&nbsp;&nbsp;&nbsp;&nbsp;println!("{:?}",&nbsp;num_ref);&nbsp;//&nbsp;✅</div><div>}</div><div>```</div></div><img src ="http://www.cppblog.com/jinq0123/aggbug/217794.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-08-25 13:32 <a href="http://www.cppblog.com/jinq0123/archive/2021/08/25/217794.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rust callback idiom</title><link>http://www.cppblog.com/jinq0123/archive/2021/08/24/217793.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 24 Aug 2021 02:19:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/08/24/217793.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217793.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/08/24/217793.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217793.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217793.html</trackback:ping><description><![CDATA[<div style="background-color: #ffffff; font-family: Consolas, &quot;Courier New&quot;, monospace; line-height: 19px; white-space: pre;"><div><span style="color: #800000;font-weight: bold;">#&nbsp;Rust&nbsp;callback&nbsp;idiom</span></div><br /><div>Code&nbsp;is&nbsp;from:&nbsp;https://stackoverflow.com/questions/41081240/idiomatic-callbacks-in-rust</div><div>and</div><div>https://morestina.net/blog/793/closure-lifetimes-in-rust</div><br /><div>```</div><div>struct&nbsp;Processor&lt;'a&gt;&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;callback:&nbsp;Box&lt;dyn&nbsp;FnMut()&nbsp;+&nbsp;'a&gt;,</div><div>}</div><br /><div>impl&lt;'a&gt;&nbsp;Processor&lt;'a&gt;&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;new()&nbsp;-&gt;&nbsp;Processor&lt;'a&gt;&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Processor&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;callback:&nbsp;Box::new(||&nbsp;()),</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</div><div>&nbsp;&nbsp;&nbsp;&nbsp;}</div><br /><div>&nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;set_callback(&amp;mut&nbsp;self,&nbsp;c:&nbsp;impl&nbsp;FnMut()&nbsp;+&nbsp;'a)&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.callback&nbsp;=&nbsp;Box::new(c);</div><div>&nbsp;&nbsp;&nbsp;&nbsp;}</div><br /><div>&nbsp;&nbsp;&nbsp;&nbsp;fn&nbsp;process_events(&amp;mut&nbsp;self)&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(self.callback)();</div><div>&nbsp;&nbsp;&nbsp;&nbsp;}</div><div>}</div><br /><div>fn&nbsp;simple_callback()&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;println!("hello");</div><div>}</div><br /><div>fn&nbsp;main()&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;_&nbsp;=&nbsp;Processor::new();</div><div>&nbsp;&nbsp;&nbsp;&nbsp;</div><div>&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;mut&nbsp;p&nbsp;=&nbsp;Processor&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;callback:&nbsp;Box::new(simple_callback),</div><div>&nbsp;&nbsp;&nbsp;&nbsp;};</div><div>&nbsp;&nbsp;&nbsp;&nbsp;p.process_events();</div><div>&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;s&nbsp;=&nbsp;"world!".to_string();</div><div>&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;callback2&nbsp;=&nbsp;move&nbsp;||&nbsp;println!("hello&nbsp;{}",&nbsp;s);</div><div>&nbsp;&nbsp;&nbsp;&nbsp;p.set_callback(callback2);</div><div>&nbsp;&nbsp;&nbsp;&nbsp;p.process_events();</div><div>}</div><div>```</div><br /><div>Note:</div><div><span style="color: #0451a5;">*</span>&nbsp;"impl&nbsp;FnMut()"&nbsp;can&nbsp;only&nbsp;used&nbsp;in&nbsp;function&nbsp;declaration,&nbsp;not&nbsp;in&nbsp;struct&nbsp;declaration.</div><div><span style="color: #0451a5;">*</span>&nbsp;dyn&nbsp;FnMut()&nbsp;is&nbsp;unsized,&nbsp;so&nbsp;it&nbsp;must&nbsp;be&nbsp;stored&nbsp;in&nbsp;Box</div><div><span style="color: #0451a5;">*</span>&nbsp;set_callback(&amp;mut&nbsp;self,&nbsp;c:&nbsp;impl&nbsp;FnMut())&nbsp;need&nbsp;a&nbsp;lifetime&nbsp;for&nbsp;c&nbsp;to&nbsp;tell&nbsp;compiler&nbsp;that&nbsp;c&nbsp;outlives&nbsp;structure</div><div>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0451a5;">+</span>&nbsp;rustc&nbsp;suggests&nbsp;<span style="color: #800000;">`impl&nbsp;FnMut()&nbsp;+&nbsp;'static`</span>,&nbsp;but&nbsp;that&nbsp;is&nbsp;too&nbsp;restrictive</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0451a5;">-</span>&nbsp;In&nbsp;most&nbsp;cases,&nbsp;we&nbsp;do&nbsp;not&nbsp;have&nbsp;a&nbsp;static&nbsp;lifetimed&nbsp;callback</div><div><span style="color: #0451a5;">*</span>&nbsp;FnMut()&nbsp;is&nbsp;more&nbsp;restrictive&nbsp;than&nbsp;FnOnce(),&nbsp;but&nbsp;FnOnce()&nbsp;can&nbsp;only&nbsp;be&nbsp;called&nbsp;once</div><div><span style="color: #0451a5;">*</span>&nbsp;set_callback(...)&nbsp;is&nbsp;a&nbsp;template&nbsp;method,&nbsp;because&nbsp;each&nbsp;closure&nbsp;has&nbsp;a&nbsp;different&nbsp;type</div></div><img src ="http://www.cppblog.com/jinq0123/aggbug/217793.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-08-24 10:19 <a href="http://www.cppblog.com/jinq0123/archive/2021/08/24/217793.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rust variable rebinding for closure</title><link>http://www.cppblog.com/jinq0123/archive/2021/08/22/217787.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 22 Aug 2021 09:25:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/08/22/217787.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217787.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/08/22/217787.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217787.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217787.html</trackback:ping><description><![CDATA[# Rust variable rebinding for closure<br /><br />From: https://rust-unofficial.github.io/patterns/idioms/pass-var-to-closure.html<br /><br />Rust closure captures variables by reference by default.<br />You can use "move" keyword to change to move variables.<br />In most cases, some variables are moved, and some are referenced.<br />We can rebind variables in a separate scope before move to the closure.<br /><br />```<br />use std::rc::Rc;<br /><br />let num1 = Rc::new(1);<br />let num2 = Rc::new(2);<br />let num3 = Rc::new(3);<br />let closure = {<br />&nbsp;&nbsp;&nbsp; // `num1` is moved<br />&nbsp;&nbsp;&nbsp; let num2 = num2.clone();&nbsp; // `num2` is cloned<br />&nbsp;&nbsp;&nbsp; let num3 = num3.as_ref();&nbsp; // `num3` is borrowed<br />&nbsp;&nbsp;&nbsp; move || {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *num1 + *num2 + *num3;<br />&nbsp;&nbsp;&nbsp; }<br />};<br />```<br /><br />Or we can use additional variables to move in the same scope:<br />```<br />let num2_clone = num2.clone();<br />let num3_ref = num3.as_ref();<br />let closure = move || {<br />&nbsp;&nbsp;&nbsp; *num1 + *num2_clone + *num3_ref<br />}<br />```<br /><br />Using separate scope can reuse the variable name, which make the closure body clearer,<br />but need additional indent.<img src ="http://www.cppblog.com/jinq0123/aggbug/217787.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-08-22 17:25 <a href="http://www.cppblog.com/jinq0123/archive/2021/08/22/217787.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rust Deref coercion example</title><link>http://www.cppblog.com/jinq0123/archive/2021/08/22/217786.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 22 Aug 2021 04:31:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/08/22/217786.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217786.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/08/22/217786.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217786.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217786.html</trackback:ping><description><![CDATA[# Rust Deref coercion example<br /><br />https://doc.rust-lang.org/std/ops/trait.Deref.html<br /><br />```<br />use std::ops::Deref;<br /><br />struct DerefExample&lt;T&gt; {<br />&nbsp;&nbsp;&nbsp; value: T<br />}<br /><br />impl&lt;T&gt; Deref for DerefExample&lt;T&gt; {<br />&nbsp;&nbsp;&nbsp; type Target = T;<br /><br />&nbsp;&nbsp;&nbsp; fn deref(&amp;self) -&gt; &amp;Self::Target {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;self.value<br />&nbsp;&nbsp;&nbsp; }<br />}<br /><br />let x = DerefExample { value: 'a' };<br />assert_eq!('a', *x);<br />```<br /><br />Deref coercion can be used in newtype:<br />```<br />struct MyI32(i32)<br /><br />impl Deref for MyI32 {<br />&nbsp;&nbsp;&nbsp; type Target = i32;<br />&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; fn deref(&amp;self) -&gt; &amp;Self::Target {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;self.0<br />&nbsp;&nbsp;&nbsp; }<br />}<br />```<br /><img src ="http://www.cppblog.com/jinq0123/aggbug/217786.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-08-22 12:31 <a href="http://www.cppblog.com/jinq0123/archive/2021/08/22/217786.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rust Error Return Check Policy</title><link>http://www.cppblog.com/jinq0123/archive/2021/08/09/217775.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 09 Aug 2021 09:08:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/08/09/217775.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217775.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/08/09/217775.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217775.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217775.html</trackback:ping><description><![CDATA[<h3>Error Return Check Policy<a href="https://www.ockam.io/learn/how-to-guides/contributing/ockam_rust_code_standard#error-return-check-policy" style="box-sizing: border-box; vertical-align: baseline; text-decoration-line: none; outline: none;"></a></h3><ul e801dxl0"="" style="box-sizing: border-box; vertical-align: baseline; list-style: initial; padding-left: 1.6rem; color: #3c454e; font-family: &quot;IBM Plex Sans&quot;, sans-serif; font-size: 16px; background-color: #ffffff;"><li style="box-sizing: border-box; vertical-align: baseline; margin-bottom: 0.4rem; margin-top: 0px; margin-left: 0px; padding-left: 0px; line-height: 1.5;">Never use&nbsp;<code e1q2in260"="" style="box-sizing: border-box; font-family: &quot;IBM Plex Sans&quot;, sans-serif; font-size: 1.2rem; vertical-align: baseline; background: #e6ecf1; border-radius: 0.2rem; padding: 0.5rem 1rem; font-weight: 700;">unwrap</code>&nbsp;on&nbsp;<span e9jhbpx0"="" style="box-sizing: border-box; vertical-align: baseline;">Result</span>. If the type is&nbsp;<em style="box-sizing: border-box; vertical-align: baseline;">Err</em>, it will panic and crash the program. The only exception is if it has already been checked for error previously or in test code.</li><li style="box-sizing: border-box; vertical-align: baseline; margin-bottom: 0.4rem; margin-top: 0px; margin-left: 0px; padding-left: 0px; line-height: 1.5;">Never use&nbsp;<code e1q2in260"="" style="box-sizing: border-box; font-family: &quot;IBM Plex Sans&quot;, sans-serif; font-size: 1.2rem; vertical-align: baseline; background: #e6ecf1; border-radius: 0.2rem; padding: 0.5rem 1rem; font-weight: 700;">unwrap</code>&nbsp;on&nbsp;<span e9jhbpx0"="" style="box-sizing: border-box; vertical-align: baseline;">Option</span>&nbsp;for the same reason if the type is&nbsp;<em style="box-sizing: border-box; vertical-align: baseline;">None</em>&nbsp;as&nbsp;<span e9jhbpx0"="" style="box-sizing: border-box; vertical-align: baseline;">Result</span>&nbsp;is&nbsp;<em style="box-sizing: border-box; vertical-align: baseline;">Err</em>.</li></ul><img src ="http://www.cppblog.com/jinq0123/aggbug/217775.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-08-09 17:08 <a href="http://www.cppblog.com/jinq0123/archive/2021/08/09/217775.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rust visibility</title><link>http://www.cppblog.com/jinq0123/archive/2021/08/09/217774.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 09 Aug 2021 05:45:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/08/09/217774.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217774.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/08/09/217774.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217774.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217774.html</trackback:ping><description><![CDATA[From:&nbsp;<a href="https://doc.rust-lang.org/reference/visibility-and-privacy.html">Visibility and privacy - The Rust Reference (rust-lang.org)</a><br /><h2><a href="https://doc.rust-lang.org/reference/visibility-and-privacy.html#pubin-path-pubcrate-pubsuper-and-pubself" style="text-decoration-line: none;"><code style="font-size: unset; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important;">pub(in path)</code>,&nbsp;<code style="font-size: unset; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important;">pub(crate)</code>,&nbsp;<code style="font-size: unset; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important;">pub(super)</code>, and&nbsp;<code style="font-size: unset; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important;">pub(self)</code></a></h2><p style="line-height: 1.45em; font-family: &quot;Open Sans&quot;, sans-serif; font-size: 16px; background-color: #ffffff;">In addition to public and private, Rust allows users to declare an item as visible only within a given scope. The rules for&nbsp;<code style="font-size: 0.875em; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important; display: inline; overflow-x: initial; background: #f6f7f6; color: var(--inline-code-color); padding: 0.1em 0.3em; border-radius: 3px;">pub</code>&nbsp;restrictions are as follows:</p><ul style="line-height: 1.45em; font-family: &quot;Open Sans&quot;, sans-serif; font-size: 16px; background-color: #ffffff;"><li><code style="font-size: 0.875em; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important; display: inline; overflow-x: initial; background: #f6f7f6; color: var(--inline-code-color); padding: 0.1em 0.3em; border-radius: 3px;">pub(in path)</code>&nbsp;makes an item visible within the provided&nbsp;<code style="font-size: 0.875em; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important; display: inline; overflow-x: initial; background: #f6f7f6; color: var(--inline-code-color); padding: 0.1em 0.3em; border-radius: 3px;">path</code>.&nbsp;<code style="font-size: 0.875em; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important; display: inline; overflow-x: initial; background: #f6f7f6; color: var(--inline-code-color); padding: 0.1em 0.3em; border-radius: 3px;">path</code>&nbsp;must be an ancestor module of the item whose visibility is being declared.</li><li><code style="font-size: 0.875em; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important; display: inline; overflow-x: initial; background: #f6f7f6; color: var(--inline-code-color); padding: 0.1em 0.3em; border-radius: 3px;">pub(crate)</code>&nbsp;makes an item visible within the current crate.</li><li><code style="font-size: 0.875em; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important; display: inline; overflow-x: initial; background: #f6f7f6; color: var(--inline-code-color); padding: 0.1em 0.3em; border-radius: 3px;">pub(super)</code>&nbsp;makes an item visible to the parent module. This is equivalent to&nbsp;<code style="font-size: 0.875em; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important; display: inline; overflow-x: initial; background: #f6f7f6; color: var(--inline-code-color); padding: 0.1em 0.3em; border-radius: 3px;">pub(in super)</code>.</li><li><code style="font-size: 0.875em; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important; display: inline; overflow-x: initial; background: #f6f7f6; color: var(--inline-code-color); padding: 0.1em 0.3em; border-radius: 3px;">pub(self)</code>&nbsp;makes an item visible to the current module. This is equivalent to&nbsp;<code style="font-size: 0.875em; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important; display: inline; overflow-x: initial; background: #f6f7f6; color: var(--inline-code-color); padding: 0.1em 0.3em; border-radius: 3px;">pub(in self)</code>&nbsp;or not using&nbsp;<code style="font-size: 0.875em; font-family: &quot;Source Code Pro&quot;, Consolas, &quot;Ubuntu Mono&quot;, Menlo, &quot;DejaVu Sans Mono&quot;, monospace, monospace !important; display: inline; overflow-x: initial; background: #f6f7f6; color: var(--inline-code-color); padding: 0.1em 0.3em; border-radius: 3px;">pub</code>&nbsp;at all.</li></ul><img src ="http://www.cppblog.com/jinq0123/aggbug/217774.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-08-09 13:45 <a href="http://www.cppblog.com/jinq0123/archive/2021/08/09/217774.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Why does Rust check borrow even in single thread</title><link>http://www.cppblog.com/jinq0123/archive/2021/08/07/217773.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sat, 07 Aug 2021 08:05:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/08/07/217773.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217773.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/08/07/217773.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217773.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217773.html</trackback:ping><description><![CDATA[<div style="background-color: #ffffff; font-family: Consolas, &quot;Courier New&quot;, monospace; line-height: 19px; white-space: pre;"><div><span style="color: #800000;font-weight: bold;">#&nbsp;Why&nbsp;does&nbsp;Rust&nbsp;check&nbsp;borrow&nbsp;even&nbsp;in&nbsp;single&nbsp;thread</span></div><br /><div>(Jin&nbsp;Qing's&nbsp;Column,&nbsp;Aug.&nbsp;7,&nbsp;2021)</div><br /><div>The&nbsp;Rust&nbsp;book&nbsp;says&nbsp;borrow&nbsp;checking&nbsp;is&nbsp;to&nbsp;prevent&nbsp;data&nbsp;race.</div><div>But&nbsp;the&nbsp;borrow&nbsp;checker&nbsp;forbids&nbsp;multiply&nbsp;mutable&nbsp;borrows&nbsp;even&nbsp;in&nbsp;the&nbsp;same&nbsp;thread.</div><div>Is&nbsp;there&nbsp;data&nbsp;race&nbsp;in&nbsp;single&nbsp;thread?</div><div>Why&nbsp;does&nbsp;the&nbsp;borrow&nbsp;checker&nbsp;forbid&nbsp;it&nbsp;in&nbsp;the&nbsp;same&nbsp;thread?</div><br /><div>[<span style="color: #a31515;">The&nbsp;Problem&nbsp;With&nbsp;Single-threaded&nbsp;Shared&nbsp;Mutability</span>](<span style="text-decoration-line: underline;">https://manishearth.github.io/blog/2015/05/17/the-problem-with-shared-mutability/</span>)</div><div>answers&nbsp;this&nbsp;question.</div><br /><div>It&nbsp;gaves&nbsp;2&nbsp;cases&nbsp;that&nbsp;shared&nbsp;mutability&nbsp;causes&nbsp;prolem.</div><div>One&nbsp;is&nbsp;Rust&nbsp;enum&nbsp;variable,&nbsp;which&nbsp;can&nbsp;has&nbsp;different&nbsp;inner&nbsp;type.</div><div>If&nbsp;the&nbsp;inner&nbsp;type&nbsp;changed,&nbsp;the&nbsp;references&nbsp;to&nbsp;the&nbsp;old&nbsp;data&nbsp;would&nbsp;be&nbsp;invalidated.</div><div>Another&nbsp;case&nbsp;is&nbsp;Iterator&nbsp;invalidation&nbsp;that&nbsp;the&nbsp;container's&nbsp;change&nbsp;can&nbsp;invalidate&nbsp;the&nbsp;Iterator.</div><br /><br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/217773.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-08-07 16:05 <a href="http://www.cppblog.com/jinq0123/archive/2021/08/07/217773.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UE4 Blueprint Multiple Event BeginPlay</title><link>http://www.cppblog.com/jinq0123/archive/2021/07/31/217765.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sat, 31 Jul 2021 07:19:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/07/31/217765.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217765.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/07/31/217765.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217765.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217765.html</trackback:ping><description><![CDATA[# Multiple Event BeginPlay<br /><br />(金庆的专栏 2021.7)<br /><br />How to do multiple actions on Event BeginPlay in UE4 Blueprints?<br /><br />Sams-Teach-Yourself-Unreal-Engine-4-Game-Development-in-24-Hours says:<br />```<br />Q. When I try to add a second event node, BeginPlay, the Editor shows me the first one already<br />placed in the Event Graph. Why does this happen?<br /><br />A. Some events, such as Event Tick and the BeginPlay event, can have only one instance per<br />Blueprint. <br />```<br /><br />https://forums.unrealengine.com/t/do-multiple-things-on-event-begin-play/411/10<br />```<br />The Sequence node allows for a single execution pulse to trigger a series of events in order. The node may have any number of outputs, all of which get called as soon as the Sequence node receives an input. They will always get called in order, but without any delay. To a typical user, the outputs will likely appear to have been triggered simultaneously.<br />```<br /><br />Youtube video: [How to do Multiple Actions on Event Begin Play Unreal Engine 4 Blueprints](https://www.youtube.com/watch?v=nqG-ztbs230)<img src ="http://www.cppblog.com/jinq0123/aggbug/217765.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-07-31 15:19 <a href="http://www.cppblog.com/jinq0123/archive/2021/07/31/217765.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual Studio 2019 Compiler Hangs</title><link>http://www.cppblog.com/jinq0123/archive/2021/07/31/217764.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sat, 31 Jul 2021 07:16:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/07/31/217764.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217764.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/07/31/217764.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217764.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217764.html</trackback:ping><description><![CDATA[# Visual Studio 2019 Compiler Hangs<br /><br />(金庆的专栏 2021.7)<br /><br />Discovered by my colleague Shen Yichai:<br />```<br />Share a interesting MS Build bug:<br />For file a.cpp, enable optimization for Win64 or XSX. <br />The MSBuild always compiling without error and ending (infinite compile). <br />The PS5 (clang) does not have this issue.<br />```<br /><br />The simplified code:<br />```<br /><span style="color: #800000; font-family: Courier;">struct Tag</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;int v;</span><br /><span style="color: #800000; font-family: Courier;">};</span><br /><br /><span style="color: #800000; font-family: Courier;">void Goo(Tag* r, Tag* a)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;r-&gt;v = a-&gt;v;</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">void Foo(Tag* pos0, Tag* pos)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;for (int j = 0; j &lt; 4; j++)</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; if (j == 0) {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; 8; i++) {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Goo(pos0++, pos);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Goo(pos0++, pos);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; else {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; 8; i++) {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Goo(pos0++, pos);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Goo(pos0++, pos);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">int main()</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;Foo(nullptr, nullptr);</span><br /><span style="color: #800000; font-family: Courier;">}</span><br />```<br /><br />The default release configuration can build correctly.<br />But if "Properties -&gt; C/C++ -&gt; Optimization -&gt; Whole Program optimization" (/GL) of file or project is changed to "No", <br />the compilation will take a long time as 5 minutes.<br /><br />```<br />Microsoft Visual Studio Community 2019<br />Version 16.9.5<br />VisualStudio.16.Release/16.9.5+31229.75<br />Microsoft .NET Framework<br />Version 4.8.04084<br />```<img src ="http://www.cppblog.com/jinq0123/aggbug/217764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-07-31 15:16 <a href="http://www.cppblog.com/jinq0123/archive/2021/07/31/217764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fbx File Format Identifier</title><link>http://www.cppblog.com/jinq0123/archive/2021/05/30/217692.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 30 May 2021 01:55:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/05/30/217692.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217692.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/05/30/217692.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217692.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217692.html</trackback:ping><description><![CDATA[# Fbx File Format Identifier<br /><br />(金庆的专栏 2021.5)<br /><br />Print the list of FBX file format identifiers.<br /><br />FBX SDK FbxExporter can set the file format identifier which is an int parameter.<br />The commnet says: User does not need to specify it by default.<br />If not specified, plugin will detect the file format according to file suffix automatically.<br /><br />FBX SDK 2020 automatically set it to the latest binary format, which can not be parsed by "Autodesk FBX Converter 2013".<br />We need to specify the format identifier for FBX Converter 2013.<br />But there is no specification of this parameter.<br />We use the following code to display all the valid format identifiers and their descriptions.<br /><br />```<br />#include &lt;fbxsdk.h&gt;<br />#include &lt;cassert&gt;<br /><br />int main()<br />{<br />&nbsp;&nbsp;&nbsp; FbxManager* myManager = FbxManager::Create();<br />&nbsp;&nbsp;&nbsp; assert(myManager);<br /><br />&nbsp;&nbsp;&nbsp; FbxIOSettings* ios = FbxIOSettings::Create(myManager, IOSROOT);<br />&nbsp;&nbsp;&nbsp; myManager-&gt;SetIOSettings(ios);<br /><br />&nbsp;&nbsp;&nbsp; int lFormatCount = myManager-&gt;GetIOPluginRegistry()-&gt;GetWriterFormatCount();<br />&nbsp;&nbsp;&nbsp; for (int lFormatIndex = 0; lFormatIndex &lt; lFormatCount; lFormatIndex++)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FbxString lDesc = myManager-&gt;GetIOPluginRegistry()-&gt;GetWriterFormatDescription(lFormatIndex);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("Format index %d: %s\n", lFormatIndex, (const char*)lDesc);<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; return 0;<br />}<br />```<br /><br />Output:<br />```<br />Format index 0: FBX binary (*.fbx)<br />Format index 1: FBX ascii (*.fbx)<br />Format index 2: FBX encrypted (*.fbx)<br />Format index 3: FBX 6.0 binary (*.fbx)<br />Format index 4: FBX 6.0 ascii (*.fbx)<br />Format index 5: FBX 6.0 encrypted (*.fbx)<br />Format index 6: AutoCAD DXF (*.dxf)<br />Format index 7: Alias OBJ (*.obj)<br />Format index 8: Collada DAE (*.dae)<br />Format index 9: Biovision BVH (*.bvh)<br />Format index 10: Motion Analysis HTR (*.htr)<br />Format index 11: Motion Analysis TRC (*.trc)<br />Format index 12: Acclaim ASF (*.asf)<br />Format index 13: Acclaim AMC (*.amc)<br />Format index 14: Vicon C3D (*.c3d)<br />Format index 15: Adaptive Optics AOA (*.aoa)<br />Format index 16: Superfluo MCD (*.mcd)<br />```<br /><br />FBX Converter 2013 will error "File is corrupted" for files exported as *.fbx file format: -1, 0, 2, 5.<br />Ascii format (1, 4) and FBX 6.0 binary (3) are OK.<br /><img src ="http://www.cppblog.com/jinq0123/aggbug/217692.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-05-30 09:55 <a href="http://www.cppblog.com/jinq0123/archive/2021/05/30/217692.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第9代游戏主机</title><link>http://www.cppblog.com/jinq0123/archive/2021/05/09/217680.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 09 May 2021 12:44:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/05/09/217680.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217680.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/05/09/217680.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217680.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217680.html</trackback:ping><description><![CDATA[# 第9代游戏主机<br /><br />原文：[Ninth generation of video game consoles](https://en.wikipedia.org/wiki/Ninth_generation_of_video_game_consoles)<br /><br />2020.11，微软(MS) Xbox Series X/S 和 Sony PlayStation 5 (PS5) 发布，标志着游戏主机进入第9代。<br /><br />和前代的 Xbox One 和 PS4 相比，新一代主机有可观的性能提升，支持实时光线跟踪，4K分辨率，目标帧率为60。<br />内部都使用了固态硬盘(SSD)。低配版没有光驱，仅支持网络和USB。<br /><br />定位上要胜过任天堂Switch和云游戏服务如 Stadia 和 Amazon Luna.<br /><br />## 背景<br /><br />第8代时间较长。因为摩尔定律，过去几代一般每代为5年时间，但是 MS 和 Sony 出了中间代产品 Xbox One X 和 PS4 Pro.<br /><br />2020.3 开始的 COVID-19 疫情影响也使新一代主机的发布延后了。<br /><br />## 主要主机<br /><br />### PS5<br /><br />有2个机型，基本型和数字型，数字型没有光驱较便宜，其他一样。<br />PS5和PS4的游戏兼容，只有少量游戏不支持，但是可以通过 PS Now 云游戏服务玩 PS4 游戏。<br /><br />### Xbox Series X/S<br /><br />MS 延继了双主机模式：高端的X系列和低端的S系列。S系列没有光驱。<br />两者都支持外部存储和Xbox Live在线分发。向后兼容以前的游戏，但不包括Kinect游戏。<br />MS鼓励开发商使用 Smart Delivery，把Xbox One游戏升级到Xbox Series X/S。<br /><br />## 其他主机<br /><br />* 任天堂 Switch<br />* 云游戏平台：Stadia, Amazon Luna, GeForce Now<img src ="http://www.cppblog.com/jinq0123/aggbug/217680.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-05-09 20:44 <a href="http://www.cppblog.com/jinq0123/archive/2021/05/09/217680.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Canvas Scaler 的3种模式</title><link>http://www.cppblog.com/jinq0123/archive/2021/03/02/217621.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 02 Mar 2021 04:00:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/03/02/217621.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217621.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/03/02/217621.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217621.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217621.html</trackback:ping><description><![CDATA[Canvas Scaler 的3种模式<br /><br />(金庆的专栏 2021.3)<br /><br />参考：<br />https://wenku.baidu.com/view/83991090336c1eb91b375db8.html<br /><br />Unity Canvas 有个 Canvas Scaler 组件，用来决定 Canvas 的 Scale(缩放)值。<br />Scale 有 X,Y,Z 3个分量，都是同一值，即在各个方向上都是同倍率缩放的。<br />它有3种Scale Mode。<br /><br />因为设计时的宽高比与目标机型宽高比不同，Canvas 需要先增减为目标高宽比，然后再缩放。<br />Canvas 缩放并不影响UI元素的相互位置，只是同比缩放。<br />但是高宽比调整时会造成UI元素的相对位置变化，如宽度增大后，UI元素会在宽度方向上相互散开。<br /><br />可以在 Unity Editor Game 页左上角分辨率下拉菜单中创建几个低分辨率屏，用来测试屏幕大小切换。<br />测试界面可放置2个按钮，一个锚定到左上，位于左上，一个锚定到右下，位于右下，不要strech。<br /><br />3种模式如下。<br /><br />## Constance Pixel Size<br /><br />Constance Pixel Size 模式下，Scale 总是为1。<br />目标机上的 Canvas 就是其分辨率大小。<br />因为设计时分辨率与实际分辨率不同，显示会不同。<br />但是图片和按钮的大小保持固定像素大小。<br />如果屏幕变大，UI元素就会相互散开，变小则聚拢。<br />如果需要缩放，只能通过程序调节。<br /><br />## Scale With Screen Size<br /><br />随屏幕大小缩放。<br />该模式下有个 Reference Resolution (参考分辨率)，应该设为主流机型的分辨率。<br />在主流机型下，Scale 为1，与设计显示相同。<br /><br />https://blog.csdn.net/u011948420/article/details/112641308<br />2020中国移动游戏质量白皮书-WeTest 报告 Android 手机 TOP300 分辨率为 2340*1080 占 31%。<br /><br />如果目标机型为 4680*2160，则 Scale 正好为2；如果目标机型为 1179*540，则Scale为0.5.<br /><br />一般情况下宽高比不同，此时Scale算法有3种，即3种Sceen Match Mode：<br /><br />### Match Width Or Height<br /><br />匹配宽度或高度。<br /><br />此时有个 Match 划动条，可以在 Width(0)..Height(1)之间。<br />如果为0，匹配宽度，则 Scale 为目标屏宽与参考屏宽之比；<br />如果为1，匹配高度，则 Scale 为目标屏高与参考屏高之比；<br />如果为0.5, 加权匹配，则是这2个比值的平均值。<br /><br />匹配宽度时，高度方向上会有UI扩散或聚拢。<br />匹配高度时，宽度方向上会有UI扩散或聚拢。<br />加权匹配时，UI在高上扩散宽上聚拢，或者在高上聚拢宽上扩散。<br /><br />### Expand<br /><br />增加。先增加宽或高到目标宽高比。该增加方向UI元素会散开。<br /><br />### Shrink<br /><br />减少。先减少宽或高到目标宽高比。该减少方向UI元素会聚拢。<br /><br />## Constant Physical Size<br /><br />固定物理大小。<br />随着4k屏的出现，屏幕DPI会很大，许多设备的像素点非常小。<br />同样的按钮，在高DPI下，如果固定像素大小，则会非常小，这时适合用该模式。<br /><br /><img src ="http://www.cppblog.com/jinq0123/aggbug/217621.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-03-02 12:00 <a href="http://www.cppblog.com/jinq0123/archive/2021/03/02/217621.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C#异步方法返回void和Task的区别</title><link>http://www.cppblog.com/jinq0123/archive/2021/02/25/217618.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 25 Feb 2021 02:38:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/02/25/217618.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217618.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/02/25/217618.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217618.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217618.html</trackback:ping><description><![CDATA[# C#异步方法返回void和Task的区别<br /><br />(金庆的专栏 2021.2)<br /><br />如果异步(async关键字)方法有返回值，返回类型为T时，返回类型必然是 `Task&lt;T&gt;`。<br />但是如果没有返回值，异步方法的返回类型有2种，一个是返回 Task, 一个是返回 void：<br />```<br />&nbsp;&nbsp;&nbsp; public async Task CountDownAsync(int count)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = count; i &gt;= 0; i--)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; await Task.Delay(1000); <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br /><br />&nbsp;&nbsp;&nbsp; public async void CountDown(int count)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = count; i &gt;= 0; i--)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; await Task.Delay(1000);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />```<br /><br />调用时，如果返回 Task, 但返回值被忽略时，VS 会用绿色波浪线警告：<br />```<br />&nbsp;&nbsp;&nbsp; CountDownAsync(3);<br />&nbsp;&nbsp;&nbsp; ~~~~~~~~~~~~~~~~~<br />```<br /><br />信息为：<br />```<br />(awaitable) Task AsyncExample.CountDownAsync(int count)<br /><br />Usage:<br />&nbsp;await CountDownAsync(...);<br /><br />Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.<br />```<br /><br />中文为：<br />```<br />CS4014:由于此调用不会等待，因此在此调用完成之前将会继续执行当前方法。请考虑将"await"运算符应用于调用结果。<br />```<br /><br />添加 await 后就正常了：<br />```<br />&nbsp;&nbsp;&nbsp; await CountDownAsync(3);<br />```<br /><br />如果调用者不是一个异步方法，因为只有在异步方法中才可以使用 await,<br />或者并不想在此等待，如想同时执行多个 CountDownAsync(),<br />就不能应用 await 来消除警告。<br /><br />此时可以改用 void 返回值的版本：<br />```<br />void Test()<br />{<br />&nbsp;&nbsp;&nbsp; ...<br />&nbsp;&nbsp;&nbsp; CountDown(3);<br />&nbsp;&nbsp;&nbsp; CountDown(3);<br />&nbsp;&nbsp;&nbsp; ...<br />}<br /><br />async void CountDown(int count)<br />{<br />&nbsp;&nbsp;&nbsp; for (int i = count; i &gt;= 0; i--)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; await Task.Delay(1000);<br />&nbsp;&nbsp;&nbsp; }<br />}<br />```<br /><br />&gt; Never call `async Task` methods without also awaiting on the returned Task. If you don&#8217;t want to wait for the async behaviour to complete, you should call an `async void` method instead.<br /><br />摘自：http://www.stevevermeulen.com/index.php/2017/09/using-async-await-in-unity3d-2017/<br /><br />CountDown() 可以直接调用 CountDownAsync() 实现：<br />```<br />async void CountDown(int count)<br />{<br />&nbsp;&nbsp;&nbsp; await CountDownAsync(count);<br />}<br />```<br /><br />使用下划线变量忽略异步方法的返回值也可以消除警告：<br />```<br />void Test()<br />{<br />&nbsp;&nbsp;&nbsp; ...<br />&nbsp;&nbsp;&nbsp; _ = CountDownAsync(3);<br />&nbsp;&nbsp;&nbsp; _ = CountDownAsync(3);<br />&nbsp;&nbsp;&nbsp; ...<br />}<br />```<br /><br />但是这样同时也会忽略 CountDownAsync() 中的异常。如以下异常会被忽略。<br /><br />```<br />void Test()<br />{<br />&nbsp;&nbsp;&nbsp; ...<br />&nbsp;&nbsp;&nbsp; _ = CountDownAsync(3);<br />&nbsp;&nbsp;&nbsp; ...<br />}<br /><br />async Task CountDownAsync(int count)<br />{<br />&nbsp;&nbsp;&nbsp; for (int i = count; i &gt;= 0; i--)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; await Task.Delay(1000); <br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; throw new Exception();<br />}<br />```<br /><br />如果是调用返回 void 的异步方法，Unity 会报错：<br />```<br />Exception: Exception of type 'System.Exception' was thrown.<br />```<br /><br />## 对 Async 后缀的说明<br /><br />```<br />You could say that the Async suffix convention is to communicate to the API user that the method is awaitable. For a method to be awaitable, it must return Task for a void, or Task&lt;T&gt; for a value-returning method, which means only the latter can be suffixed with Async.<br />```<br /><br />摘自：https://stackoverflow.com/questions/15951774<br /><br />grpc 生成的代码中，异步请求返回了一个 AsyncCall 对象，AsyncCall 实现了 GetAwaiter() 接口：<br />```<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public virtual grpc::AsyncUnaryCall&lt;global::Routeguide.Feature&gt; GetFeatureAsync(global::Routeguide.Point request, ...)<br />```<br /><br />可以这样调用并等待：<br />```<br />&nbsp;&nbsp;&nbsp; var resp = await client.GetFeatureAsync(req);<br />```<br /><br />虽然返回类型不是`Task&lt;&gt;`, 但是可等待，所以添加了 Async 后缀。<br /><img src ="http://www.cppblog.com/jinq0123/aggbug/217618.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-02-25 10:38 <a href="http://www.cppblog.com/jinq0123/archive/2021/02/25/217618.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>