Skip to content

Commit c5c55a1

Browse files
committed
perf: niche rkyv values
1 parent 3e9c1a5 commit c5c55a1

File tree

9 files changed

+119
-44
lines changed

9 files changed

+119
-44
lines changed

bathbot-model/src/osekai.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ use std::{
99
use eyre::{Result, WrapErr};
1010
use form_urlencoded::Serializer as FormSerializer;
1111
use rkyv::{
12-
bytecheck::CheckBytes, string::ArchivedString, with::Niche, Archive, Archived,
13-
Deserialize as RkyvDeserialize, Portable, Serialize,
12+
bytecheck::CheckBytes,
13+
niche::niching::{NaN, Null},
14+
string::ArchivedString,
15+
with::NicheInto,
16+
Archive, Archived, Deserialize as RkyvDeserialize, Portable, Serialize,
1417
};
1518
use rosu_v2::{
1619
model::GameMode,
@@ -27,6 +30,7 @@ use twilight_interactions::command::{CommandOption, CreateOption};
2730
use super::deser;
2831
use crate::{
2932
rkyv_util::{time::DateRkyv, DerefAsString},
33+
rosu_v2::mode::GameModeNiche,
3034
RankingKind,
3135
};
3236

@@ -202,18 +206,20 @@ pub struct OsekaiMedal {
202206
#[serde(with = "deser::u32_string")]
203207
pub ordering: u32,
204208
#[serde(rename = "Frequency", with = "deser::option_f32_string")]
209+
#[rkyv(with = NicheInto<NaN>)]
205210
pub rarity: Option<f32>,
206211
pub name: Box<str>,
207212
#[serde(rename = "Link")]
208213
icon_url_suffix: Box<str>,
209214
pub description: Box<str>,
210215
#[serde(rename = "Gamemode", deserialize_with = "maybe_osekai_mode")]
216+
#[rkyv(with = NicheInto<GameModeNiche>)]
211217
pub mode: Option<GameMode>,
212218
pub grouping: MedalGroup,
213-
#[rkyv(with = Niche)]
219+
#[rkyv(with = NicheInto<Null>)]
214220
solution: Option<Box<str>>,
215-
#[rkyv(with = Niche)]
216221
#[serde(deserialize_with = "medal_mods")]
222+
#[rkyv(with = NicheInto<Null>)]
217223
pub mods: Option<Box<str>>,
218224
#[serde(rename = "Supports_Lazer", deserialize_with = "stringified_bool_int")]
219225
pub supports_lazer: bool,
@@ -810,6 +816,7 @@ pub struct OsekaiRarityEntry {
810816
#[serde(rename = "possessionRate", with = "deser::f32_string")]
811817
pub possession_percent: f32,
812818
#[serde(rename = "gameMode", deserialize_with = "maybe_osekai_mode")]
819+
#[rkyv(with = NicheInto<GameModeNiche>)]
813820
pub mode: Option<GameMode>,
814821
}
815822

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,24 @@
11
use std::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8};
22

33
use rkyv::{
4-
niche::option_nonzero::{
5-
ArchivedOptionNonZeroU16, ArchivedOptionNonZeroU32, ArchivedOptionNonZeroU64,
6-
ArchivedOptionNonZeroU8,
7-
},
4+
niche::{niched_option::NichedOption, niching::Zero},
85
rancor::Fallible,
96
with::{ArchiveWith, DeserializeWith, SerializeWith},
10-
Place,
7+
Archived, Place,
118
};
129

1310
pub struct AsNonZero;
1411

1512
macro_rules! impl_as_non_zero {
16-
($ar:ty, $nz:ty, $ne:ty) => {
13+
($nz:ty, $ne:ty) => {
1714
impl ArchiveWith<Option<$ne>> for AsNonZero {
18-
type Archived = $ar;
15+
type Archived = NichedOption<Archived<$nz>, Zero>;
1916
type Resolver = ();
2017

2118
#[inline]
2219
fn resolve_with(field: &Option<$ne>, _: Self::Resolver, out: Place<Self::Archived>) {
2320
let opt = field.and_then(<$nz>::new);
24-
<$ar>::resolve_from_option(opt, out);
21+
NichedOption::resolve_from_option(opt.as_ref(), Some(()), out);
2522
}
2623
}
2724

@@ -35,10 +32,12 @@ macro_rules! impl_as_non_zero {
3532
}
3633
}
3734

38-
impl<D: Fallible + ?Sized> DeserializeWith<$ar, Option<$ne>, D> for AsNonZero {
35+
impl<D: Fallible + ?Sized>
36+
DeserializeWith<NichedOption<Archived<$nz>, Zero>, Option<$ne>, D> for AsNonZero
37+
{
3938
#[inline]
4039
fn deserialize_with(
41-
field: &$ar,
40+
field: &NichedOption<Archived<$nz>, Zero>,
4241
_: &mut D,
4342
) -> Result<Option<$ne>, <D as Fallible>::Error> {
4443
Ok(field.as_ref().copied().map(<$nz>::from).map(<$nz>::get))
@@ -47,7 +46,7 @@ macro_rules! impl_as_non_zero {
4746
};
4847
}
4948

50-
impl_as_non_zero!(ArchivedOptionNonZeroU8, NonZeroU8, u8);
51-
impl_as_non_zero!(ArchivedOptionNonZeroU16, NonZeroU16, u16);
52-
impl_as_non_zero!(ArchivedOptionNonZeroU32, NonZeroU32, u32);
53-
impl_as_non_zero!(ArchivedOptionNonZeroU64, NonZeroU64, u64);
49+
impl_as_non_zero!(NonZeroU8, u8);
50+
impl_as_non_zero!(NonZeroU16, u16);
51+
impl_as_non_zero!(NonZeroU32, u32);
52+
impl_as_non_zero!(NonZeroU64, u64);

bathbot-model/src/rkyv_util/time.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rkyv::{
22
bytecheck::CheckBytes,
33
munge::munge,
4+
niche::niching::Niching,
45
rancor::{Fallible, Source},
56
rend::u64_le,
67
traits::NoUndef,
@@ -11,7 +12,7 @@ use time::{error::ComponentRange, Date, OffsetDateTime};
1112

1213
pub struct DateTimeRkyv;
1314

14-
#[derive(Copy, Clone, CheckBytes, Portable)]
15+
#[derive(Copy, Clone, CheckBytes, Portable, PartialEq, Eq)]
1516
#[bytecheck(crate = rkyv::bytecheck)]
1617
#[repr(C)]
1718
pub struct ArchivedDateTime {
@@ -24,7 +25,7 @@ pub struct ArchivedDateTime {
2425
unsafe impl NoUndef for ArchivedDateTime {}
2526

2627
impl ArchivedDateTime {
27-
pub fn new(datetime: OffsetDateTime) -> Self {
28+
pub const fn new(datetime: OffsetDateTime) -> Self {
2829
let unix_timestamp_nanos = datetime.unix_timestamp_nanos();
2930

3031
Self {
@@ -73,6 +74,16 @@ impl<D: Fallible<Error: Source>> DeserializeWith<ArchivedDateTime, OffsetDateTim
7374
}
7475
}
7576

77+
impl Niching<ArchivedDateTime> for DateTimeRkyv {
78+
unsafe fn is_niched(niched: *const ArchivedDateTime) -> bool {
79+
unsafe { *niched == ArchivedDateTime::new(OffsetDateTime::UNIX_EPOCH) }
80+
}
81+
82+
fn resolve_niched(out: Place<ArchivedDateTime>) {
83+
Self::resolve_with(&OffsetDateTime::UNIX_EPOCH, (), out);
84+
}
85+
}
86+
7687
pub struct DateRkyv;
7788

7889
impl DateRkyv {

bathbot-model/src/rosu_v2/grade.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ use rkyv::{Archive, Deserialize, Serialize};
22
use rosu_v2::model::Grade;
33

44
#[derive(Archive, Serialize, Deserialize)]
5-
#[rkyv(remote = Grade, archived = ArchivedGrade, resolver = GradeResolver, derive(Copy, Clone))]
5+
#[rkyv(
6+
remote = Grade,
7+
archived = ArchivedGrade,
8+
resolver = GradeResolver,
9+
derive(Copy, Clone),
10+
)]
611
pub enum GradeRkyv {
712
F,
813
D,

bathbot-model/src/rosu_v2/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub mod grade;
2+
pub mod mode;
23
pub mod ranking;
34
pub mod user;

bathbot-model/src/rosu_v2/mode.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use rkyv::{niche::niching::Niching, Archive, Place};
2+
use rosu_mods::GameMode;
3+
4+
pub struct GameModeNiche;
5+
6+
impl GameModeNiche {
7+
const NICHED: u8 = u8::MAX;
8+
}
9+
10+
impl Niching<GameMode> for GameModeNiche {
11+
unsafe fn is_niched(niched: *const GameMode) -> bool {
12+
unsafe { *niched as u8 == Self::NICHED }
13+
}
14+
15+
fn resolve_niched(out: Place<GameMode>) {
16+
Self::NICHED.resolve((), unsafe { out.cast_unchecked() });
17+
}
18+
}

bathbot-model/src/rosu_v2/ranking.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use rkyv::{with::Map, Archive, Serialize};
1+
use rkyv::{
2+
niche::niching::NaN,
3+
with::{Map, MapNiche},
4+
Archive, Serialize,
5+
};
26
use rosu_v2::prelude::{CountryCode, Rankings, User, UserStatistics, Username};
37

48
use super::user::UserStatisticsRkyv;
@@ -23,6 +27,6 @@ pub struct RankingsUserRkyv {
2327
pub user_id: u32,
2428
#[rkyv(with = DerefAsString)]
2529
pub username: Username,
26-
#[rkyv(with = Map<UserStatisticsRkyv>)]
30+
#[rkyv(with = MapNiche<UserStatisticsRkyv, NaN>)]
2731
pub statistics: Option<UserStatistics>,
2832
}

bathbot-model/src/rosu_v2/user.rs

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ use ::rosu_v2::model::user::{
55
use bathbot_util::osu::UserStats;
66
use rkyv::{
77
munge::munge,
8+
niche::niching::{NaN, Niching},
89
rancor::{Fallible, Source},
910
rend::u32_le,
1011
ser::{Allocator, Writer},
11-
with::{ArchiveWith, InlineAsBox, Map, SerializeWith},
12+
with::{ArchiveWith, InlineAsBox, Map, MapNiche, SerializeWith},
1213
Archive, Deserialize, Place, Serialize,
1314
};
1415
use rosu_v2::prelude::{CountryCode, DailyChallengeUserStatistics, GameMode, Username};
@@ -72,13 +73,16 @@ impl From<MedalCompactRkyv> for MedalCompact {
7273
}
7374

7475
#[derive(Archive, Serialize)]
75-
#[rkyv(remote = DailyChallengeUserStatistics, archived = ArchivedDailyChallengeUserStatistics)]
76+
#[rkyv(
77+
remote = DailyChallengeUserStatistics,
78+
archived = ArchivedDailyChallengeUserStatistics,
79+
)]
7680
pub struct DailyChallengeUserStatisticsRkyv {
7781
pub daily_streak_best: u32,
7882
pub daily_streak_current: u32,
79-
#[rkyv(with = Map<DateTimeRkyv>)]
83+
#[rkyv(with = MapNiche<DateTimeRkyv, DateTimeRkyv>)]
8084
pub last_update: Option<OffsetDateTime>,
81-
#[rkyv(with = Map<DateTimeRkyv>)]
85+
#[rkyv(with = MapNiche<DateTimeRkyv, DateTimeRkyv>)]
8286
pub last_weekly_streak: Option<OffsetDateTime>,
8387
pub playcount: u32,
8488
pub top_10p_placements: u32,
@@ -113,6 +117,17 @@ pub struct TeamRkyv {
113117
pub short_name: String,
114118
}
115119

120+
impl Niching<ArchivedTeam> for TeamRkyv {
121+
unsafe fn is_niched(niched: *const ArchivedTeam) -> bool {
122+
unsafe { (*niched).id == 0 }
123+
}
124+
125+
fn resolve_niched(out: Place<ArchivedTeam>) {
126+
munge!(let ArchivedTeam { id, .. } = out);
127+
0_u32.resolve((), id);
128+
}
129+
}
130+
116131
#[derive(Clone, Archive, Serialize)]
117132
pub struct User {
118133
pub avatar_url: Box<str>,
@@ -122,7 +137,7 @@ pub struct User {
122137
pub join_date: OffsetDateTime,
123138
#[rkyv(with = UserKudosuRkyv)]
124139
pub kudosu: UserKudosu,
125-
#[rkyv(with = Map<DateTimeRkyv>)]
140+
#[rkyv(with = MapNiche<DateTimeRkyv, DateTimeRkyv>)]
126141
pub last_visit: Option<OffsetDateTime>,
127142
pub mode: GameMode,
128143
pub user_id: u32,
@@ -134,7 +149,7 @@ pub struct User {
134149
pub follower_count: u32,
135150
pub graveyard_mapset_count: u32,
136151
pub guest_mapset_count: u32,
137-
#[rkyv(with = Map<UserHighestRankRkyv>)]
152+
#[rkyv(with = MapNiche<UserHighestRankRkyv, DateTimeRkyv>)]
138153
pub highest_rank: Option<UserHighestRank>,
139154
pub loved_mapset_count: u32,
140155
pub mapping_follower_count: u32,
@@ -145,14 +160,14 @@ pub struct User {
145160
#[rkyv(with = Map<MonthlyCountRkyv>)]
146161
pub replays_watched_counts: Vec<MonthlyCount>,
147162
pub scores_first_count: u32,
148-
#[rkyv(with = Map<UserStatisticsRkyv>)]
163+
#[rkyv(with = MapNiche<UserStatisticsRkyv, NaN>)]
149164
pub statistics: Option<UserStatistics>,
150165
pub pending_mapset_count: u32,
151166
#[rkyv(with = Map<MedalCompactRkyv>)]
152167
pub medals: Vec<MedalCompact>,
153168
#[rkyv(with = DailyChallengeUserStatisticsRkyv)]
154169
pub daily_challenge: DailyChallengeUserStatistics,
155-
#[rkyv(with = Map<TeamRkyv>)]
170+
#[rkyv(with = MapNiche<TeamRkyv, TeamRkyv>)]
156171
pub team: Option<Team>,
157172
}
158173

@@ -194,7 +209,11 @@ impl ArchiveWith<UserExtended> for User {
194209
DerefAsString::resolve_with(&user.country_code, resolver.country_code, country_code);
195210
DateTimeRkyv::resolve_with(&user.join_date, resolver.join_date, join_date);
196211
UserKudosuRkyv::resolve_with(&user.kudosu, resolver.kudosu, kudosu);
197-
Map::<DateTimeRkyv>::resolve_with(&user.last_visit, resolver.last_visit, last_visit);
212+
MapNiche::<DateTimeRkyv, DateTimeRkyv>::resolve_with(
213+
&user.last_visit,
214+
resolver.last_visit,
215+
last_visit,
216+
);
198217
user.mode.resolve(resolver.mode, mode);
199218
user.user_id.resolve(resolver.user_id, user_id);
200219
DerefAsString::resolve_with(&user.username, resolver.username, username);
@@ -214,7 +233,7 @@ impl ArchiveWith<UserExtended> for User {
214233
resolver.guest_mapset_count,
215234
guest_mapset_count,
216235
);
217-
Map::<UserHighestRankRkyv>::resolve_with(
236+
MapNiche::<UserHighestRankRkyv, DateTimeRkyv>::resolve_with(
218237
&user.highest_rank,
219238
resolver.highest_rank,
220239
highest_rank,
@@ -259,14 +278,18 @@ impl ArchiveWith<UserExtended> for User {
259278
resolver.replays_watched_counts,
260279
replays_watched_counts,
261280
);
262-
Map::<UserStatisticsRkyv>::resolve_with(&user.statistics, resolver.statistics, statistics);
281+
MapNiche::<UserStatisticsRkyv, NaN>::resolve_with(
282+
&user.statistics,
283+
resolver.statistics,
284+
statistics,
285+
);
263286
MapUnwrapOrDefault::<MedalCompactRkyv>::resolve_with(&user.medals, resolver.medals, medals);
264287
DailyChallengeUserStatisticsRkyv::resolve_with(
265288
&user.daily_challenge_stats,
266289
resolver.daily_challenge,
267290
daily_challenge,
268291
);
269-
Map::<TeamRkyv>::resolve_with(&user.team, resolver.team, team);
292+
MapNiche::<TeamRkyv, TeamRkyv>::resolve_with(&user.team, resolver.team, team);
270293
}
271294
}
272295

@@ -279,12 +302,15 @@ impl<S: Fallible<Error: Source> + Writer + Allocator + ?Sized> SerializeWith<Use
279302
country_code: DerefAsString::serialize_with(&user.country_code, serializer)?,
280303
join_date: DateTimeRkyv::serialize_with(&user.join_date, serializer)?,
281304
kudosu: UserKudosuRkyv::serialize_with(&user.kudosu, serializer)?,
282-
last_visit: Map::<DateTimeRkyv>::serialize_with(&user.last_visit, serializer)?,
305+
last_visit: MapNiche::<DateTimeRkyv, DateTimeRkyv>::serialize_with(
306+
&user.last_visit,
307+
serializer,
308+
)?,
283309
mode: user.mode.serialize(serializer)?,
284310
user_id: user.user_id.serialize(serializer)?,
285311
username: DerefAsString::serialize_with(&user.username, serializer)?,
286312
badges: MapUnwrapOrDefault::<BadgeRkyv>::serialize_with(&user.badges, serializer)?,
287-
highest_rank: Map::<UserHighestRankRkyv>::serialize_with(
313+
highest_rank: MapNiche::<UserHighestRankRkyv, DateTimeRkyv>::serialize_with(
288314
&user.highest_rank,
289315
serializer,
290316
)?,
@@ -329,7 +355,10 @@ impl<S: Fallible<Error: Source> + Writer + Allocator + ?Sized> SerializeWith<Use
329355
&user.replays_watched_counts,
330356
serializer,
331357
)?,
332-
statistics: Map::<UserStatisticsRkyv>::serialize_with(&user.statistics, serializer)?,
358+
statistics: MapNiche::<UserStatisticsRkyv, NaN>::serialize_with(
359+
&user.statistics,
360+
serializer,
361+
)?,
333362
medals: MapUnwrapOrDefault::<MedalCompactRkyv>::serialize_with(
334363
&user.medals,
335364
serializer,
@@ -338,7 +367,7 @@ impl<S: Fallible<Error: Source> + Writer + Allocator + ?Sized> SerializeWith<Use
338367
&user.daily_challenge_stats,
339368
serializer,
340369
)?,
341-
team: Map::<TeamRkyv>::serialize_with(&user.team, serializer)?,
370+
team: MapNiche::<TeamRkyv, TeamRkyv>::serialize_with(&user.team, serializer)?,
342371
})
343372
}
344373
}
@@ -381,7 +410,7 @@ impl From<UserExtended> for User {
381410
#[rkyv(remote = UserHighestRank, archived = ArchivedUserHighestRank, derive(Clone))]
382411
pub struct UserHighestRankRkyv {
383412
pub rank: u32,
384-
#[rkyv(with = DateTimeRkyv)]
413+
#[rkyv(with = DateTimeRkyv, niche = DateTimeRkyv)]
385414
pub updated_at: OffsetDateTime,
386415
}
387416

@@ -430,6 +459,7 @@ pub struct UserStatisticsRkyv {
430459
pub grade_counts: GradeCounts,
431460
#[rkyv(with = UserLevelRkyv)]
432461
pub level: UserLevel,
462+
#[rkyv(niche = NaN)]
433463
pub accuracy: f32,
434464
pub country_rank: u32,
435465
pub global_rank: u32,

0 commit comments

Comments
 (0)