From e643830306444202ccda7538bad0a5854b01b7ca Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 24 Nov 2023 17:04:13 +0000 Subject: [PATCH] Write custom serializer for bools in indexeddb --- .../src/crypto_store/mod.rs | 25 ++++++----- crates/matrix-sdk-indexeddb/src/lib.rs | 2 + .../src/serialize_bool_for_indexeddb.rs | 41 +++++++++++++++++++ 3 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 crates/matrix-sdk-indexeddb/src/serialize_bool_for_indexeddb.rs diff --git a/crates/matrix-sdk-indexeddb/src/crypto_store/mod.rs b/crates/matrix-sdk-indexeddb/src/crypto_store/mod.rs index 8a742017e56..d290c5847a7 100644 --- a/crates/matrix-sdk-indexeddb/src/crypto_store/mod.rs +++ b/crates/matrix-sdk-indexeddb/src/crypto_store/mod.rs @@ -374,7 +374,7 @@ impl IndexeddbCryptoStore { // serialize and encrypt the data about the request request: self.serialize_value_as_bytes(gossip_request)?, - unsent: if gossip_request.sent_out { None } else { Some(1) }, + unsent: !gossip_request.sent_out, }; Ok(obj.try_into()?) @@ -1209,19 +1209,18 @@ struct GossipRequestIndexedDbObject { /// Whether the request has yet to be sent out. /// - /// Really, this represents a boolean value, but booleans don't work as keys - /// in indexeddb (see [ECMA spec]). In any case, we don't need to be - /// able to retrieve entries where `unsent` is false, so we may as well - /// omit them from the index (see also [Stack Overflow]). + /// Since we only need to be able to find requests where this is `true`, we + /// skip serialization in cases where it is `false`. That has the effect + /// of omitting it from the indexeddb index. /// - /// To avoid too much `serde` magic, we use an `Option`, and omit the value - /// altogether if it is `None`, which means it will be excluded from the - /// "unsent" index. If it is `Some`, the actual value is unimportant. - /// - /// [ECMA spec]: https://w3c.github.io/IndexedDB/#key - /// [Stack overflow]: https://stackoverflow.com/a/24501949/637864 - #[serde(skip_serializing_if = "Option::is_none")] - unsent: Option, + /// We also use a custom serializer because bools can't be used as keys in + /// indexeddb. + #[serde( + default, + skip_serializing_if = "std::ops::Not::not", + with = "crate::serialize_bool_for_indexeddb" + )] + unsent: bool, } impl TryInto for GossipRequestIndexedDbObject { diff --git a/crates/matrix-sdk-indexeddb/src/lib.rs b/crates/matrix-sdk-indexeddb/src/lib.rs index e9a2245761f..9a86ac07a3e 100644 --- a/crates/matrix-sdk-indexeddb/src/lib.rs +++ b/crates/matrix-sdk-indexeddb/src/lib.rs @@ -6,6 +6,8 @@ use thiserror::Error; #[cfg(feature = "e2e-encryption")] mod crypto_store; mod safe_encode; +#[cfg(feature = "e2e-encryption")] +mod serialize_bool_for_indexeddb; mod state_store; #[cfg(feature = "e2e-encryption")] diff --git a/crates/matrix-sdk-indexeddb/src/serialize_bool_for_indexeddb.rs b/crates/matrix-sdk-indexeddb/src/serialize_bool_for_indexeddb.rs new file mode 100644 index 00000000000..be092b1f2a5 --- /dev/null +++ b/crates/matrix-sdk-indexeddb/src/serialize_bool_for_indexeddb.rs @@ -0,0 +1,41 @@ +// Copyright 2023 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Booleans don't work as keys in indexeddb (see [ECMA spec]), so instead we +//! serialize them as `0` or `1`. +//! +//! This module implements a custom serializer which can be used on `bool` +//! struct fields with: +//! +//! ```ignore +//! #[serde(with = "serialize_bool_for_indexeddb")] +//! ``` +//! +//! [ECMA spec]: https://w3c.github.io/IndexedDB/#key +use serde::{Deserializer, Serializer}; + +pub fn serialize(v: &bool, s: S) -> Result +where + S: Serializer, +{ + s.serialize_u8(if *v { 1 } else { 0 }) +} + +pub fn deserialize<'de, D>(d: D) -> Result +where + D: Deserializer<'de>, +{ + let v: u8 = serde::de::Deserialize::deserialize(d)?; + Ok(v != 0) +}