1 //! An immutable, owned value (except for interior mutability).
3 //! The purpose of `Frozen` is to make a value immutable for the sake of defensive programming. For example,
4 //! suppose we have the following:
7 //! struct Bar { /* some data */ }
10 //! /// Some computed data that should never change after construction.
11 //! pub computed: Bar,
13 //! /* some other fields */
17 //! /// Mutate the `Bar`.
18 //! pub fn mutate(&mut self) { }
22 //! Now suppose we want to pass around a mutable `Foo` instance but, we want to make sure that
23 //! `computed` does not change accidentally (e.g. somebody might accidentally call
24 //! `foo.computed.mutate()`). This is what `Frozen` is for. We can do the following:
28 //! use rustc_data_structures::frozen::Frozen;
31 //! /// Some computed data that should never change after construction.
32 //! pub computed: Frozen<Bar>,
34 //! /* some other fields */
38 //! `Frozen` impls `Deref`, so we can ergonomically call methods on `Bar`, but it doesn't `impl
39 //! DerefMut`. Now calling `foo.compute.mutate()` will result in a compile-time error stating that
40 //! `mutate` requires a mutable reference but we don't have one.
44 //! - `Frozen` doesn't try to defend against interior mutability (e.g. `Frozen<RefCell<Bar>>`).
45 //! - `Frozen` doesn't pin it's contents (e.g. one could still do `foo.computed =
46 //! Frozen::freeze(new_bar)`).
48 /// An owned immutable value.
50 pub struct Frozen<T>(T);
53 pub fn freeze(val: T) -> Self {
58 impl<T> std::ops::Deref for Frozen<T> {
61 fn deref(&self) -> &T {