async_coap/arc_guard.rs
1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16//! # Arc Guard
17//!
18//! This crate[^1] provides the [`ArcGuard`] class, which is a container for a single object
19//! with lifetime that is bound to that of an `Arc`. This is useful for passing around boxed
20//! futures that have a lifetime that is limited to that of the object that created it.
21//!
22//! For example, the following does not compile:
23//!
24//! ```compile_fail
25//! # use async_coap::arc_guard; // Remove if spun off into own crate
26//! use futures::{future::ready,future::BoxFuture,prelude::*};
27//! use std::sync::{Arc,Weak};
28//! use arc_guard::{ArcGuard,ArcGuardExt};
29//!
30//! trait PropertyFetcher {
31//! fn fetch(
32//! &self,
33//! key: &str,
34//! ) -> BoxFuture<Option<String>>;
35//! }
36//!
37//! struct WeakFetcher {
38//! sub_obj: Weak<Box<PropertyFetcher>>,
39//! }
40//!
41//! impl PropertyFetcher for WeakFetcher {
42//! fn fetch(&self, key: &str) -> BoxFuture<Option<String>> {
43//! if let Some(arc) = self.sub_obj.upgrade() {
44//! // error[E0515]: cannot return value referencing local variable `arc`
45//! arc.fetch(key).boxed()
46//! } else {
47//! ready(None).boxed()
48//! }
49//! }
50//! }
51//! ```
52//!
53//! If you think about it, the fact that `rustc` doesn't like this code makes perfect sense:
54//! because `sub_obj` is a weak reference, it could be dropped at any moment, violating the
55//! lifetime guarantee for the return value of `fetch()`. To fix this, we need to ensure that
56//! the value we return internally keeps an `Arc` reference to the object that created it. That's
57//! where `ArcGuard` comes in:
58//!
59//! ```
60//! # use async_coap::arc_guard; // Remove if spun off into own crate
61//! # use futures::{future::ready,future::BoxFuture,prelude::*};
62//! # use std::sync::{Arc,Weak};
63//! # use arc_guard::{ArcGuard,ArcGuardExt};
64//! #
65//! # trait PropertyFetcher {
66//! # fn fetch(
67//! # &self,
68//! # key: &str,
69//! # ) -> BoxFuture<Option<String>>;
70//! # }
71//! #
72//! # struct WeakFetcher {
73//! # sub_obj: Weak<Box<PropertyFetcher>>,
74//! # }
75//!
76//! impl PropertyFetcher for WeakFetcher {
77//! fn fetch(&self, key: &str) -> BoxFuture<Option<String>> {
78//! if let Some(arc) = self.sub_obj.upgrade() {
79//! // Compiles and works!
80//! arc.guard(|x|x.fetch(key)).boxed()
81//! } else {
82//! ready(None).boxed()
83//! }
84//! }
85//! }
86//! ```
87//!
88//! ## Additional Examples
89//!
90//! ```
91//! # use async_coap::arc_guard; // Remove if spun off into own crate
92//! # use std::sync::{Arc,Weak};
93//! # use arc_guard::{ArcGuard,ArcGuardExt};
94//!
95//! let mut arc = Arc::new("foobar".to_string());
96//!
97//! let guarded = arc.guard(|s| &s.as_str()[3..]);
98//!
99//! assert_eq!(guarded, "bar");
100//!
101//! // We can't get a mutable instance to the
102//! // string while `guarded` is still around.
103//! assert_eq!(Arc::get_mut(&mut arc), None);
104//!
105//! core::mem::drop(guarded);
106//!
107//! assert!(Arc::get_mut(&mut arc).is_some());
108//! ```
109//!
110//! [^1]: I would have loved to call this crate `lifeguard`, because it is a "guard" on the
111//! lifetime of the contained "head" instance, but sadly that name was
112//! [already taken](https://crates.io/crates/lifeguard).
113//!
114
115#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
116#![warn(clippy::all)]
117
118use futures::prelude::*;
119use pin_utils::unsafe_pinned;
120use std::cmp::Ordering;
121use std::ops::Deref;
122use std::pin::Pin;
123use std::sync::Arc;
124
125/// A container for a single object with lifetime that is bound to that of an `Arc`.
126///
127/// See [Module Documentation](index.html) for more information.
128#[derive(Debug, Clone)]
129pub struct ArcGuard<RC, T> {
130 inner: T,
131 head: Arc<RC>,
132}
133
134impl<RC, T> ArcGuard<RC, T> {
135 unsafe_pinned!(inner: T);
136
137 /// Constructs a new `ArcGuard<>` instance using the given `Arc<>` and getter closure.
138 /// The use of a closure for the getter allows for a more convenient syntax while ensuring
139 /// the lifetimes are properly accounted for.
140 ///
141 /// See the main documentation for `ArcGuard<>` for a usage example.
142 pub fn new<'head, F>(head: Arc<RC>, getter: F) -> ArcGuard<RC, T>
143 where
144 F: FnOnce(&'head RC) -> T,
145 RC: 'head,
146 T: 'head,
147 {
148 // SAFETY: This is safe because we are only using this reference to create our object,
149 // and, by holding a reference to `head`, this class ensures that it does not live longer
150 // than the contained reference.
151 ArcGuard {
152 inner: getter(unsafe { std::mem::transmute::<&RC, &RC>(&head) }),
153 head,
154 }
155 }
156
157 /// Borrows a reference to the `Arc` that is being held to preserve the underlying value.
158 pub fn head(&self) -> &Arc<RC> {
159 &self.head
160 }
161}
162
163unsafe impl<RC, T: Send> Send for ArcGuard<RC, T> {}
164unsafe impl<RC, T: Sync> Sync for ArcGuard<RC, T> {}
165
166impl<RC, T> Deref for ArcGuard<RC, T> {
167 type Target = T;
168
169 fn deref(&self) -> &Self::Target {
170 &self.inner
171 }
172}
173
174impl<RC, T: std::fmt::Display> std::fmt::Display for ArcGuard<RC, T> {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
176 self.inner.fmt(f)
177 }
178}
179
180impl<RC, T: AsRef<R>, R> AsRef<R> for ArcGuard<RC, T> {
181 fn as_ref(&self) -> &R {
182 self.inner.as_ref()
183 }
184}
185
186impl<RC, T> std::borrow::Borrow<T> for ArcGuard<RC, T> {
187 fn borrow(&self) -> &T {
188 &self.inner
189 }
190}
191
192impl<RC, T: PartialEq<R>, R> PartialEq<R> for ArcGuard<RC, T> {
193 fn eq(&self, other: &R) -> bool {
194 self.inner.eq(other)
195 }
196}
197
198impl<RC, T: PartialOrd<R>, R> PartialOrd<R> for ArcGuard<RC, T> {
199 fn partial_cmp(&self, other: &R) -> Option<Ordering> {
200 self.inner.partial_cmp(other)
201 }
202}
203
204impl<RC, T: Future> Future for ArcGuard<RC, T> {
205 type Output = T::Output;
206
207 fn poll(
208 mut self: Pin<&mut Self>,
209 cx: &mut futures::task::Context<'_>,
210 ) -> futures::task::Poll<Self::Output> {
211 self.as_mut().inner().poll(cx)
212 }
213}
214
215impl<RC, T: Stream> Stream for ArcGuard<RC, T> {
216 type Item = T::Item;
217
218 fn poll_next(
219 mut self: Pin<&mut Self>,
220 cx: &mut futures::task::Context<'_>,
221 ) -> futures::task::Poll<Option<Self::Item>> {
222 self.as_mut().inner().poll_next(cx)
223 }
224}
225
226/// A convenience trait for `Arc<>` that makes it easier to construct `ArcGuard<>` instances.
227///
228/// See [Module Documentation](index.html) for more information.
229pub trait ArcGuardExt<RC> {
230 /// Convenience method for constructing `ArcGuard<>` instances.
231 ///
232 /// See [Module Documentation](index.html) for more information.
233 fn guard<'head, F, T>(&self, getter: F) -> ArcGuard<RC, T>
234 where
235 F: FnOnce(&'head RC) -> T,
236 RC: 'head,
237 T: 'head;
238}
239
240impl<RC> ArcGuardExt<RC> for Arc<RC> {
241 fn guard<'head, F, T>(&self, getter: F) -> ArcGuard<RC, T>
242 where
243 F: FnOnce(&'head RC) -> T,
244 RC: 'head,
245 T: 'head,
246 {
247 ArcGuard::new(self.clone(), getter)
248 }
249}