//! 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: //! //! ```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. //! //! # 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)] 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 } }