]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_data_structures/src/frozen.rs
New upstream version 1.49.0+dfsg1
[rustc.git] / compiler / rustc_data_structures / src / frozen.rs
1 //! An immutable, owned value (except for interior mutability).
2 //!
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:
5 //!
6 //! ```rust
7 //! struct Bar { /* some data */ }
8 //!
9 //! struct Foo {
10 //! /// Some computed data that should never change after construction.
11 //! pub computed: Bar,
12 //!
13 //! /* some other fields */
14 //! }
15 //!
16 //! impl Bar {
17 //! /// Mutate the `Bar`.
18 //! pub fn mutate(&mut self) { }
19 //! }
20 //! ```
21 //!
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:
25 //!
26 //! ```rust
27 //! use rustc_data_structures::frozen::Frozen;
28 //!
29 //! struct Foo {
30 //! /// Some computed data that should never change after construction.
31 //! pub computed: Frozen<Bar>,
32 //!
33 //! /* some other fields */
34 //! }
35 //! ```
36 //!
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.
40 //!
41 //! # Caveats
42 //!
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)`).
46
47 /// An owned immutable value.
48 #[derive(Debug)]
49 pub struct Frozen<T>(T);
50
51 impl<T> Frozen<T> {
52 pub fn freeze(val: T) -> Self {
53 Frozen(val)
54 }
55 }
56
57 impl<T> std::ops::Deref for Frozen<T> {
58 type Target = T;
59
60 fn deref(&self) -> &T {
61 &self.0
62 }
63 }