Skip to main content

explicit/
lib.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Utilities which allow code to be more robust to changes in dependencies.
6//!
7//! The utilities in this crate allow code to depend on details of its
8//! dependencies which would not normally be captured by code using the
9//! canonical Rust style. See [this document][rust-patterns] for a discussion of
10//! when and why this might be desirable.
11//!
12//! [rust-patterns]: https://fuchsia.dev/fuchsia-src/contribute/contributing-to-netstack/rust-patterns
13
14#![no_std]
15#![warn(missing_docs)]
16
17use core::task::Poll;
18
19/// An extension trait adding functionality to [`Result`].
20pub trait ResultExt<T, E> {
21    /// Like [`Result::ok`], but the caller must provide the error type being
22    /// discarded.
23    ///
24    /// This allows code to be written which will stop compiling if a result's
25    /// error type changes in the future.
26    fn ok_checked<EE: sealed::EqType<E>>(self) -> Option<T>;
27
28    /// Like [`Result::err`], but the caller must provide the ok type being
29    /// discarded.
30    ///
31    /// This allows code to be written which will stop compiling if a result's
32    /// ok type changes in the future.
33    fn err_checked<TT: sealed::EqType<T>>(self) -> Option<E>;
34}
35
36impl<T, E> ResultExt<T, E> for Result<T, E> {
37    fn ok_checked<EE: sealed::EqType<E>>(self) -> Option<T> {
38        Result::ok(self)
39    }
40
41    fn err_checked<TT: sealed::EqType<T>>(self) -> Option<E> {
42        Result::err(self)
43    }
44}
45
46/// An extension trait adding functionality to [`Poll`].
47pub trait PollExt<T> {
48    /// Like [`Poll::is_ready`], but the caller must provide the inner type.
49    ///
50    /// This allows both the authors and the reviewers to check if information
51    /// is being discarded unnoticed.
52    fn is_ready_checked<TT: sealed::EqType<T>>(&self) -> bool;
53}
54
55impl<T> PollExt<T> for Poll<T> {
56    fn is_ready_checked<TT: sealed::EqType<T>>(&self) -> bool {
57        Poll::is_ready(self)
58    }
59}
60
61/// A trait providing unreachability assertion enforced by the type system.
62///
63/// # Example
64/// ```
65///
66/// /// Provides guaranteed winning lottery numbers.
67/// trait LotteryOracle {
68///   fn get_winning_number(&self) -> u32;
69/// }
70///
71/// // Might return a thing that gives winning lottery numbers.
72/// fn try_get_lottery_oracle() -> Option<impl LotteryOracle> {
73///   // This function always returns `None` but we still need a type that
74///   // the option _could_ hold.
75///
76///   /// Uninstantiable type that implements [`LotteryOracle`].
77///   struct UninstantiableOracle(!);
78///
79///   /// Enable use with [`UnreachableExt`].
80///   impl AsRef<!> for UninstantiableOracle {
81///     fn as_ref(&self) -> ! {
82///       &self.0
83///     }
84///   }
85///
86///   /// Trivial implementation that can't actually be used.
87///   impl LotteryOracle for UninstantiableOracle {
88///     fn get_winning_number(&self) -> u32 {
89///       self.uninstantiable_unreachable()
90///     }
91///   }
92///
93///   Option::<UninstantiableOracle>::None
94/// }
95/// ```
96///
97/// # Implementing
98///
99/// This trait is blanket-implemented for any type that can be used to construct
100/// an instance of `!`. To use it, simply implement [`AsRef<!>`].
101pub trait UnreachableExt: sealed::Sealed {
102    /// A method that can't be called.
103    ///
104    /// This method returns an instance of any caller-specified type, which
105    /// makes it impossible to implement unless the method receiver is itself
106    /// uninstantiable. This method is similar to the `unreachable!` macro, but
107    /// should be preferred over the macro since it uses the type system to
108    /// enforce unreachability where `unreachable!` indicates a logical
109    /// assertion checked at runtime.
110    fn uninstantiable_unreachable<T>(&self) -> T;
111}
112
113impl<N: AsRef<!>> UnreachableExt for N {
114    fn uninstantiable_unreachable<T>(&self) -> T {
115        match *self.as_ref() {}
116    }
117}
118
119mod sealed {
120
121    /// `EqType<T>` indicates that the implementer is equal to `T`.
122    ///
123    /// For all `T`, `T: EqType<T>`. For all distinct `T` and `U`, `T:
124    /// !EqType<U>`.
125    pub trait EqType<T> {}
126
127    impl<T> EqType<T> for T {}
128
129    /// Trait that can only be implemented within this crate.
130    pub trait Sealed {}
131
132    impl<T: AsRef<!>> Sealed for T {}
133}