]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_data_structures/src/frozen.rs
Rollup merge of #106716 - c410-f3r:rfc-2397-1, r=davidtwco
[rust.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 //! ```
27 //! # struct Bar {}
28 //! use rustc_data_structures::frozen::Frozen;
29 //!
30 //! struct Foo {
31 //!     /// Some computed data that should never change after construction.
32 //!     pub computed: Frozen<Bar>,
33 //!
34 //!     /* some other fields */
35 //! }
36 //! ```
37 //!
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.
41 //!
42 //! # Caveats
43 //!
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)`).
47
48 /// An owned immutable value.
49 #[derive(Debug)]
50 pub struct Frozen<T>(T);
51
52 impl<T> Frozen<T> {
53     pub fn freeze(val: T) -> Self {
54         Frozen(val)
55     }
56 }
57
58 impl<T> std::ops::Deref for Frozen<T> {
59     type Target = T;
60
61     fn deref(&self) -> &T {
62         &self.0
63     }
64 }