1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Data isolation.
// TODO(https://fxbug.dev/42067751): This type should not derive `PartialEq`. Though it only allows trivial
// observation (i.e., "is this black box the same as that black box?"),
// that is observation nonetheless and client code could foreseeably branch
// based on this query. It is implemented to ease the implementation of
// tests, where assertions of equality are ubiquitous.
/// Isolates data such that it is inaccessible without explicitly releasing it.
///
/// Sequestered data cannot be directly read nor written while contained (though it can be
/// trivially replaced). This is useful for data that must be "ferried" through a system but should
/// not generally be examined nor inspected, in particular when inspection of the data would
/// otherwise seem innocuous but implicitly violates a design contract or introduces an unwanted
/// data dependency.
///
/// **This type cannot completely prevent reads and writes.** Rather, it makes reads and writes
/// very explicit and more obvious in order to avoid mistakes in data APIs.
///
/// Sequestering data is trivial and is done via the core `From` and `Into` traits. Releasing data
/// is intentionally more explicit and requires the use of fully-qualified syntax that names the
/// `Sequestered` type.
///
/// As sequestered data is considered a "black box", `Sequestered` only implements the `Clone` and
/// `Debug` traits (so long as the type `T` provides implementations). Note that `Copy` is not
/// implemented, because releasing data would not be strictly affine and data could be implicitly
/// copied out of fields via `release`. This is not only implicit, but can be counterintuitive in
/// some contexts, because `release` moves a copy of the `Sequestered`.
///
/// `Sequestered` also implements `PartialEq` largely for testing. See https://fxbug.dev/42067751.
#[derive(Clone, Debug, PartialEq)]
#[repr(transparent)]
pub struct Sequestered<T>(T);
impl<T> Sequestered<T> {
/// Releases the sequestered data.
///
/// Releasing should be performed sparingly, carefully, and typically at API boundaries where
/// there is no longer a need to prevent reads of the data. Releases, which are explicit,
/// should be given extra scrutiny, somewhat like `unsafe` code.
///
/// This function does not use a receiver and so requires fully-qualified syntax in order to
/// make releases more explicit and obvious.
///
/// # Examples
///
/// ```rust,ignore
/// // Sequester data.
/// let text: Sequestered<&'static str> = "lorem ipsum".into();
/// // Release data. The fully-qualified syntax is required.
/// let text = Sequestered::release(text);
/// ```
#[inline(always)]
pub fn release(sequestered: Self) -> T {
sequestered.0
}
}
impl<T> From<T> for Sequestered<T> {
#[inline(always)]
fn from(inner: T) -> Self {
Sequestered(inner)
}
}