1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! Definition of [`Snapshot`]

use crate::*;

#[cfg(creusot)]
use crate::std::ops::Deref;

/// A copyable snapshot, usable in pearlite.
///
/// The `Snapshot` type contains the logical value of some data, in a purely immutable way.
/// It is zero sized.
///
/// Creating a snapshot does _not_ move the ownership of a value.
///
/// # Pearlite syntax
///
/// In executable code, you may create a snapshot with the [`snapshot!`] macro. Inside
/// this macro, you may write _pearlite_ code; this code will not run during the normal
/// execution of the program.
///
/// ## Example
///
/// ```
/// # use creusot_contracts::{*, logic::Mapping};
/// let x: Snapshot<Int> = snapshot!(1);
/// let m: Snapshot<Mapping<Int, Int>> = snapshot!(|x| x + 1);
/// ```
#[trusted]
#[rustc_diagnostic_item = "snapshot_ty"]
#[cfg_attr(creusot, creusot::builtins = "prelude.prelude.Snapshot.snap_ty")]
pub struct Snapshot<T: ?Sized>(pub(crate) std::marker::PhantomData<T>);

#[cfg(creusot)]
impl<T: ?Sized> Deref for Snapshot<T> {
    type Target = T;

    #[trusted]
    #[logic]
    #[rustc_diagnostic_item = "snapshot_deref"]
    #[creusot::builtins = "prelude.prelude.Snapshot.inner"]
    fn deref(&self) -> &Self::Target {
        dead
    }
}

impl<T: View + ?Sized> View for Snapshot<T> {
    type ViewTy = T::ViewTy;

    #[logic]
    #[open]
    fn view(self) -> Self::ViewTy {
        pearlite! { self.deref().view() }
    }
}

impl<T: ?Sized> Clone for Snapshot<T> {
    #[pure]
    #[ensures(result == *self)]
    fn clone(&self) -> Self {
        *self
    }
}

impl<T: ?Sized> Copy for Snapshot<T> {}

impl<T: ?Sized> Snapshot<T> {
    /// Create a new snapshot in logic code.
    #[trusted]
    #[logic]
    #[creusot::builtins = "prelude.prelude.Snapshot.new"]
    #[rustc_diagnostic_item = "snapshot_new"]
    pub fn new(value: T) -> Snapshot<T> {
        let _ = value;
        dead
    }

    /// Get the value of the snapshot.
    ///
    /// When possible, you should instead use the dereference operator.
    ///
    /// # Example
    /// ```
    /// # use creusot_contracts::*;
    /// let x = snapshot!(1);
    /// proof_assert!(x.inner() == 1);
    /// proof_assert!(*x == 1); // prefer this
    /// ```
    #[trusted]
    #[logic]
    #[rustc_diagnostic_item = "snapshot_inner"]
    #[creusot::builtins = "prelude.prelude.Snapshot.inner"]
    pub fn inner(self) -> T
    where
        T: Sized, // TODO: don't require T: Sized here. Problem: return type is T.
    {
        dead
    }

    /// Internal function used in the `snapshot!` macro.
    #[doc(hidden)]
    #[cfg(not(creusot))]
    pub fn from_fn(_: fn() -> T) -> Self {
        Snapshot(std::marker::PhantomData)
    }
}