refactor for stronger RawPduId type
implement standard traits for PduCount enable serde for arrayvec typedef various shortid's pducount simplifications split parts of pdu_metadata service to core/pdu and api/relations remove some yields; improve var names/syntax tweak types for limit timeline limit arguments Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
parent
2e4d9cb37c
commit
9da523c004
41 changed files with 796 additions and 573 deletions
|
@ -17,7 +17,7 @@ pub use ::tracing;
|
|||
pub use config::Config;
|
||||
pub use error::Error;
|
||||
pub use info::{rustc_flags_capture, version, version::version};
|
||||
pub use pdu::{Event, PduBuilder, PduCount, PduEvent};
|
||||
pub use pdu::{Event, PduBuilder, PduCount, PduEvent, PduId, RawPduId};
|
||||
pub use server::Server;
|
||||
pub use utils::{ctor, dtor, implement, result, result::Result};
|
||||
|
||||
|
|
|
@ -1,38 +1,135 @@
|
|||
use std::cmp::Ordering;
|
||||
#![allow(clippy::cast_possible_wrap, clippy::cast_sign_loss, clippy::as_conversions)]
|
||||
|
||||
use ruma::api::client::error::ErrorKind;
|
||||
use std::{cmp::Ordering, fmt, fmt::Display, str::FromStr};
|
||||
|
||||
use crate::{Error, Result};
|
||||
use crate::{err, Error, Result};
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum PduCount {
|
||||
Backfilled(u64),
|
||||
Normal(u64),
|
||||
Backfilled(i64),
|
||||
}
|
||||
|
||||
impl PduCount {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn min() -> Self { Self::Backfilled(u64::MAX) }
|
||||
pub fn from_unsigned(unsigned: u64) -> Self { Self::from_signed(unsigned as i64) }
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn max() -> Self { Self::Normal(u64::MAX) }
|
||||
|
||||
pub fn try_from_string(token: &str) -> Result<Self> {
|
||||
if let Some(stripped_token) = token.strip_prefix('-') {
|
||||
stripped_token.parse().map(PduCount::Backfilled)
|
||||
} else {
|
||||
token.parse().map(PduCount::Normal)
|
||||
pub fn from_signed(signed: i64) -> Self {
|
||||
match signed {
|
||||
i64::MIN..=0 => Self::Backfilled(signed),
|
||||
_ => Self::Normal(signed as u64),
|
||||
}
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid pagination token."))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn stringify(&self) -> String {
|
||||
pub fn into_unsigned(self) -> u64 {
|
||||
self.debug_assert_valid();
|
||||
match self {
|
||||
Self::Backfilled(x) => format!("-{x}"),
|
||||
Self::Normal(x) => x.to_string(),
|
||||
Self::Normal(i) => i,
|
||||
Self::Backfilled(i) => i as u64,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn into_signed(self) -> i64 {
|
||||
self.debug_assert_valid();
|
||||
match self {
|
||||
Self::Normal(i) => i as i64,
|
||||
Self::Backfilled(i) => i,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn into_normal(self) -> Self {
|
||||
self.debug_assert_valid();
|
||||
match self {
|
||||
Self::Normal(i) => Self::Normal(i),
|
||||
Self::Backfilled(_) => Self::Normal(0),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn checked_add(self, add: u64) -> Result<Self, Error> {
|
||||
Ok(match self {
|
||||
Self::Normal(i) => Self::Normal(
|
||||
i.checked_add(add)
|
||||
.ok_or_else(|| err!(Arithmetic("PduCount::Normal overflow")))?,
|
||||
),
|
||||
Self::Backfilled(i) => Self::Backfilled(
|
||||
i.checked_add(add as i64)
|
||||
.ok_or_else(|| err!(Arithmetic("PduCount::Backfilled overflow")))?,
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn checked_sub(self, sub: u64) -> Result<Self, Error> {
|
||||
Ok(match self {
|
||||
Self::Normal(i) => Self::Normal(
|
||||
i.checked_sub(sub)
|
||||
.ok_or_else(|| err!(Arithmetic("PduCount::Normal underflow")))?,
|
||||
),
|
||||
Self::Backfilled(i) => Self::Backfilled(
|
||||
i.checked_sub(sub as i64)
|
||||
.ok_or_else(|| err!(Arithmetic("PduCount::Backfilled underflow")))?,
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn saturating_add(self, add: u64) -> Self {
|
||||
match self {
|
||||
Self::Normal(i) => Self::Normal(i.saturating_add(add)),
|
||||
Self::Backfilled(i) => Self::Backfilled(i.saturating_add(add as i64)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn saturating_sub(self, sub: u64) -> Self {
|
||||
match self {
|
||||
Self::Normal(i) => Self::Normal(i.saturating_sub(sub)),
|
||||
Self::Backfilled(i) => Self::Backfilled(i.saturating_sub(sub as i64)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn min() -> Self { Self::Backfilled(i64::MIN) }
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn max() -> Self { Self::Normal(i64::MAX as u64) }
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn debug_assert_valid(&self) {
|
||||
if let Self::Backfilled(i) = self {
|
||||
debug_assert!(*i <= 0, "Backfilled sequence must be negative");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PduCount {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
self.debug_assert_valid();
|
||||
match self {
|
||||
Self::Normal(i) => write!(f, "{i}"),
|
||||
Self::Backfilled(i) => write!(f, "{i}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PduCount {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(token: &str) -> Result<Self, Self::Err> { Ok(Self::from_signed(token.parse()?)) }
|
||||
}
|
||||
|
||||
impl PartialOrd for PduCount {
|
||||
|
@ -40,12 +137,9 @@ impl PartialOrd for PduCount {
|
|||
}
|
||||
|
||||
impl Ord for PduCount {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self, other) {
|
||||
(Self::Normal(s), Self::Normal(o)) => s.cmp(o),
|
||||
(Self::Backfilled(s), Self::Backfilled(o)) => o.cmp(s),
|
||||
(Self::Normal(_), Self::Backfilled(_)) => Ordering::Greater,
|
||||
(Self::Backfilled(_), Self::Normal(_)) => Ordering::Less,
|
||||
}
|
||||
}
|
||||
fn cmp(&self, other: &Self) -> Ordering { self.into_signed().cmp(&other.into_signed()) }
|
||||
}
|
||||
|
||||
impl Default for PduCount {
|
||||
fn default() -> Self { Self::Normal(0) }
|
||||
}
|
||||
|
|
22
src/core/pdu/id.rs
Normal file
22
src/core/pdu/id.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
use super::{PduCount, RawPduId};
|
||||
use crate::utils::u64_from_u8x8;
|
||||
|
||||
pub type ShortRoomId = ShortId;
|
||||
pub type ShortEventId = ShortId;
|
||||
pub type ShortId = u64;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct PduId {
|
||||
pub shortroomid: ShortRoomId,
|
||||
pub shorteventid: PduCount,
|
||||
}
|
||||
|
||||
impl From<RawPduId> for PduId {
|
||||
#[inline]
|
||||
fn from(raw: RawPduId) -> Self {
|
||||
Self {
|
||||
shortroomid: u64_from_u8x8(raw.shortroomid()),
|
||||
shorteventid: PduCount::from_unsigned(u64_from_u8x8(raw.shorteventid())),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,8 +4,12 @@ mod count;
|
|||
mod event;
|
||||
mod event_id;
|
||||
mod filter;
|
||||
mod id;
|
||||
mod raw_id;
|
||||
mod redact;
|
||||
mod relation;
|
||||
mod strip;
|
||||
mod tests;
|
||||
mod unsigned;
|
||||
|
||||
use std::{cmp::Ordering, sync::Arc};
|
||||
|
@ -21,6 +25,8 @@ pub use self::{
|
|||
count::PduCount,
|
||||
event::Event,
|
||||
event_id::*,
|
||||
id::*,
|
||||
raw_id::*,
|
||||
};
|
||||
use crate::Result;
|
||||
|
||||
|
|
117
src/core/pdu/raw_id.rs
Normal file
117
src/core/pdu/raw_id.rs
Normal file
|
@ -0,0 +1,117 @@
|
|||
use arrayvec::ArrayVec;
|
||||
|
||||
use super::{PduCount, PduId, ShortEventId, ShortId, ShortRoomId};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum RawPduId {
|
||||
Normal(RawPduIdNormal),
|
||||
Backfilled(RawPduIdBackfilled),
|
||||
}
|
||||
|
||||
type RawPduIdNormal = [u8; RawPduId::NORMAL_LEN];
|
||||
type RawPduIdBackfilled = [u8; RawPduId::BACKFILLED_LEN];
|
||||
|
||||
const INT_LEN: usize = size_of::<ShortId>();
|
||||
|
||||
impl RawPduId {
|
||||
const BACKFILLED_LEN: usize = size_of::<ShortRoomId>() + INT_LEN + size_of::<ShortEventId>();
|
||||
const MAX_LEN: usize = Self::BACKFILLED_LEN;
|
||||
const NORMAL_LEN: usize = size_of::<ShortRoomId>() + size_of::<ShortEventId>();
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn pdu_count(&self) -> PduCount {
|
||||
let id: PduId = (*self).into();
|
||||
id.shorteventid
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn shortroomid(self) -> [u8; INT_LEN] {
|
||||
match self {
|
||||
Self::Normal(raw) => raw[0..INT_LEN]
|
||||
.try_into()
|
||||
.expect("normal raw shortroomid array from slice"),
|
||||
Self::Backfilled(raw) => raw[0..INT_LEN]
|
||||
.try_into()
|
||||
.expect("backfilled raw shortroomid array from slice"),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn shorteventid(self) -> [u8; INT_LEN] {
|
||||
match self {
|
||||
Self::Normal(raw) => raw[INT_LEN..INT_LEN * 2]
|
||||
.try_into()
|
||||
.expect("normal raw shorteventid array from slice"),
|
||||
Self::Backfilled(raw) => raw[INT_LEN * 2..INT_LEN * 3]
|
||||
.try_into()
|
||||
.expect("backfilled raw shorteventid array from slice"),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
match self {
|
||||
Self::Normal(ref raw) => raw,
|
||||
Self::Backfilled(ref raw) => raw,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for RawPduId {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] { self.as_bytes() }
|
||||
}
|
||||
|
||||
impl From<&[u8]> for RawPduId {
|
||||
#[inline]
|
||||
fn from(id: &[u8]) -> Self {
|
||||
match id.len() {
|
||||
Self::NORMAL_LEN => Self::Normal(
|
||||
id[0..Self::NORMAL_LEN]
|
||||
.try_into()
|
||||
.expect("normal RawPduId from [u8]"),
|
||||
),
|
||||
Self::BACKFILLED_LEN => Self::Backfilled(
|
||||
id[0..Self::BACKFILLED_LEN]
|
||||
.try_into()
|
||||
.expect("backfilled RawPduId from [u8]"),
|
||||
),
|
||||
_ => unimplemented!("unrecognized RawPduId length"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PduId> for RawPduId {
|
||||
#[inline]
|
||||
fn from(id: PduId) -> Self {
|
||||
const MAX_LEN: usize = RawPduId::MAX_LEN;
|
||||
type RawVec = ArrayVec<u8, MAX_LEN>;
|
||||
|
||||
let mut vec = RawVec::new();
|
||||
vec.extend(id.shortroomid.to_be_bytes());
|
||||
id.shorteventid.debug_assert_valid();
|
||||
match id.shorteventid {
|
||||
PduCount::Normal(shorteventid) => {
|
||||
vec.extend(shorteventid.to_be_bytes());
|
||||
Self::Normal(
|
||||
vec.as_ref()
|
||||
.try_into()
|
||||
.expect("RawVec into RawPduId::Normal"),
|
||||
)
|
||||
},
|
||||
PduCount::Backfilled(shorteventid) => {
|
||||
vec.extend(0_u64.to_be_bytes());
|
||||
vec.extend(shorteventid.to_be_bytes());
|
||||
Self::Backfilled(
|
||||
vec.as_ref()
|
||||
.try_into()
|
||||
.expect("RawVec into RawPduId::Backfilled"),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
22
src/core/pdu/relation.rs
Normal file
22
src/core/pdu/relation.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
use ruma::events::relation::RelationType;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::implement;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
struct ExtractRelType {
|
||||
rel_type: RelationType,
|
||||
}
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
struct ExtractRelatesToEventId {
|
||||
#[serde(rename = "m.relates_to")]
|
||||
relates_to: ExtractRelType,
|
||||
}
|
||||
|
||||
#[implement(super::PduEvent)]
|
||||
#[must_use]
|
||||
pub fn relation_type_equal(&self, rel_type: &RelationType) -> bool {
|
||||
self.get_content()
|
||||
.map(|c: ExtractRelatesToEventId| c.relates_to.rel_type)
|
||||
.is_ok_and(|r| r == *rel_type)
|
||||
}
|
19
src/core/pdu/tests.rs
Normal file
19
src/core/pdu/tests.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
#![cfg(test)]
|
||||
|
||||
use super::PduCount;
|
||||
|
||||
#[test]
|
||||
fn backfilled_parse() {
|
||||
let count: PduCount = "-987654".parse().expect("parse() failed");
|
||||
let backfilled = matches!(count, PduCount::Backfilled(_));
|
||||
|
||||
assert!(backfilled, "not backfilled variant");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normal_parse() {
|
||||
let count: PduCount = "987654".parse().expect("parse() failed");
|
||||
let backfilled = matches!(count, PduCount::Backfilled(_));
|
||||
|
||||
assert!(!backfilled, "backfilled variant");
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue