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
147
pub struct Context<F: crate::SequenceFactory = crate::TimeSequenceFactory> {
	sequence_factory: F,
	sequence: F::Sequence,
	session: Session,
}

impl Default for Context<crate::TimeSequenceFactory> {
	fn default() -> Self {
		Self::new()
	}
}

impl<SequenceFactory: crate::SequenceFactory + Default> Context<SequenceFactory> {
	pub fn new() -> Self {
		Context {
			sequence_factory: Default::default(),
			sequence: SequenceFactory::base(),
			session: Session::new(),
		}
	}
}

impl<SequenceFactory: crate::SequenceFactory> Context<SequenceFactory> {
	pub fn next_sequence(&mut self) -> Sequence<SequenceFactory> {
		let next = self.sequence_factory.acquire(self.sequence.clone());
		assert!(next > self.sequence);

		self.sequence = next.clone();

		Sequence {
			value: next,
			session: self.session.clone(),
			undo: 0,
		}
	}

	/** Start a new session.
	 *
	 * This updates the session in this `Context`. This is similar to starting a new `Context` but it ensures that the sequences are still monotonically increasing across sessions which can be important for `Mergable` objects with last-write-wins semantics.
	 */
	pub fn new_session(&mut self) {
		self.session = Session::new();
	}

	pub fn session(&self) -> Session {
		self.session.clone()
	}
}

pub struct Sequence<SequenceFactory: crate::SequenceFactory> {
	value: SequenceFactory::Sequence,
	session: Session,
	undo: u8,
}

impl<SequenceFactory: crate::SequenceFactory> Sequence<SequenceFactory> {
	pub fn zero() -> Self {
		Sequence {
			value: SequenceFactory::base(),
			session: Session(u64::min_value()),
			undo: 0,
		}
	}

	pub fn undo(&self) -> Result<Self, crate::RevertError> {
		let mut r = self.clone();
		r.undo = self.undo.checked_add(1)
			.ok_or(crate::RevertError::TooManyRedos)?;
		Ok(r)
	}
}

impl<T: crate::SequenceFactory> std::fmt::Debug for Sequence<T>
	where T::Sequence: std::fmt::Debug
{
	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
		let Sequence{value, session, undo} = self;
		write!(f, "Sequence({:?}, {:?}, {:?})", value, session, undo)
	}
}

impl<SequenceFactory: crate::SequenceFactory> Clone for Sequence<SequenceFactory> {
	fn clone(&self) -> Self {
		Sequence {
			value: self.value.clone(),
			session: self.session.clone(),
			undo: self.undo,
		}
	}
}

impl<SequenceFactory: crate::SequenceFactory> std::cmp::PartialEq for Sequence<SequenceFactory> {
	fn eq(&self, that: &Self) -> bool {
		let Sequence{value, session, undo} = self;
		(value, session, undo) == (&that.value, &that.session, &that.undo)
	}
}

impl<SequenceFactory: crate::SequenceFactory> std::cmp::Eq for Sequence<SequenceFactory> {
}

impl<SequenceFactory: crate::SequenceFactory> std::cmp::PartialOrd for Sequence<SequenceFactory> {
	fn partial_cmp(&self, that: &Self) -> Option<std::cmp::Ordering> {
		let Sequence{value, session, undo} = self;
		std::cmp::PartialOrd::partial_cmp(
			&(value, session, undo),
			&(&that.value, &that.session, &that.undo))
	}
}

impl<SequenceFactory: crate::SequenceFactory> std::cmp::Ord for Sequence<SequenceFactory> {
	fn cmp(&self, that: &Self) -> std::cmp::Ordering {
		let Sequence{value, session, undo} = self;
		(value, session, undo).cmp(&(&that.value, &that.session, &that.undo))
	}
}

impl<SequenceFactory: crate::SequenceFactory> std::hash::Hash for Sequence<SequenceFactory> {
	fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
		let Sequence{value, session, undo} = self;
		value.hash(h);
		session.hash(h);
		undo.hash(h);
	}
}

#[derive(Clone,Eq,PartialEq,Hash,Ord,PartialOrd)]
pub struct Session(u64);

impl Session {
	pub fn new() -> Self {
		Self::unsafe_from_u64(rand::Rng::gen(&mut rand::thread_rng()))
	}

	/// Create a session from the provided value.
	///
	/// WARNING: If the same session id is used concurrently it may cause unspecified behaviour including crashes.
	pub fn unsafe_from_u64(session: u64) -> Self {
		Session(session)
	}
}

impl std::fmt::Debug for Session {
	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
		write!(f, "Session({:x})", self.0)
	}
}