Skip to content

Commit

Permalink
Write custom serializer for bools in indexeddb
Browse files Browse the repository at this point in the history
  • Loading branch information
richvdh committed Nov 25, 2023
1 parent fbbdc51 commit e643830
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 13 deletions.
25 changes: 12 additions & 13 deletions crates/matrix-sdk-indexeddb/src/crypto_store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()?)
Expand Down Expand Up @@ -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<u8>,
/// 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<JsValue> for GossipRequestIndexedDbObject {
Expand Down
2 changes: 2 additions & 0 deletions crates/matrix-sdk-indexeddb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
41 changes: 41 additions & 0 deletions crates/matrix-sdk-indexeddb/src/serialize_bool_for_indexeddb.rs
Original file line number Diff line number Diff line change
@@ -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<S>(v: &bool, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_u8(if *v { 1 } else { 0 })
}

pub fn deserialize<'de, D>(d: D) -> Result<bool, D::Error>
where
D: Deserializer<'de>,
{
let v: u8 = serde::de::Deserialize::deserialize(d)?;
Ok(v != 0)
}

0 comments on commit e643830

Please sign in to comment.