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
//! 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<Bar>, //! //! /* 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<RefCell<Bar>>`). //! - `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>(T); impl<T> Frozen<T> { pub fn freeze(val: T) -> Self { Frozen(val) } } impl<T> std::ops::Deref for Frozen<T> { type Target = T; fn deref(&self) -> &T { &self.0 } }