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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//
// Copyright 2018 Tamas Blummer
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//!
//! # Reference to persistent data
//! allows reference of a data space of 2^48

use page::PAGE_SIZE;

use std::cmp::Ordering;
use std::fmt;
use std::ops;

const INVALID: u64 = 0xffffffffffff;

#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
/// Pointer to persistent data. Limited to 2^48
pub struct PRef(u64);

impl Default for PRef {
    fn default() -> Self {
        PRef(INVALID)
    }
}

impl Ord for PRef {
    fn cmp(&self, other: &Self) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl PartialOrd for PRef {
    fn partial_cmp(&self, other: &PRef) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl From<u64> for PRef {
    fn from(n: u64) -> Self {
        PRef(n)
    }
}

impl fmt::Display for PRef {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", self.0)
    }
}

impl ops::Add<u64> for PRef {
    type Output = PRef;

    fn add(self, rhs: u64) -> <Self as ops::Add<u64>>::Output {
        PRef::from(self.as_u64() + rhs)
    }
}

impl ops::AddAssign<u64> for PRef {
    fn add_assign(&mut self, rhs: u64) {
        #[cfg(debug_assertions)]
        {
            if self.0 + rhs >= INVALID {
                panic!("Pref::from(INVALID)");
            }
        }
        self.0 += rhs;
    }
}

impl ops::Sub<u64> for PRef {
    type Output = PRef;

    fn sub(self, rhs: u64) -> <Self as ops::Sub<u64>>::Output {
        PRef::from(self.as_u64() - rhs)
    }
}

impl ops::SubAssign<u64> for PRef {
    fn sub_assign(&mut self, rhs: u64) {
        #[cfg(debug_assertions)]
        {
            if rhs > self.0 {
                panic!("pref would become invalid through subtraction");
            }
        }
        self.0 -= rhs;
    }
}

impl PRef {
    /// construct an invalid pref
    pub fn invalid () -> PRef {
        PRef(INVALID)
    }

    /// is this a valid pref?
    pub fn is_valid (&self) -> bool {
        self.0 < INVALID
    }

    /// convert to a number
    pub fn as_u64 (&self) -> u64 {
        return self.0;
    }

    /// pref of the page of this pref
    pub fn this_page(&self) -> PRef {
        PRef::from((self.0/ PAGE_SIZE as u64)* PAGE_SIZE as u64)
    }

    /// compute page number of an pref
    pub fn page_number(&self) -> u64 {
        self.0/PAGE_SIZE as u64
    }

    /// position within the pref's page
    pub fn in_page_pos(&self) -> usize {
        (self.0 % PAGE_SIZE as u64) as usize
    }
}