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:
27 //! use rustc_data_structures::frozen::Frozen;
30 //! /// Some computed data that should never change after construction.
31 //! pub computed: Frozen<Bar>,
33 //! /* some other fields */
37 //! `Frozen` impls `Deref`, so we can ergonomically call methods on `Bar`, but it doesn't `impl
38 //! DerefMut`. Now calling `foo.compute.mutate()` will result in a compile-time error stating that
39 //! `mutate` requires a mutable reference but we don't have one.
43 //! - `Frozen` doesn't try to defend against interior mutability (e.g. `Frozen<RefCell<Bar>>`).
44 //! - `Frozen` doesn't pin it's contents (e.g. one could still do `foo.computed =
45 //! Frozen::freeze(new_bar)`).
47 /// An owned immutable value.
49 pub struct Frozen<T>(T);
52 pub fn freeze(val: T) -> Self {
57 impl<T> std::ops::Deref for Frozen<T> {
60 fn deref(&self) -> &T {