1
0
mirror of https://github.com/actix/actix-extras.git synced 2025-03-28 15:08:39 +01:00

768 lines
50 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `actix-session/src/lib.rs`."><meta name="keywords" content="rust, rustlang, rust-lang"><title>lib.rs - source</title><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceSerif4-Regular.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../FiraSans-Regular.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../FiraSans-Medium.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceCodePro-Regular.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceSerif4-Bold.ttf.woff2"><link rel="preload" as="font" type="font/woff2" crossorigin href="../../SourceCodePro-Semibold.ttf.woff2"><link rel="stylesheet" type="text/css" href="../../normalize.css"><link rel="stylesheet" type="text/css" href="../../rustdoc.css" id="mainThemeStyle"><link rel="stylesheet" type="text/css" href="../../ayu.css" disabled><link rel="stylesheet" type="text/css" href="../../dark.css" disabled><link rel="stylesheet" type="text/css" href="../../light.css" id="themeStyle"><script id="default-settings" ></script><script src="../../storage.js"></script><script src="../../crates.js"></script><script defer src="../../main.js"></script><script defer src="../../source-script.js"></script><script defer src="../../source-files.js"></script>
<noscript><link rel="stylesheet" href="../../noscript.css"></noscript><link rel="alternate icon" type="image/png" href="../../favicon-16x16.png"><link rel="alternate icon" type="image/png" href="../../favicon-32x32.png"><link rel="icon" type="image/svg+xml" href="../../favicon.svg"></head><body class="rustdoc source"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle">&#9776;</button><a class="sidebar-logo" href="../../actix_session/index.html"><div class="logo-container"><img class="rust-logo" src="../../rust-logo.svg" alt="logo"></div>
</a><h2 class="location"></h2>
</nav>
<nav class="sidebar"><a class="sidebar-logo" href="../../actix_session/index.html"><div class="logo-container"><img class="rust-logo" src="../../rust-logo.svg" alt="logo"></div>
</a></nav><main><div class="width-limiter"><div class="sub-container"><a class="sub-logo-container" href="../../actix_session/index.html"><img class="rust-logo" src="../../rust-logo.svg" alt="logo"></a><nav class="sub"><div class="theme-picker hidden"><button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"><img width="22" height="22" alt="Pick another theme!" src="../../brush.svg"></button><div id="theme-choices" role="menu"></div></div><form class="search-form"><div class="search-container"><span></span><input class="search-input" name="search" autocomplete="off" spellcheck="false" placeholder="Click or press S to search, ? for more options…" type="search"><button type="button" id="help-button" title="help">?</button><a id="settings-menu" href="../../settings.html" title="settings"><img width="22" height="22" alt="Change settings" src="../../wheel.svg"></a></div></form></nav></div><section id="main-content" class="content"><div class="example-wrap"><pre class="line-numbers"><span id="1"> 1</span>
<span id="2"> 2</span>
<span id="3"> 3</span>
<span id="4"> 4</span>
<span id="5"> 5</span>
<span id="6"> 6</span>
<span id="7"> 7</span>
<span id="8"> 8</span>
<span id="9"> 9</span>
<span id="10"> 10</span>
<span id="11"> 11</span>
<span id="12"> 12</span>
<span id="13"> 13</span>
<span id="14"> 14</span>
<span id="15"> 15</span>
<span id="16"> 16</span>
<span id="17"> 17</span>
<span id="18"> 18</span>
<span id="19"> 19</span>
<span id="20"> 20</span>
<span id="21"> 21</span>
<span id="22"> 22</span>
<span id="23"> 23</span>
<span id="24"> 24</span>
<span id="25"> 25</span>
<span id="26"> 26</span>
<span id="27"> 27</span>
<span id="28"> 28</span>
<span id="29"> 29</span>
<span id="30"> 30</span>
<span id="31"> 31</span>
<span id="32"> 32</span>
<span id="33"> 33</span>
<span id="34"> 34</span>
<span id="35"> 35</span>
<span id="36"> 36</span>
<span id="37"> 37</span>
<span id="38"> 38</span>
<span id="39"> 39</span>
<span id="40"> 40</span>
<span id="41"> 41</span>
<span id="42"> 42</span>
<span id="43"> 43</span>
<span id="44"> 44</span>
<span id="45"> 45</span>
<span id="46"> 46</span>
<span id="47"> 47</span>
<span id="48"> 48</span>
<span id="49"> 49</span>
<span id="50"> 50</span>
<span id="51"> 51</span>
<span id="52"> 52</span>
<span id="53"> 53</span>
<span id="54"> 54</span>
<span id="55"> 55</span>
<span id="56"> 56</span>
<span id="57"> 57</span>
<span id="58"> 58</span>
<span id="59"> 59</span>
<span id="60"> 60</span>
<span id="61"> 61</span>
<span id="62"> 62</span>
<span id="63"> 63</span>
<span id="64"> 64</span>
<span id="65"> 65</span>
<span id="66"> 66</span>
<span id="67"> 67</span>
<span id="68"> 68</span>
<span id="69"> 69</span>
<span id="70"> 70</span>
<span id="71"> 71</span>
<span id="72"> 72</span>
<span id="73"> 73</span>
<span id="74"> 74</span>
<span id="75"> 75</span>
<span id="76"> 76</span>
<span id="77"> 77</span>
<span id="78"> 78</span>
<span id="79"> 79</span>
<span id="80"> 80</span>
<span id="81"> 81</span>
<span id="82"> 82</span>
<span id="83"> 83</span>
<span id="84"> 84</span>
<span id="85"> 85</span>
<span id="86"> 86</span>
<span id="87"> 87</span>
<span id="88"> 88</span>
<span id="89"> 89</span>
<span id="90"> 90</span>
<span id="91"> 91</span>
<span id="92"> 92</span>
<span id="93"> 93</span>
<span id="94"> 94</span>
<span id="95"> 95</span>
<span id="96"> 96</span>
<span id="97"> 97</span>
<span id="98"> 98</span>
<span id="99"> 99</span>
<span id="100">100</span>
<span id="101">101</span>
<span id="102">102</span>
<span id="103">103</span>
<span id="104">104</span>
<span id="105">105</span>
<span id="106">106</span>
<span id="107">107</span>
<span id="108">108</span>
<span id="109">109</span>
<span id="110">110</span>
<span id="111">111</span>
<span id="112">112</span>
<span id="113">113</span>
<span id="114">114</span>
<span id="115">115</span>
<span id="116">116</span>
<span id="117">117</span>
<span id="118">118</span>
<span id="119">119</span>
<span id="120">120</span>
<span id="121">121</span>
<span id="122">122</span>
<span id="123">123</span>
<span id="124">124</span>
<span id="125">125</span>
<span id="126">126</span>
<span id="127">127</span>
<span id="128">128</span>
<span id="129">129</span>
<span id="130">130</span>
<span id="131">131</span>
<span id="132">132</span>
<span id="133">133</span>
<span id="134">134</span>
<span id="135">135</span>
<span id="136">136</span>
<span id="137">137</span>
<span id="138">138</span>
<span id="139">139</span>
<span id="140">140</span>
<span id="141">141</span>
<span id="142">142</span>
<span id="143">143</span>
<span id="144">144</span>
<span id="145">145</span>
<span id="146">146</span>
<span id="147">147</span>
<span id="148">148</span>
<span id="149">149</span>
<span id="150">150</span>
<span id="151">151</span>
<span id="152">152</span>
<span id="153">153</span>
<span id="154">154</span>
<span id="155">155</span>
<span id="156">156</span>
<span id="157">157</span>
<span id="158">158</span>
<span id="159">159</span>
<span id="160">160</span>
<span id="161">161</span>
<span id="162">162</span>
<span id="163">163</span>
<span id="164">164</span>
<span id="165">165</span>
<span id="166">166</span>
<span id="167">167</span>
<span id="168">168</span>
<span id="169">169</span>
<span id="170">170</span>
<span id="171">171</span>
<span id="172">172</span>
<span id="173">173</span>
<span id="174">174</span>
<span id="175">175</span>
<span id="176">176</span>
<span id="177">177</span>
<span id="178">178</span>
<span id="179">179</span>
<span id="180">180</span>
<span id="181">181</span>
<span id="182">182</span>
<span id="183">183</span>
<span id="184">184</span>
<span id="185">185</span>
<span id="186">186</span>
<span id="187">187</span>
<span id="188">188</span>
<span id="189">189</span>
<span id="190">190</span>
<span id="191">191</span>
<span id="192">192</span>
<span id="193">193</span>
<span id="194">194</span>
<span id="195">195</span>
<span id="196">196</span>
<span id="197">197</span>
<span id="198">198</span>
<span id="199">199</span>
<span id="200">200</span>
<span id="201">201</span>
<span id="202">202</span>
<span id="203">203</span>
<span id="204">204</span>
<span id="205">205</span>
<span id="206">206</span>
<span id="207">207</span>
<span id="208">208</span>
<span id="209">209</span>
<span id="210">210</span>
<span id="211">211</span>
<span id="212">212</span>
<span id="213">213</span>
<span id="214">214</span>
<span id="215">215</span>
<span id="216">216</span>
<span id="217">217</span>
<span id="218">218</span>
<span id="219">219</span>
<span id="220">220</span>
<span id="221">221</span>
<span id="222">222</span>
<span id="223">223</span>
<span id="224">224</span>
<span id="225">225</span>
<span id="226">226</span>
<span id="227">227</span>
<span id="228">228</span>
<span id="229">229</span>
<span id="230">230</span>
<span id="231">231</span>
<span id="232">232</span>
<span id="233">233</span>
<span id="234">234</span>
<span id="235">235</span>
<span id="236">236</span>
<span id="237">237</span>
<span id="238">238</span>
<span id="239">239</span>
<span id="240">240</span>
<span id="241">241</span>
<span id="242">242</span>
<span id="243">243</span>
<span id="244">244</span>
<span id="245">245</span>
<span id="246">246</span>
<span id="247">247</span>
<span id="248">248</span>
<span id="249">249</span>
<span id="250">250</span>
<span id="251">251</span>
<span id="252">252</span>
<span id="253">253</span>
<span id="254">254</span>
<span id="255">255</span>
<span id="256">256</span>
<span id="257">257</span>
<span id="258">258</span>
<span id="259">259</span>
<span id="260">260</span>
<span id="261">261</span>
<span id="262">262</span>
<span id="263">263</span>
<span id="264">264</span>
<span id="265">265</span>
<span id="266">266</span>
<span id="267">267</span>
<span id="268">268</span>
<span id="269">269</span>
<span id="270">270</span>
<span id="271">271</span>
<span id="272">272</span>
<span id="273">273</span>
<span id="274">274</span>
<span id="275">275</span>
<span id="276">276</span>
<span id="277">277</span>
<span id="278">278</span>
<span id="279">279</span>
<span id="280">280</span>
<span id="281">281</span>
<span id="282">282</span>
<span id="283">283</span>
<span id="284">284</span>
<span id="285">285</span>
<span id="286">286</span>
<span id="287">287</span>
<span id="288">288</span>
<span id="289">289</span>
<span id="290">290</span>
<span id="291">291</span>
<span id="292">292</span>
<span id="293">293</span>
<span id="294">294</span>
<span id="295">295</span>
<span id="296">296</span>
<span id="297">297</span>
<span id="298">298</span>
<span id="299">299</span>
<span id="300">300</span>
<span id="301">301</span>
<span id="302">302</span>
<span id="303">303</span>
<span id="304">304</span>
<span id="305">305</span>
<span id="306">306</span>
<span id="307">307</span>
<span id="308">308</span>
<span id="309">309</span>
<span id="310">310</span>
<span id="311">311</span>
<span id="312">312</span>
<span id="313">313</span>
<span id="314">314</span>
<span id="315">315</span>
<span id="316">316</span>
<span id="317">317</span>
<span id="318">318</span>
<span id="319">319</span>
<span id="320">320</span>
<span id="321">321</span>
<span id="322">322</span>
<span id="323">323</span>
<span id="324">324</span>
<span id="325">325</span>
<span id="326">326</span>
<span id="327">327</span>
<span id="328">328</span>
<span id="329">329</span>
<span id="330">330</span>
<span id="331">331</span>
<span id="332">332</span>
<span id="333">333</span>
<span id="334">334</span>
<span id="335">335</span>
<span id="336">336</span>
<span id="337">337</span>
<span id="338">338</span>
<span id="339">339</span>
<span id="340">340</span>
<span id="341">341</span>
<span id="342">342</span>
<span id="343">343</span>
<span id="344">344</span>
<span id="345">345</span>
<span id="346">346</span>
<span id="347">347</span>
<span id="348">348</span>
<span id="349">349</span>
<span id="350">350</span>
<span id="351">351</span>
<span id="352">352</span>
<span id="353">353</span>
<span id="354">354</span>
<span id="355">355</span>
<span id="356">356</span>
<span id="357">357</span>
<span id="358">358</span>
<span id="359">359</span>
<span id="360">360</span>
<span id="361">361</span>
<span id="362">362</span>
<span id="363">363</span>
<span id="364">364</span>
<span id="365">365</span>
<span id="366">366</span>
<span id="367">367</span>
<span id="368">368</span>
<span id="369">369</span>
<span id="370">370</span>
<span id="371">371</span>
<span id="372">372</span>
<span id="373">373</span>
<span id="374">374</span>
<span id="375">375</span>
<span id="376">376</span>
<span id="377">377</span>
<span id="378">378</span>
<span id="379">379</span>
<span id="380">380</span>
</pre><pre class="rust"><code><span class="doccomment">//! Sessions for Actix Web.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! Provides a general solution for session management. Session middleware could provide different</span>
<span class="doccomment">//! implementations which could be accessed via general session API.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! This crate provides a general solution for session management and includes a cookie backend.</span>
<span class="doccomment">//! Other backend implementations can be built to use persistent or key-value stores, for example.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! In general, some session middleware, such as a [`CookieSession`] is initialized and applied.</span>
<span class="doccomment">//! To access session data, the [`Session`] extractor must be used. This extractor allows reading</span>
<span class="doccomment">//! modifying session data.</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! ```no_run</span>
<span class="doccomment">//! use actix_web::{web, App, HttpServer, HttpResponse, Error};</span>
<span class="doccomment">//! use actix_session::{Session, CookieSession};</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! fn index(session: Session) -&gt; Result&lt;&amp;&#39;static str, Error&gt; {</span>
<span class="doccomment">//! // access session data</span>
<span class="doccomment">//! if let Some(count) = session.get::&lt;i32&gt;(&quot;counter&quot;)? {</span>
<span class="doccomment">//! println!(&quot;SESSION value: {}&quot;, count);</span>
<span class="doccomment">//! session.insert(&quot;counter&quot;, count + 1)?;</span>
<span class="doccomment">//! } else {</span>
<span class="doccomment">//! session.insert(&quot;counter&quot;, 1)?;</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! Ok(&quot;Welcome!&quot;)</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//!</span>
<span class="doccomment">//! #[actix_web::main]</span>
<span class="doccomment">//! async fn main() -&gt; std::io::Result&lt;()&gt; {</span>
<span class="doccomment">//! HttpServer::new(</span>
<span class="doccomment">//! || App::new()</span>
<span class="doccomment">//! // create cookie based session middleware</span>
<span class="doccomment">//! .wrap(CookieSession::signed(&amp;[0; 32]).secure(false))</span>
<span class="doccomment">//! .default_service(web::to(|| HttpResponse::Ok())))</span>
<span class="doccomment">//! .bind((&quot;127.0.0.1&quot;, 8080))?</span>
<span class="doccomment">//! .run()</span>
<span class="doccomment">//! .await</span>
<span class="doccomment">//! }</span>
<span class="doccomment">//! ```</span>
<span class="attribute">#![<span class="ident">deny</span>(<span class="ident">rust_2018_idioms</span>, <span class="ident">nonstandard_style</span>)]</span>
<span class="attribute">#![<span class="ident">warn</span>(<span class="ident">future_incompatible</span>, <span class="ident">missing_docs</span>)]</span>
<span class="kw">use</span> <span class="ident">std</span>::{
<span class="ident">cell</span>::{<span class="ident">Ref</span>, <span class="ident">RefCell</span>},
<span class="ident">collections::HashMap</span>,
<span class="ident">mem</span>,
<span class="ident">rc::Rc</span>,
};
<span class="kw">use</span> <span class="ident">actix_utils::future</span>::{<span class="ident">ok</span>, <span class="ident">Ready</span>};
<span class="kw">use</span> <span class="ident">actix_web</span>::{
<span class="ident">dev</span>::{<span class="ident">Extensions</span>, <span class="ident">Payload</span>, <span class="ident">ServiceRequest</span>, <span class="ident">ServiceResponse</span>},
<span class="ident">Error</span>, <span class="ident">FromRequest</span>, <span class="ident">HttpMessage</span>, <span class="ident">HttpRequest</span>,
};
<span class="kw">use</span> <span class="ident">serde</span>::{<span class="ident">de::DeserializeOwned</span>, <span class="ident">Serialize</span>};
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;cookie-session&quot;</span>)]</span>
<span class="kw">mod</span> <span class="ident">cookie</span>;
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">feature</span> <span class="op">=</span> <span class="string">&quot;cookie-session&quot;</span>)]</span>
<span class="kw">pub</span> <span class="kw">use</span> <span class="ident"><span class="self">self</span>::cookie::CookieSession</span>;
<span class="doccomment">/// The high-level interface you use to modify session data.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Session object is obtained with [`UserSession::get_session`]. The [`UserSession`] trait is</span>
<span class="doccomment">/// implemented for `HttpRequest`, `ServiceRequest`, and `RequestHead`.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// use actix_session::Session;</span>
<span class="doccomment">/// use actix_web::Result;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// async fn index(session: Session) -&gt; Result&lt;&amp;&#39;static str&gt; {</span>
<span class="doccomment">/// // access session data</span>
<span class="doccomment">/// if let Some(count) = session.get::&lt;i32&gt;(&quot;counter&quot;)? {</span>
<span class="doccomment">/// session.insert(&quot;counter&quot;, count + 1)?;</span>
<span class="doccomment">/// } else {</span>
<span class="doccomment">/// session.insert(&quot;counter&quot;, 1)?;</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Ok(&quot;Welcome!&quot;)</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Session</span>(<span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">RefCell</span><span class="op">&lt;</span><span class="ident">SessionInner</span><span class="op">&gt;</span><span class="op">&gt;</span>);
<span class="doccomment">/// Extraction of a [`Session`] object.</span>
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">UserSession</span> {
<span class="doccomment">/// Extract the [`Session`] object</span>
<span class="kw">fn</span> <span class="ident">get_session</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Session</span>;
}
<span class="kw">impl</span> <span class="ident">UserSession</span> <span class="kw">for</span> <span class="ident">HttpRequest</span> {
<span class="kw">fn</span> <span class="ident">get_session</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Session</span> {
<span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="self">self</span>.<span class="ident">extensions_mut</span>())
}
}
<span class="kw">impl</span> <span class="ident">UserSession</span> <span class="kw">for</span> <span class="ident">ServiceRequest</span> {
<span class="kw">fn</span> <span class="ident">get_session</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Session</span> {
<span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="self">self</span>.<span class="ident">extensions_mut</span>())
}
}
<span class="doccomment">/// Status of a [`Session`].</span>
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">PartialEq</span>, <span class="ident">Clone</span>, <span class="ident">Debug</span>)]</span>
<span class="kw">pub</span> <span class="kw">enum</span> <span class="ident">SessionStatus</span> {
<span class="doccomment">/// Session has been updated and requires a new persist operation.</span>
<span class="ident">Changed</span>,
<span class="doccomment">/// Session is flagged for deletion and should be removed from client and server.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Most operations on the session after purge flag is set should have no effect.</span>
<span class="ident">Purged</span>,
<span class="doccomment">/// Session is flagged for refresh.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// For example, when using a backend that has a TTL (time-to-live) expiry on the session entry,</span>
<span class="doccomment">/// the session will be refreshed even if no data inside it has changed. The client may also</span>
<span class="doccomment">/// be notified of the refresh.</span>
<span class="ident">Renewed</span>,
<span class="doccomment">/// Session is unchanged from when last seen (if exists).</span>
<span class="doccomment">///</span>
<span class="doccomment">/// This state also captures new (previously unissued) sessions such as a user&#39;s first</span>
<span class="doccomment">/// site visit.</span>
<span class="ident">Unchanged</span>,
}
<span class="kw">impl</span> <span class="ident">Default</span> <span class="kw">for</span> <span class="ident">SessionStatus</span> {
<span class="kw">fn</span> <span class="ident">default</span>() -&gt; <span class="ident">SessionStatus</span> {
<span class="ident">SessionStatus::Unchanged</span>
}
}
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Default</span>)]</span>
<span class="kw">struct</span> <span class="ident">SessionInner</span> {
<span class="ident">state</span>: <span class="ident">HashMap</span><span class="op">&lt;</span><span class="ident">String</span>, <span class="ident">String</span><span class="op">&gt;</span>,
<span class="ident">status</span>: <span class="ident">SessionStatus</span>,
}
<span class="kw">impl</span> <span class="ident">Session</span> {
<span class="doccomment">/// Get a `value` from the session.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">get</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">DeserializeOwned</span><span class="op">&gt;</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">key</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>, <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">s</span>) <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow</span>().<span class="ident">state</span>.<span class="ident">get</span>(<span class="ident">key</span>) {
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(<span class="ident">serde_json::from_str</span>(<span class="ident">s</span>)<span class="question-mark">?</span>))
} <span class="kw">else</span> {
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
}
}
<span class="doccomment">/// Get all raw key-value data from the session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Note that values are JSON encoded.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">entries</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="ident">Ref</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span>, <span class="ident">HashMap</span><span class="op">&lt;</span><span class="ident">String</span>, <span class="ident">String</span><span class="op">&gt;</span><span class="op">&gt;</span> {
<span class="ident">Ref::map</span>(<span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow</span>(), <span class="op">|</span><span class="ident">inner</span><span class="op">|</span> <span class="kw-2">&amp;</span><span class="ident">inner</span>.<span class="ident">state</span>)
}
<span class="doccomment">/// Inserts a key-value pair into the session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Any serializable value can be used and will be encoded as JSON in session data, hence why</span>
<span class="doccomment">/// only a reference to the value is taken.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">insert</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">key</span>: <span class="kw">impl</span> <span class="ident">Into</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>, <span class="ident">value</span>: <span class="kw">impl</span> <span class="ident">Serialize</span>) -&gt; <span class="prelude-ty">Result</span><span class="op">&lt;</span>(), <span class="ident">Error</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">status</span> <span class="op">!</span><span class="op">=</span> <span class="ident">SessionStatus::Purged</span> {
<span class="ident">inner</span>.<span class="ident">status</span> <span class="op">=</span> <span class="ident">SessionStatus::Changed</span>;
<span class="kw">let</span> <span class="ident">val</span> <span class="op">=</span> <span class="ident">serde_json::to_string</span>(<span class="kw-2">&amp;</span><span class="ident">value</span>)<span class="question-mark">?</span>;
<span class="ident">inner</span>.<span class="ident">state</span>.<span class="ident">insert</span>(<span class="ident">key</span>.<span class="ident">into</span>(), <span class="ident">val</span>);
}
<span class="prelude-val">Ok</span>(())
}
<span class="doccomment">/// Remove value from the session.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// If present, the JSON encoded value is returned.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">remove</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">key</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span> {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">status</span> <span class="op">!</span><span class="op">=</span> <span class="ident">SessionStatus::Purged</span> {
<span class="ident">inner</span>.<span class="ident">status</span> <span class="op">=</span> <span class="ident">SessionStatus::Changed</span>;
<span class="kw">return</span> <span class="ident">inner</span>.<span class="ident">state</span>.<span class="ident">remove</span>(<span class="ident">key</span>);
}
<span class="prelude-val">None</span>
}
<span class="doccomment">/// Remove value from the session and deserialize.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Returns None if key was not present in session. Returns T if deserialization succeeds,</span>
<span class="doccomment">/// otherwise returns un-deserialized JSON string.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">remove_as</span><span class="op">&lt;</span><span class="ident">T</span>: <span class="ident">DeserializeOwned</span><span class="op">&gt;</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">key</span>: <span class="kw-2">&amp;</span><span class="ident">str</span>) -&gt; <span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">T</span>, <span class="ident">String</span><span class="op">&gt;</span><span class="op">&gt;</span> {
<span class="self">self</span>.<span class="ident">remove</span>(<span class="ident">key</span>)
.<span class="ident">map</span>(<span class="op">|</span><span class="ident">val_str</span><span class="op">|</span> <span class="kw">match</span> <span class="ident">serde_json::from_str</span>(<span class="kw-2">&amp;</span><span class="ident">val_str</span>) {
<span class="prelude-val">Ok</span>(<span class="ident">val</span>) =&gt; <span class="prelude-val">Ok</span>(<span class="ident">val</span>),
<span class="prelude-val">Err</span>(<span class="ident">_err</span>) =&gt; {
<span class="macro">log::debug!</span>(
<span class="string">&quot;removed value (key: {}) could not be deserialized as {}&quot;</span>,
<span class="ident">key</span>,
<span class="ident">std::any::type_name</span>::<span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</span>()
);
<span class="prelude-val">Err</span>(<span class="ident">val_str</span>)
}
})
}
<span class="doccomment">/// Clear the session.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">clear</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">status</span> <span class="op">!</span><span class="op">=</span> <span class="ident">SessionStatus::Purged</span> {
<span class="ident">inner</span>.<span class="ident">status</span> <span class="op">=</span> <span class="ident">SessionStatus::Changed</span>;
<span class="ident">inner</span>.<span class="ident">state</span>.<span class="ident">clear</span>()
}
}
<span class="doccomment">/// Removes session both client and server side.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">purge</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
<span class="ident">inner</span>.<span class="ident">status</span> <span class="op">=</span> <span class="ident">SessionStatus::Purged</span>;
<span class="ident">inner</span>.<span class="ident">state</span>.<span class="ident">clear</span>();
}
<span class="doccomment">/// Renews the session key, assigning existing session state to new key.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">renew</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="self">self</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
<span class="kw">if</span> <span class="ident">inner</span>.<span class="ident">status</span> <span class="op">!</span><span class="op">=</span> <span class="ident">SessionStatus::Purged</span> {
<span class="ident">inner</span>.<span class="ident">status</span> <span class="op">=</span> <span class="ident">SessionStatus::Renewed</span>;
}
}
<span class="doccomment">/// Adds the given key-value pairs to the session on the request.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Values that match keys already existing on the session will be overwritten. Values should</span>
<span class="doccomment">/// already be JSON serialized.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_session::Session;</span>
<span class="doccomment">/// # use actix_web::test;</span>
<span class="doccomment">/// let mut req = test::TestRequest::default().to_srv_request();</span>
<span class="doccomment">///</span>
<span class="doccomment">/// Session::set_session(</span>
<span class="doccomment">/// &amp;mut req,</span>
<span class="doccomment">/// vec![(&quot;counter&quot;.to_string(), serde_json::to_string(&amp;0).unwrap())],</span>
<span class="doccomment">/// );</span>
<span class="doccomment">/// ```</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">set_session</span>(<span class="ident">req</span>: <span class="kw-2">&amp;mut</span> <span class="ident">ServiceRequest</span>, <span class="ident">data</span>: <span class="kw">impl</span> <span class="ident">IntoIterator</span><span class="op">&lt;</span><span class="ident">Item</span> <span class="op">=</span> (<span class="ident">String</span>, <span class="ident">String</span>)<span class="op">&gt;</span>) {
<span class="kw">let</span> <span class="ident">session</span> <span class="op">=</span> <span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="ident">req</span>.<span class="ident">extensions_mut</span>());
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">inner</span> <span class="op">=</span> <span class="ident">session</span>.<span class="number">0</span>.<span class="ident">borrow_mut</span>();
<span class="ident">inner</span>.<span class="ident">state</span>.<span class="ident">extend</span>(<span class="ident">data</span>);
}
<span class="doccomment">/// Returns session status and iterator of key-value pairs of changes.</span>
<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">get_changes</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>(
<span class="ident">res</span>: <span class="kw-2">&amp;mut</span> <span class="ident">ServiceResponse</span><span class="op">&lt;</span><span class="ident">B</span><span class="op">&gt;</span>,
) -&gt; (<span class="ident">SessionStatus</span>, <span class="kw">impl</span> <span class="ident">Iterator</span><span class="op">&lt;</span><span class="ident">Item</span> <span class="op">=</span> (<span class="ident">String</span>, <span class="ident">String</span>)<span class="op">&gt;</span>) {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">s_impl</span>) <span class="op">=</span> <span class="ident">res</span>
.<span class="ident">request</span>()
.<span class="ident">extensions</span>()
.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">RefCell</span><span class="op">&lt;</span><span class="ident">SessionInner</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span>()
{
<span class="kw">let</span> <span class="ident">state</span> <span class="op">=</span> <span class="ident">mem::take</span>(<span class="kw-2">&amp;mut</span> <span class="ident">s_impl</span>.<span class="ident">borrow_mut</span>().<span class="ident">state</span>);
(<span class="ident">s_impl</span>.<span class="ident">borrow</span>().<span class="ident">status</span>.<span class="ident">clone</span>(), <span class="ident">state</span>.<span class="ident">into_iter</span>())
} <span class="kw">else</span> {
(<span class="ident">SessionStatus::Unchanged</span>, <span class="ident">HashMap::new</span>().<span class="ident">into_iter</span>())
}
}
<span class="kw">fn</span> <span class="ident">get_session</span>(<span class="ident">extensions</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Extensions</span>) -&gt; <span class="ident">Session</span> {
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">s_impl</span>) <span class="op">=</span> <span class="ident">extensions</span>.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">Rc</span><span class="op">&lt;</span><span class="ident">RefCell</span><span class="op">&lt;</span><span class="ident">SessionInner</span><span class="op">&gt;</span><span class="op">&gt;</span><span class="op">&gt;</span>() {
<span class="kw">return</span> <span class="ident">Session</span>(<span class="ident">Rc::clone</span>(<span class="ident">s_impl</span>));
}
<span class="kw">let</span> <span class="ident">inner</span> <span class="op">=</span> <span class="ident">Rc::new</span>(<span class="ident">RefCell::new</span>(<span class="ident">SessionInner::default</span>()));
<span class="ident">extensions</span>.<span class="ident">insert</span>(<span class="ident">inner</span>.<span class="ident">clone</span>());
<span class="ident">Session</span>(<span class="ident">inner</span>)
}
}
<span class="doccomment">/// Extractor implementation for Session type.</span>
<span class="doccomment">///</span>
<span class="doccomment">/// # Examples</span>
<span class="doccomment">/// ```</span>
<span class="doccomment">/// # use actix_web::*;</span>
<span class="doccomment">/// use actix_session::Session;</span>
<span class="doccomment">///</span>
<span class="doccomment">/// #[get(&quot;/&quot;)]</span>
<span class="doccomment">/// async fn index(session: Session) -&gt; Result&lt;impl Responder&gt; {</span>
<span class="doccomment">/// // access session data</span>
<span class="doccomment">/// if let Some(count) = session.get::&lt;i32&gt;(&quot;counter&quot;)? {</span>
<span class="doccomment">/// session.insert(&quot;counter&quot;, count + 1)?;</span>
<span class="doccomment">/// } else {</span>
<span class="doccomment">/// session.insert(&quot;counter&quot;, 1)?;</span>
<span class="doccomment">/// }</span>
<span class="doccomment">///</span>
<span class="doccomment">/// let count = session.get::&lt;i32&gt;(&quot;counter&quot;)?.unwrap();</span>
<span class="doccomment">/// Ok(format!(&quot;Counter: {}&quot;, count))</span>
<span class="doccomment">/// }</span>
<span class="doccomment">/// ```</span>
<span class="kw">impl</span> <span class="ident">FromRequest</span> <span class="kw">for</span> <span class="ident">Session</span> {
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">Error</span>;
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">Ready</span><span class="op">&lt;</span><span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">Session</span>, <span class="ident">Error</span><span class="op">&gt;</span><span class="op">&gt;</span>;
<span class="attribute">#[<span class="ident">inline</span>]</span>
<span class="kw">fn</span> <span class="ident">from_request</span>(<span class="ident">req</span>: <span class="kw-2">&amp;</span><span class="ident">HttpRequest</span>, <span class="kw">_</span>: <span class="kw-2">&amp;mut</span> <span class="ident">Payload</span>) -&gt; <span class="ident"><span class="self">Self</span>::Future</span> {
<span class="ident">ok</span>(<span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="ident">req</span>.<span class="ident">extensions_mut</span>()))
}
}
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">test</span>)]</span>
<span class="kw">mod</span> <span class="ident">tests</span> {
<span class="kw">use</span> <span class="ident">actix_web</span>::{<span class="ident">test</span>, <span class="ident">HttpResponse</span>};
<span class="kw">use</span> <span class="kw">super</span>::<span class="kw-2">*</span>;
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">session</span>() {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">test::TestRequest::default</span>().<span class="ident">to_srv_request</span>();
<span class="ident">Session::set_session</span>(
<span class="kw-2">&amp;mut</span> <span class="ident">req</span>,
<span class="macro">vec!</span>[(<span class="string">&quot;key&quot;</span>.<span class="ident">to_string</span>(), <span class="ident">serde_json::to_string</span>(<span class="string">&quot;value&quot;</span>).<span class="ident">unwrap</span>())],
);
<span class="kw">let</span> <span class="ident">session</span> <span class="op">=</span> <span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="ident">req</span>.<span class="ident">extensions_mut</span>());
<span class="kw">let</span> <span class="ident">res</span> <span class="op">=</span> <span class="ident">session</span>.<span class="ident">get</span>::<span class="op">&lt;</span><span class="ident">String</span><span class="op">&gt;</span>(<span class="string">&quot;key&quot;</span>).<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">res</span>, <span class="prelude-val">Some</span>(<span class="string">&quot;value&quot;</span>.<span class="ident">to_string</span>()));
<span class="ident">session</span>.<span class="ident">insert</span>(<span class="string">&quot;key2&quot;</span>, <span class="string">&quot;value2&quot;</span>).<span class="ident">unwrap</span>();
<span class="ident">session</span>.<span class="ident">remove</span>(<span class="string">&quot;key&quot;</span>);
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">res</span> <span class="op">=</span> <span class="ident">req</span>.<span class="ident">into_response</span>(<span class="ident">HttpResponse::Ok</span>().<span class="ident">finish</span>());
<span class="kw">let</span> (<span class="ident">_status</span>, <span class="ident">state</span>) <span class="op">=</span> <span class="ident">Session::get_changes</span>(<span class="kw-2">&amp;mut</span> <span class="ident">res</span>);
<span class="kw">let</span> <span class="ident">changes</span>: <span class="ident">Vec</span><span class="op">&lt;</span><span class="kw">_</span><span class="op">&gt;</span> <span class="op">=</span> <span class="ident">state</span>.<span class="ident">collect</span>();
<span class="macro">assert_eq!</span>(<span class="ident">changes</span>, [(<span class="string">&quot;key2&quot;</span>.<span class="ident">to_string</span>(), <span class="string">&quot;\&quot;value2\&quot;&quot;</span>.<span class="ident">to_string</span>())]);
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">get_session</span>() {
<span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">test::TestRequest::default</span>().<span class="ident">to_srv_request</span>();
<span class="ident">Session::set_session</span>(
<span class="kw-2">&amp;mut</span> <span class="ident">req</span>,
<span class="macro">vec!</span>[(<span class="string">&quot;key&quot;</span>.<span class="ident">to_string</span>(), <span class="ident">serde_json::to_string</span>(<span class="kw-2">&amp;</span><span class="bool-val">true</span>).<span class="ident">unwrap</span>())],
);
<span class="kw">let</span> <span class="ident">session</span> <span class="op">=</span> <span class="ident">req</span>.<span class="ident">get_session</span>();
<span class="kw">let</span> <span class="ident">res</span> <span class="op">=</span> <span class="ident">session</span>.<span class="ident">get</span>(<span class="string">&quot;key&quot;</span>).<span class="ident">unwrap</span>();
<span class="macro">assert_eq!</span>(<span class="ident">res</span>, <span class="prelude-val">Some</span>(<span class="bool-val">true</span>));
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">purge_session</span>() {
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">test::TestRequest::default</span>().<span class="ident">to_srv_request</span>();
<span class="kw">let</span> <span class="ident">session</span> <span class="op">=</span> <span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="ident">req</span>.<span class="ident">extensions_mut</span>());
<span class="macro">assert_eq!</span>(<span class="ident">session</span>.<span class="number">0</span>.<span class="ident">borrow</span>().<span class="ident">status</span>, <span class="ident">SessionStatus::Unchanged</span>);
<span class="ident">session</span>.<span class="ident">purge</span>();
<span class="macro">assert_eq!</span>(<span class="ident">session</span>.<span class="number">0</span>.<span class="ident">borrow</span>().<span class="ident">status</span>, <span class="ident">SessionStatus::Purged</span>);
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">renew_session</span>() {
<span class="kw">let</span> <span class="ident">req</span> <span class="op">=</span> <span class="ident">test::TestRequest::default</span>().<span class="ident">to_srv_request</span>();
<span class="kw">let</span> <span class="ident">session</span> <span class="op">=</span> <span class="ident">Session::get_session</span>(<span class="kw-2">&amp;mut</span> <span class="kw-2">*</span><span class="ident">req</span>.<span class="ident">extensions_mut</span>());
<span class="macro">assert_eq!</span>(<span class="ident">session</span>.<span class="number">0</span>.<span class="ident">borrow</span>().<span class="ident">status</span>, <span class="ident">SessionStatus::Unchanged</span>);
<span class="ident">session</span>.<span class="ident">renew</span>();
<span class="macro">assert_eq!</span>(<span class="ident">session</span>.<span class="number">0</span>.<span class="ident">borrow</span>().<span class="ident">status</span>, <span class="ident">SessionStatus::Renewed</span>);
}
<span class="attribute">#[<span class="ident">actix_web::test</span>]</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">session_entries</span>() {
<span class="kw">let</span> <span class="ident">session</span> <span class="op">=</span> <span class="ident">Session</span>(<span class="ident">Rc::new</span>(<span class="ident">RefCell::new</span>(<span class="ident">SessionInner::default</span>())));
<span class="ident">session</span>.<span class="ident">insert</span>(<span class="string">&quot;test_str&quot;</span>, <span class="string">&quot;val&quot;</span>).<span class="ident">unwrap</span>();
<span class="ident">session</span>.<span class="ident">insert</span>(<span class="string">&quot;test_num&quot;</span>, <span class="number">1</span>).<span class="ident">unwrap</span>();
<span class="kw">let</span> <span class="ident">map</span> <span class="op">=</span> <span class="ident">session</span>.<span class="ident">entries</span>();
<span class="ident">map</span>.<span class="ident">contains_key</span>(<span class="string">&quot;test_str&quot;</span>);
<span class="ident">map</span>.<span class="ident">contains_key</span>(<span class="string">&quot;test_num&quot;</span>);
}
}
</code></pre></div>
</section><section id="search" class="content hidden"></section></div></main><div id="rustdoc-vars" data-root-path="../../" data-current-crate="actix_session" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.60.0-nightly (30b3f35c4 2022-02-17)" ></div>
</body></html>