This repository has been archived on 2022-04-04. You can view files and clone it, but cannot push or open issues or pull requests.

191 lines
20 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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="githubcrates-iodocs-rs"><meta name="keywords" content="rust, rustlang, rust-lang, async_trait"><title>async_trait - Rust</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>
<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 mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="sidebar-menu" role="button">&#9776;</div><a class="sidebar-logo" href="../async_trait/index.html"><div class="logo-container"><img class="rust-logo" src="../rust-logo.png" alt="logo"></div>
</a><h2 class="location">Crate async_trait</h2><div class="block version"><div class="narrow-helper"></div><p>Version 0.1.52</p></div><div class="sidebar-elems"><a id="all-types" href="all.html"><p>See all async_trait's items</p></a><div id="sidebar-vars" data-name="async_trait" data-ty="mod" data-relpath=""></div><script defer src="sidebar-items.js"></script></div></nav><main><div class="width-limiter"><div class="sub-container"><a class="sub-logo-container" href="../async_trait/index.html"><img class="rust-logo" src="../rust-logo.png" alt="logo"></a><nav class="sub"><div class="theme-picker"><button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"><img width="18" height="18" alt="Pick another theme!" src="../brush.svg"></button><div id="theme-choices" role="menu"></div></div><form class="search-form"><div class="search-container"><div><select id="crate-search"><option value="All crates">All crates</option></select><input class="search-input" name="search" autocomplete="off" spellcheck="false" placeholder="Click or press S to search, ? for more options…" type="search"></div><button type="button" id="help-button" title="help">?</button><a id="settings-menu" href="../settings.html" title="settings"><img width="18" height="18" alt="Change settings" src="../wheel.svg"></a></div></form></nav></div><section id="main-content" class="content"><h1 class="fqn"><span class="in-band">Crate <a class="mod" href="#">async_trait</a><button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"><img src="../clipboard.svg" width="19" height="18" alt="Copy item path"></button></span><span class="out-of-band"><span id="render-detail"><a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">[<span class="inner">&#x2212;</span>]</a></span><a class="srclink" href="../src/async_trait/lib.rs.html#1-338" title="goto source code">[src]</a></span></h1><details class="rustdoc-toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p><a href="https://github.com/dtolnay/async-trait"><img src="https://img.shields.io/badge/github-8da0cb?style=for-the-badge&amp;labelColor=555555&amp;logo=github" alt="github" /></a><a href="https://crates.io/crates/async-trait"><img src="https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&amp;labelColor=555555&amp;logo=rust" alt="crates-io" /></a><a href="https://docs.rs/async-trait"><img src="https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&amp;labelColor=555555&amp;logoColor=white&amp;logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" alt="docs-rs" /></a></p>
<br>
<h5>Type erasure for async trait methods</h5>
<p>The initial round of stabilizations for the async/await language feature in
Rust 1.39 did not include support for async fn in traits. Trying to include
an async fn in a trait produces the following error:</p>
<div class='information'><div class='tooltip compile_fail'></div></div><div class="example-wrap"><pre class="rust rust-example-rendered compile_fail"><code><span class="kw">trait</span> <span class="ident">MyTrait</span> {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">f</span>() {}
}</code></pre></div>
<div class="example-wrap"><pre class="language-text"><code>error[E0706]: trait fns cannot be declared `async`
--&gt; src/main.rs:4:5
|
4 | async fn f() {}
| ^^^^^^^^^^^^^^^</code></pre></div>
<p>This crate provides an attribute macro to make async fn in traits work.</p>
<p>Please refer to <a href="https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/"><em>why async fn in traits are hard</em></a> for a deeper
analysis of how this implementation differs from what the compiler and
language hope to deliver in the future.</p>
<br>
<h2 id="example" class="section-header"><a href="#example">Example</a></h2>
<p>This example implements the core of a highly effective advertising platform
using async fn in a trait.</p>
<p>The only thing to notice here is that we write an <code>#[async_trait]</code> macro on
top of traits and trait impls that contain async fn, and then they work.</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use</span> <span class="ident">async_trait::async_trait</span>;
<span class="attribute">#[<span class="ident">async_trait</span>]</span>
<span class="kw">trait</span> <span class="ident">Advertisement</span> {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">run</span>(<span class="kw-2">&amp;</span><span class="self">self</span>);
}
<span class="kw">struct</span> <span class="ident">Modal</span>;
<span class="attribute">#[<span class="ident">async_trait</span>]</span>
<span class="kw">impl</span> <span class="ident">Advertisement</span> <span class="kw">for</span> <span class="ident">Modal</span> {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">run</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<span class="self">self</span>.<span class="ident">render_fullscreen</span>().<span class="kw">await</span>;
<span class="kw">for</span> <span class="kw">_</span> <span class="kw">in</span> <span class="number">0</span>..<span class="number">4u16</span> {
<span class="ident">remind_user_to_join_mailing_list</span>().<span class="kw">await</span>;
}
<span class="self">self</span>.<span class="ident">hide_for_now</span>().<span class="kw">await</span>;
}
}
<span class="kw">struct</span> <span class="ident">AutoplayingVideo</span> {
<span class="ident">media_url</span>: <span class="ident">String</span>,
}
<span class="attribute">#[<span class="ident">async_trait</span>]</span>
<span class="kw">impl</span> <span class="ident">Advertisement</span> <span class="kw">for</span> <span class="ident">AutoplayingVideo</span> {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">run</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<span class="kw">let</span> <span class="ident">stream</span> <span class="op">=</span> <span class="ident">connect</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.<span class="ident">media_url</span>).<span class="kw">await</span>;
<span class="ident">stream</span>.<span class="ident">play</span>().<span class="kw">await</span>;
<span class="comment">// Video probably persuaded user to join our mailing list!</span>
<span class="ident">Modal</span>.<span class="ident">run</span>().<span class="kw">await</span>;
}
}</code></pre></div>
<p><br><br></p>
<h2 id="supported-features" class="section-header"><a href="#supported-features">Supported features</a></h2>
<p>It is the intention that all features of Rust traits should work nicely with
#[async_trait], but the edge cases are numerous. Please file an issue if
you see unexpected borrow checker errors, type errors, or warnings. There is
no use of <code>unsafe</code> in the expanded code, so rest assured that if your code
compiles it cant be that badly broken.</p>
<blockquote>
<p>Self by value, by reference, by mut reference, or no self;<br>
Any number of arguments, any return value;<br>
Generic type parameters and lifetime parameters;<br>
Associated types;<br>
Having async and non-async functions in the same trait;<br>
Default implementations provided by the trait;<br>
Elided lifetimes;<br>
Dyn-capable traits.<br></p>
</blockquote>
<br>
<h2 id="explanation" class="section-header"><a href="#explanation">Explanation</a></h2>
<p>Async fns get transformed into methods that return <code>Pin&lt;Box&lt;dyn Future + Send + 'async&gt;&gt;</code> and delegate to a private async freestanding function.</p>
<p>For example the <code>impl Advertisement for AutoplayingVideo</code> above would be
expanded as:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">impl</span> <span class="ident">Advertisement</span> <span class="kw">for</span> <span class="ident">AutoplayingVideo</span> {
<span class="kw">fn</span> <span class="ident">run</span><span class="op">&lt;</span><span class="lifetime">&#39;async</span><span class="op">&gt;</span>(
<span class="kw-2">&amp;</span><span class="lifetime">&#39;async</span> <span class="self">self</span>,
) -&gt; <span class="ident">Pin</span><span class="op">&lt;</span><span class="ident">Box</span><span class="op">&lt;</span><span class="kw">dyn</span> <span class="ident">core::future::Future</span><span class="op">&lt;</span><span class="ident">Output</span> <span class="op">=</span> ()<span class="op">&gt;</span> <span class="op">+</span> <span class="ident">Send</span> <span class="op">+</span> <span class="lifetime">&#39;async</span><span class="op">&gt;</span><span class="op">&gt;</span>
<span class="kw">where</span>
<span class="self">Self</span>: <span class="ident">Sync</span> <span class="op">+</span> <span class="lifetime">&#39;async</span>,
{
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">run</span>(<span class="ident">_self</span>: <span class="kw-2">&amp;</span><span class="ident">AutoplayingVideo</span>) {
<span class="comment">/* the original method body */</span>
}
<span class="ident">Box::pin</span>(<span class="ident">run</span>(<span class="self">self</span>))
}
}</code></pre></div>
<p><br><br></p>
<h2 id="non-threadsafe-futures" class="section-header"><a href="#non-threadsafe-futures">Non-threadsafe futures</a></h2>
<p>Not all async traits need futures that are <code>dyn Future + Send</code>. To avoid
having Send and Sync bounds placed on the async trait methods, invoke the
async trait macro as <code>#[async_trait(?Send)]</code> on both the trait and the impl
blocks.</p>
<br>
<h2 id="elided-lifetimes" class="section-header"><a href="#elided-lifetimes">Elided lifetimes</a></h2>
<p>Be aware that async fn syntax does not allow lifetime elision outside of <code>&amp;</code>
and <code>&amp;mut</code> references. (This is true even when not using #[async_trait].)
Lifetimes must be named or marked by the placeholder <code>'_</code>.</p>
<p>Fortunately the compiler is able to diagnose missing lifetimes with a good
error message.</p>
<div class='information'><div class='tooltip compile_fail'></div></div><div class="example-wrap"><pre class="rust rust-example-rendered compile_fail"><code><span class="kw">type</span> <span class="ident">Elided</span><span class="op">&lt;</span><span class="lifetime">&#39;a</span><span class="op">&gt;</span> <span class="op">=</span> <span class="kw-2">&amp;</span><span class="lifetime">&#39;a</span> <span class="ident">usize</span>;
<span class="attribute">#[<span class="ident">async_trait</span>]</span>
<span class="kw">trait</span> <span class="ident">Test</span> {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test</span>(<span class="ident">not_okay</span>: <span class="ident">Elided</span>, <span class="ident">okay</span>: <span class="kw-2">&amp;</span><span class="ident">usize</span>) {}
}</code></pre></div>
<div class="example-wrap"><pre class="language-text"><code>error[E0726]: implicit elided lifetime not allowed here
--&gt; src/main.rs:9:29
|
9 | async fn test(not_okay: Elided, okay: &amp;usize) {}
| ^^^^^^- help: indicate the anonymous lifetime: `&lt;&#39;_&gt;`</code></pre></div>
<p>The fix is to name the lifetime or use <code>'_</code>.</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="attribute">#[<span class="ident">async_trait</span>]</span>
<span class="kw">trait</span> <span class="ident">Test</span> {
<span class="comment">// either</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test</span><span class="op">&lt;</span><span class="lifetime">&#39;e</span><span class="op">&gt;</span>(<span class="ident">elided</span>: <span class="ident">Elided</span><span class="op">&lt;</span><span class="lifetime">&#39;e</span><span class="op">&gt;</span>) {}
<span class="comment">// or</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">test</span>(<span class="ident">elided</span>: <span class="ident">Elided</span><span class="op">&lt;</span><span class="lifetime">&#39;_</span><span class="op">&gt;</span>) {}
}</code></pre></div>
<p><br><br></p>
<h2 id="dyn-traits" class="section-header"><a href="#dyn-traits">Dyn traits</a></h2>
<p>Traits with async methods can be used as trait objects as long as they meet
the usual requirements for dyn no methods with type parameters, no self
by value, no associated types, etc.</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="attribute">#[<span class="ident">async_trait</span>]</span>
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">ObjectSafe</span> {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">f</span>(<span class="kw-2">&amp;</span><span class="self">self</span>);
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">g</span>(<span class="kw-2">&amp;mut</span> <span class="self">self</span>);
}
<span class="kw">impl</span> <span class="ident">ObjectSafe</span> <span class="kw">for</span> <span class="ident">MyType</span> {...}
<span class="kw">let</span> <span class="ident">value</span>: <span class="ident">MyType</span> <span class="op">=</span> ...;
<span class="kw">let</span> <span class="ident">object</span> <span class="op">=</span> <span class="kw-2">&amp;</span><span class="ident">value</span> <span class="kw">as</span> <span class="kw-2">&amp;</span><span class="kw">dyn</span> <span class="ident">ObjectSafe</span>; <span class="comment">// make trait object</span></code></pre></div>
<p>The one wrinkle is in traits that provide default implementations of async
methods. In order for the default implementation to produce a future that is
Send, the async_trait macro must emit a bound of <code>Self: Sync</code> on trait
methods that take <code>&amp;self</code> and a bound <code>Self: Send</code> on trait methods that
take <code>&amp;mut self</code>. An example of the former is visible in the expanded code
in the explanation section above.</p>
<p>If you make a trait with async methods that have default implementations,
everything will work except that the trait cannot be used as a trait object.
Creating a value of type <code>&amp;dyn Trait</code> will produce an error that looks like
this:</p>
<div class="example-wrap"><pre class="language-text"><code>error: the trait `Test` cannot be made into an object
--&gt; src/main.rs:8:5
|
8 | async fn cannot_dyn(&amp;self) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</code></pre></div>
<p>For traits that need to be object safe and need to have default
implementations for some async methods, there are two resolutions. Either
you can add Send and/or Sync as supertraits (Send if there are <code>&amp;mut self</code>
methods with default implementations, Sync if there are <code>&amp;self</code> methods with
default implementations) to constrain all implementors of the trait such that
the default implementations are applicable to them:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="attribute">#[<span class="ident">async_trait</span>]</span>
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">ObjectSafe</span>: <span class="ident">Sync</span> { <span class="comment">// added supertrait</span>
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">can_dyn</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) {}
}
<span class="kw">let</span> <span class="ident">object</span> <span class="op">=</span> <span class="kw-2">&amp;</span><span class="ident">value</span> <span class="kw">as</span> <span class="kw-2">&amp;</span><span class="kw">dyn</span> <span class="ident">ObjectSafe</span>;</code></pre></div>
<p>or you can strike the problematic methods from your trait object by
bounding them with <code>Self: Sized</code>:</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="attribute">#[<span class="ident">async_trait</span>]</span>
<span class="kw">pub</span> <span class="kw">trait</span> <span class="ident">ObjectSafe</span> {
<span class="kw">async</span> <span class="kw">fn</span> <span class="ident">cannot_dyn</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) <span class="kw">where</span> <span class="self">Self</span>: <span class="ident">Sized</span> {}
<span class="comment">// presumably other methods</span>
}
<span class="kw">let</span> <span class="ident">object</span> <span class="op">=</span> <span class="kw-2">&amp;</span><span class="ident">value</span> <span class="kw">as</span> <span class="kw-2">&amp;</span><span class="kw">dyn</span> <span class="ident">ObjectSafe</span>;</code></pre></div>
</div></details><h2 id="attributes" class="small-section-header"><a href="#attributes">Attribute Macros</a></h2>
<div class="item-table"><div class="item-row"><div class="item-left module-item"><a class="attr" href="attr.async_trait.html" title="async_trait::async_trait attr">async_trait</a></div><div class="item-right docblock-short"></div></div></div></section><section id="search" class="content hidden"></section></div></main><div id="rustdoc-vars" data-root-path="../" data-current-crate="async_trait" data-themes="ayu,dark,light" data-resource-suffix="" data-rustdoc-version="1.59.0 (9d1b2106e 2022-02-23)" ></div>
</body></html>