Expand description

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:

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:

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)).

Structs

  • An owned immutable value.