From da4e33a9e659071ae5e7418242dea38d951a260d Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 13 Mar 2020 13:28:25 -0500 Subject: move frozen to rustc_data_structures --- src/librustc_data_structures/frozen.rs | 57 ++++++++++++++++++++++++++++++++++ src/librustc_data_structures/lib.rs | 1 + 2 files changed, 58 insertions(+) create mode 100644 src/librustc_data_structures/frozen.rs (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/frozen.rs b/src/librustc_data_structures/frozen.rs new file mode 100644 index 00000000000..835fa7d839c --- /dev/null +++ b/src/librustc_data_structures/frozen.rs @@ -0,0 +1,57 @@ +//! An immutable, owned value. +//! +//! The purpose of `Frozen` is to make a value immutable for the sake of defensive programming. For example, +//! suppose we have the following: +//! +//! ```rust +//! struct Bar { /* some data */ } +//! +//! struct Foo { +//! /// Some computed data that should never change after construction. +//! pub computed: Bar, +//! +//! /* some other fields */ +//! } +//! +//! impl Bar { +//! /// Mutate the `Bar`. +//! pub fn mutate(&mut self) { } +//! } +//! ``` +//! +//! Now suppose we want to pass around a mutable `Foo` instance but, we want to make sure that +//! `computed` does not change accidentally (e.g. somebody might accidentally call +//! `foo.computed.mutate()`). This is what `Frozen` is for. We can do the following: +//! +//! ```rust +//! use rustc_data_structures::frozen::Frozen; +//! +//! struct Foo { +//! /// Some computed data that should never change after construction. +//! pub computed: Frozen, +//! +//! /* some other fields */ +//! } +//! ``` +//! +//! `Frozen` impls `Deref`, so we can ergonomically call methods on `Bar`, but it doesn't `impl +//! DerefMut`. Now calling `foo.compute.mutate()` will result in a compile-time error stating that +//! `mutate` requires a mutable reference but we don't have one. + +/// An owned immutable value. +#[derive(Debug)] +pub struct Frozen(T); + +impl Frozen { + pub fn freeze(val: T) -> Self { + Frozen(val) + } +} + +impl std::ops::Deref for Frozen { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 13792a0c890..f9f8ff5303e 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -94,6 +94,7 @@ pub mod profiling; pub mod vec_linked_list; pub mod work_queue; pub use atomic_ref::AtomicRef; +pub mod frozen; pub struct OnDrop(pub F); -- cgit 1.4.1-3-g733a5 From a58b17f2b5e57baa45ffb5b8c979faa3191bc05a Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 13 Mar 2020 13:36:16 -0500 Subject: update rustdocs for frozen --- src/librustc_data_structures/frozen.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/librustc_data_structures') diff --git a/src/librustc_data_structures/frozen.rs b/src/librustc_data_structures/frozen.rs index 835fa7d839c..2daf5b04141 100644 --- a/src/librustc_data_structures/frozen.rs +++ b/src/librustc_data_structures/frozen.rs @@ -1,4 +1,4 @@ -//! An immutable, owned value. +//! An immutable, owned value (except for interior mutability). //! //! The purpose of `Frozen` is to make a value immutable for the sake of defensive programming. For example, //! suppose we have the following: @@ -37,6 +37,12 @@ //! `Frozen` impls `Deref`, so we can ergonomically call methods on `Bar`, but it doesn't `impl //! DerefMut`. Now calling `foo.compute.mutate()` will result in a compile-time error stating that //! `mutate` requires a mutable reference but we don't have one. +//! +//! # Caveats +//! +//! - `Frozen` doesn't try to defend against interior mutability (e.g. `Frozen>`). +//! - `Frozen` doesn't pin it's contents (e.g. one could still do `foo.computed = +//! Frozen::freeze(new_bar)`). /// An owned immutable value. #[derive(Debug)] -- cgit 1.4.1-3-g733a5