add Option support to database deserializer

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2025-02-01 22:28:09 +00:00
parent 2fa9621f3a
commit ea49b60273
2 changed files with 176 additions and 6 deletions

View file

@ -22,7 +22,7 @@ pub(crate) fn from_slice<'a, T>(buf: &'a [u8]) -> Result<T>
where
T: Deserialize<'a>,
{
let mut deserializer = Deserializer { buf, pos: 0, seq: false };
let mut deserializer = Deserializer { buf, pos: 0, rec: 0, seq: false };
T::deserialize(&mut deserializer).debug_inspect(|_| {
deserializer
@ -35,6 +35,7 @@ where
pub(crate) struct Deserializer<'de> {
buf: &'de [u8],
pos: usize,
rec: usize,
seq: bool,
}
@ -107,7 +108,7 @@ impl<'de> Deserializer<'de> {
/// consumed None is returned instead.
#[inline]
fn record_peek_byte(&self) -> Option<u8> {
let started = self.pos != 0;
let started = self.pos != 0 || self.rec > 0;
let buf = &self.buf[self.pos..];
debug_assert!(
!started || buf[0] == Self::SEP,
@ -121,13 +122,14 @@ impl<'de> Deserializer<'de> {
/// the start of the next record. (Case for some sequences)
#[inline]
fn record_start(&mut self) {
let started = self.pos != 0;
let started = self.pos != 0 || self.rec > 0;
debug_assert!(
!started || self.buf[self.pos] == Self::SEP,
"Missing expected record separator at current position"
);
self.inc_pos(started.into());
self.inc_rec(1);
}
/// Consume all remaining bytes, which may include record separators,
@ -157,6 +159,9 @@ impl<'de> Deserializer<'de> {
debug_assert!(self.pos <= self.buf.len(), "pos out of range");
}
#[inline]
fn inc_rec(&mut self, n: usize) { self.rec = self.rec.saturating_add(n); }
/// Unconsumed input bytes.
#[inline]
fn remaining(&self) -> Result<usize> {
@ -270,8 +275,16 @@ impl<'a, 'de: 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
}
#[cfg_attr(unabridged, tracing::instrument(level = "trace", skip_all))]
fn deserialize_option<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value> {
unhandled!("deserialize Option not implemented")
fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
if self
.buf
.get(self.pos)
.is_none_or(|b| *b == Deserializer::SEP)
{
visitor.visit_none()
} else {
visitor.visit_some(self)
}
}
#[cfg_attr(unabridged, tracing::instrument(level = "trace", skip_all))]

View file

@ -3,7 +3,7 @@
use std::fmt::Debug;
use arrayvec::ArrayVec;
use conduwuit::ruma::{serde::Raw, RoomId, UserId};
use conduwuit::ruma::{serde::Raw, EventId, RoomId, UserId};
use serde::Serialize;
use crate::{
@ -389,3 +389,160 @@ fn de_complex() {
assert_eq!(arr, key, "deserialization of serialization does not match");
}
#[test]
fn serde_tuple_option_value_some() {
let room_id: &RoomId = "!room:example.com".try_into().unwrap();
let user_id: &UserId = "@user:example.com".try_into().unwrap();
let mut aa = Vec::<u8>::new();
aa.extend_from_slice(room_id.as_bytes());
aa.push(0xFF);
aa.extend_from_slice(user_id.as_bytes());
let bb: (&RoomId, Option<&UserId>) = (room_id, Some(user_id));
let bbs = serialize_to_vec(&bb).expect("failed to serialize tuple");
assert_eq!(aa, bbs);
let cc: (&RoomId, Option<&UserId>) =
de::from_slice(&bbs).expect("failed to deserialize tuple");
assert_eq!(bb.1, cc.1);
assert_eq!(cc.0, bb.0);
}
#[test]
fn serde_tuple_option_value_none() {
let room_id: &RoomId = "!room:example.com".try_into().unwrap();
let mut aa = Vec::<u8>::new();
aa.extend_from_slice(room_id.as_bytes());
aa.push(0xFF);
let bb: (&RoomId, Option<&UserId>) = (room_id, None);
let bbs = serialize_to_vec(&bb).expect("failed to serialize tuple");
assert_eq!(aa, bbs);
let cc: (&RoomId, Option<&UserId>) =
de::from_slice(&bbs).expect("failed to deserialize tuple");
assert_eq!(None, cc.1);
assert_eq!(cc.0, bb.0);
}
#[test]
fn serde_tuple_option_none_value() {
let user_id: &UserId = "@user:example.com".try_into().unwrap();
let mut aa = Vec::<u8>::new();
aa.push(0xFF);
aa.extend_from_slice(user_id.as_bytes());
let bb: (Option<&RoomId>, &UserId) = (None, user_id);
let bbs = serialize_to_vec(&bb).expect("failed to serialize tuple");
assert_eq!(aa, bbs);
let cc: (Option<&RoomId>, &UserId) =
de::from_slice(&bbs).expect("failed to deserialize tuple");
assert_eq!(None, cc.0);
assert_eq!(cc.1, bb.1);
}
#[test]
fn serde_tuple_option_some_value() {
let room_id: &RoomId = "!room:example.com".try_into().unwrap();
let user_id: &UserId = "@user:example.com".try_into().unwrap();
let mut aa = Vec::<u8>::new();
aa.extend_from_slice(room_id.as_bytes());
aa.push(0xFF);
aa.extend_from_slice(user_id.as_bytes());
let bb: (Option<&RoomId>, &UserId) = (Some(room_id), user_id);
let bbs = serialize_to_vec(&bb).expect("failed to serialize tuple");
assert_eq!(aa, bbs);
let cc: (Option<&RoomId>, &UserId) =
de::from_slice(&bbs).expect("failed to deserialize tuple");
assert_eq!(bb.0, cc.0);
assert_eq!(cc.1, bb.1);
}
#[test]
fn serde_tuple_option_some_some() {
let room_id: &RoomId = "!room:example.com".try_into().unwrap();
let user_id: &UserId = "@user:example.com".try_into().unwrap();
let mut aa = Vec::<u8>::new();
aa.extend_from_slice(room_id.as_bytes());
aa.push(0xFF);
aa.extend_from_slice(user_id.as_bytes());
let bb: (Option<&RoomId>, Option<&UserId>) = (Some(room_id), Some(user_id));
let bbs = serialize_to_vec(&bb).expect("failed to serialize tuple");
assert_eq!(aa, bbs);
let cc: (Option<&RoomId>, Option<&UserId>) =
de::from_slice(&bbs).expect("failed to deserialize tuple");
assert_eq!(cc.0, bb.0);
assert_eq!(bb.1, cc.1);
}
#[test]
fn serde_tuple_option_none_none() {
let aa = vec![0xFF];
let bb: (Option<&RoomId>, Option<&UserId>) = (None, None);
let bbs = serialize_to_vec(&bb).expect("failed to serialize tuple");
assert_eq!(aa, bbs);
let cc: (Option<&RoomId>, Option<&UserId>) =
de::from_slice(&bbs).expect("failed to deserialize tuple");
assert_eq!(cc.0, bb.0);
assert_eq!(None, cc.1);
}
#[test]
fn serde_tuple_option_some_none_some() {
let room_id: &RoomId = "!room:example.com".try_into().unwrap();
let user_id: &UserId = "@user:example.com".try_into().unwrap();
let mut aa = Vec::<u8>::new();
aa.extend_from_slice(room_id.as_bytes());
aa.push(0xFF);
aa.push(0xFF);
aa.extend_from_slice(user_id.as_bytes());
let bb: (Option<&RoomId>, Option<&EventId>, Option<&UserId>) =
(Some(room_id), None, Some(user_id));
let bbs = serialize_to_vec(&bb).expect("failed to serialize tuple");
assert_eq!(aa, bbs);
let cc: (Option<&RoomId>, Option<&EventId>, Option<&UserId>) =
de::from_slice(&bbs).expect("failed to deserialize tuple");
assert_eq!(bb.0, cc.0);
assert_eq!(None, cc.1);
assert_eq!(bb.1, cc.1);
assert_eq!(bb.2, cc.2);
}
#[test]
fn serde_tuple_option_none_none_none() {
let aa = vec![0xFF, 0xFF];
let bb: (Option<&RoomId>, Option<&EventId>, Option<&UserId>) = (None, None, None);
let bbs = serialize_to_vec(&bb).expect("failed to serialize tuple");
assert_eq!(aa, bbs);
let cc: (Option<&RoomId>, Option<&EventId>, Option<&UserId>) =
de::from_slice(&bbs).expect("failed to deserialize tuple");
assert_eq!(None, cc.0);
assert_eq!(bb, cc);
}