Skip to main content

tuwunel_core/matrix/pdu/
raw_id.rs

1use std::fmt;
2
3use arrayvec::ArrayVec;
4use serde::{Deserialize, Deserializer};
5
6use super::{
7	super::{ShortId, ShortRoomId},
8	Count, Id,
9};
10
11/// Packed database key for a room's normal or backfilled PDU.
12///
13/// Both layouts begin with the big-endian compact room identifier. Normal keys
14/// are 16 bytes and backfilled keys are 24 bytes.
15#[derive(Clone, Copy, Eq, Hash, PartialEq)]
16pub enum RawId {
17	/// Packed key for an event in the normal timeline.
18	///
19	/// The key concatenates the room surrogate and unsigned count as two
20	/// big-endian integers.
21	Normal(RawIdNormal),
22
23	/// Packed key for an event in the backfilled timeline.
24	///
25	/// The key inserts an eight-byte zero marker between the room surrogate and
26	/// signed count bits.
27	Backfilled(RawIdBackfilled),
28}
29
30type RawIdNormal = [u8; RawId::NORMAL_LEN];
31type RawIdBackfilled = [u8; RawId::BACKFILLED_LEN];
32
33struct RawIdVisitor;
34
35const INT_LEN: usize = size_of::<ShortId>();
36
37impl RawId {
38	const BACKFILLED_LEN: usize = size_of::<ShortRoomId>() + INT_LEN + size_of::<i64>();
39	const MAX_LEN: usize = Self::BACKFILLED_LEN;
40	const NORMAL_LEN: usize = size_of::<ShortRoomId>() + size_of::<u64>();
41
42	/// Checks whether two raw PDU keys belong to the same room.
43	///
44	/// Only the leading compact room identifier is compared. Timeline kind and
45	/// event count do not affect the result.
46	#[inline]
47	#[must_use]
48	pub fn is_room_eq(self, other: Self) -> bool { self.shortroomid() == other.shortroomid() }
49
50	/// Decodes the timeline count stored in this raw key.
51	///
52	/// Normal and backfilled layouts are converted to the corresponding `Count`
53	/// variant. The compact room identifier is ignored.
54	#[inline]
55	#[must_use]
56	pub fn pdu_count(self) -> Count {
57		let id: Id = self.into();
58		id.count
59	}
60
61	/// Returns the encoded compact room identifier.
62	///
63	/// The bytes remain in big-endian database order. Use `Id::from` when a
64	/// typed integer value is needed.
65	#[inline]
66	#[must_use]
67	pub fn shortroomid(self) -> [u8; INT_LEN] {
68		match self {
69			| Self::Normal(raw) => raw[0..INT_LEN]
70				.try_into()
71				.expect("normal raw shortroomid array from slice"),
72			| Self::Backfilled(raw) => raw[0..INT_LEN]
73				.try_into()
74				.expect("backfilled raw shortroomid array from slice"),
75		}
76	}
77
78	/// Returns the encoded timeline count.
79	///
80	/// The bytes remain in big-endian database order. For backfilled keys the
81	/// intervening zero marker is omitted.
82	#[inline]
83	#[must_use]
84	pub fn count(self) -> [u8; INT_LEN] {
85		match self {
86			| Self::Normal(raw) => raw[INT_LEN..INT_LEN * 2]
87				.try_into()
88				.expect("normal raw indice array from slice"),
89			| Self::Backfilled(raw) => raw[INT_LEN * 2..INT_LEN * 3]
90				.try_into()
91				.expect("backfilled raw indice array from slice"),
92		}
93	}
94
95	/// Borrows the complete packed database key.
96	///
97	/// The returned slice is 16 bytes for a normal key and 24 bytes for a
98	/// backfilled key. Its lifetime is tied to this value.
99	#[inline]
100	#[must_use]
101	pub fn as_bytes(&self) -> &[u8] {
102		match self {
103			| Self::Normal(raw) => raw,
104			| Self::Backfilled(raw) => raw,
105		}
106	}
107}
108
109impl fmt::Debug for RawId {
110	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111		let id: Id = (*self).into();
112		write!(f, "{id:?}")
113	}
114}
115
116impl<'de> Deserialize<'de> for RawId {
117	#[inline]
118	fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
119		d.deserialize_bytes(RawIdVisitor)
120	}
121}
122
123impl serde::de::Visitor<'_> for RawIdVisitor {
124	type Value = RawId;
125
126	fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127		f.write_str("RawId byte array")
128	}
129
130	#[inline]
131	fn visit_bytes<E>(self, buf: &[u8]) -> Result<RawId, E> { Ok(RawId::from(buf)) }
132}
133
134impl From<Id> for RawId {
135	#[inline]
136	fn from(id: Id) -> Self {
137		const MAX_LEN: usize = RawId::MAX_LEN;
138		type RawVec = ArrayVec<u8, MAX_LEN>;
139
140		let mut vec = RawVec::new();
141		vec.extend(id.shortroomid.to_be_bytes());
142		id.count.debug_assert_valid();
143		match id.count {
144			| Count::Normal(count) => {
145				vec.extend(count.to_be_bytes());
146				Self::Normal(
147					vec.as_ref()
148						.try_into()
149						.expect("RawVec into RawId::Normal"),
150				)
151			},
152			| Count::Backfilled(count) => {
153				vec.extend(0_u64.to_be_bytes());
154				vec.extend(count.to_be_bytes());
155				Self::Backfilled(
156					vec.as_ref()
157						.try_into()
158						.expect("RawVec into RawId::Backfilled"),
159				)
160			},
161		}
162	}
163}
164
165impl From<&[u8]> for RawId {
166	#[inline]
167	fn from(id: &[u8]) -> Self {
168		match id.len() {
169			| Self::NORMAL_LEN => Self::Normal(
170				id[0..Self::NORMAL_LEN]
171					.try_into()
172					.expect("normal RawId from [u8]"),
173			),
174			| Self::BACKFILLED_LEN => Self::Backfilled(
175				id[0..Self::BACKFILLED_LEN]
176					.try_into()
177					.expect("backfilled RawId from [u8]"),
178			),
179			| _ => unimplemented!("unrecognized RawId length"),
180		}
181	}
182}
183
184impl From<&[u8; Self::NORMAL_LEN]> for RawId {
185	#[inline]
186	fn from(id: &[u8; Self::NORMAL_LEN]) -> Self { Self::Normal(*id) }
187}
188
189impl From<&[u8; Self::BACKFILLED_LEN]> for RawId {
190	#[inline]
191	fn from(id: &[u8; Self::BACKFILLED_LEN]) -> Self { Self::Backfilled(*id) }
192}
193
194impl AsRef<[u8]> for RawId {
195	#[inline]
196	fn as_ref(&self) -> &[u8] { self.as_bytes() }
197}