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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use crate::sync::atomic::{AtomicU8, Ordering};
/// Describes how likely a value is to change—how "durable" it is.
///
/// By default, inputs have [`Durability::LOW`] and interned values have
/// [`Durability::NEVER_CHANGE`]. Inputs can be explicitly set with other
/// durabilities.
///
/// We use durabilities to optimize the work of "revalidating" a query
/// after some input has changed. Ordinarily, in a new revision,
/// queries have to trace all their inputs back to the base inputs to
/// determine if any of those inputs have changed. But if we know that
/// the only changes were to inputs of low durability (the common
/// case), and we know that the query only used inputs of medium
/// durability or higher, then we can skip that enumeration.
///
/// Typically, one assigns low durabilities to inputs that the user is
/// frequently editing. Medium or high durabilities are used for
/// configuration, the source from library crates, or other things
/// that are unlikely to be edited.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Durability(DurabilityVal);
#[cfg(feature = "persistence")]
impl serde::Serialize for Durability {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde::Serialize::serialize(&(self.0 as u8), serializer)
}
}
#[cfg(feature = "persistence")]
impl<'de> serde::Deserialize<'de> for Durability {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
u8::deserialize(deserializer).map(|value| Self(DurabilityVal::from(value)))
}
}
impl std::fmt::Debug for Durability {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
match self.0 {
DurabilityVal::Low => f.write_str("Durability::LOW"),
DurabilityVal::Medium => f.write_str("Durability::MEDIUM"),
DurabilityVal::High => f.write_str("Durability::HIGH"),
DurabilityVal::NeverChange => f.write_str("Durability::NEVER_CHANGE"),
}
} else {
f.debug_tuple("Durability")
.field(&(self.0 as usize))
.finish()
}
}
}
// We use an enum here instead of a u8 for niches.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum DurabilityVal {
Low = 0,
Medium = 1,
High = 2,
NeverChange = 3,
}
impl From<u8> for DurabilityVal {
fn from(value: u8) -> Self {
match value {
0 => DurabilityVal::Low,
1 => DurabilityVal::Medium,
2 => DurabilityVal::High,
3 => DurabilityVal::NeverChange,
_ => panic!("invalid durability"),
}
}
}
impl Durability {
/// Low durability: things that change frequently.
///
/// Example: part of the crate being edited
pub const LOW: Durability = Durability(DurabilityVal::Low);
/// Medium durability: things that change sometimes, but rarely.
///
/// Example: a Cargo.toml file
pub const MEDIUM: Durability = Durability(DurabilityVal::Medium);
/// High durability: things that are not expected to change under
/// common usage.
///
/// Example: the standard library or something from crates.io
pub const HIGH: Durability = Durability(DurabilityVal::High);
/// Values with this durability never change in place.
///
/// Setting an input field to this durability permanently freezes that
/// field. Any later attempt to change its value or durability will panic.
pub const NEVER_CHANGE: Durability = Durability(DurabilityVal::NeverChange);
/// The minimum possible durability; equivalent to LOW but
/// "conceptually" distinct (i.e., if we add more durability
/// levels, this could change).
pub(crate) const MIN: Durability = Self::LOW;
/// The maximum possible durability; equivalent to NEVER_CHANGE but
/// "conceptually" distinct (i.e., if we add more durability
/// levels, this could change).
pub(crate) const MAX: Durability = Self::NEVER_CHANGE;
/// Number of durability levels whose last-change revision is tracked.
/// `NEVER_CHANGE` needs no runtime revision slot.
pub(crate) const LEN: usize = Self::HIGH.0 as usize + 1;
pub(crate) fn index(self) -> usize {
self.0 as usize
}
}
impl Default for Durability {
fn default() -> Self {
Durability::LOW
}
}
/// Durability published to readers without taking the interned shard lock.
pub(crate) struct AtomicDurability(AtomicU8);
impl AtomicDurability {
pub(crate) fn new(durability: Durability) -> Self {
Self(AtomicU8::new(durability.0 as u8))
}
#[inline]
pub(crate) fn load(&self) -> Durability {
Durability(DurabilityVal::from(self.0.load(Ordering::Acquire)))
}
pub(crate) fn store(&self, durability: Durability) {
self.0.store(durability.0 as u8, Ordering::Release);
}
}