Skip to main content

matrix_sdk_indexeddb/media_store/serializer/
foreign.rs

1// Copyright 2025 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License
14
15pub mod ignore_media_retention_policy {
16    //! This module contains a foreign implementation of [`serde::Serialize`]
17    //! and [`serde::Deserialize`] for [`IgnoreMediaRetentionPolicy`]. These
18    //! implementations can be injected with the proper macros, i.e.,
19    //! `#[serde(with = "path::to::this::module")]`.
20    //!
21    //! This is necessary, as [`IgnoreMediaRetentionPolicy`] does not implement
22    //! these traits directly.
23
24    use matrix_sdk_base::media::store::IgnoreMediaRetentionPolicy;
25    use serde::{Deserializer, Serializer};
26
27    /// Serializes an [`IgnoreMediaRetentionPolicy`] as a `u8`, where
28    /// [`IgnoreMediaRetentionPolicy::No`] is `0`
29    /// and [`IgnoreMediaRetentionPolicy::Yes`] is `1`.
30    ///
31    /// Note that this is not serialized as a `bool` because boolean values are
32    /// not supported as IndexedDB keys.
33    pub fn serialize<S>(ignore_policy: &IgnoreMediaRetentionPolicy, s: S) -> Result<S::Ok, S::Error>
34    where
35        S: Serializer,
36    {
37        s.serialize_u8(match ignore_policy {
38            IgnoreMediaRetentionPolicy::Yes => 1,
39            IgnoreMediaRetentionPolicy::No => 0,
40        })
41    }
42
43    /// Deserializes a `u8` into an [`IgnoreMediaRetentionPolicy`] where `0` is
44    /// [`IgnoreMediaRetentionPolicy::No`] and anything else is
45    /// [`IgnoreMediaRetentionPolicy::Yes`].
46    pub fn deserialize<'de, D>(d: D) -> Result<IgnoreMediaRetentionPolicy, D::Error>
47    where
48        D: Deserializer<'de>,
49    {
50        Ok(match serde::de::Deserialize::deserialize(d)? {
51            0u8 => IgnoreMediaRetentionPolicy::No,
52            _ => IgnoreMediaRetentionPolicy::Yes,
53        })
54    }
55}
56
57pub mod unix_time {
58    //! This module contains an alternative implementation of
59    //! [`serde::Serialize`] and [`serde::Deserialize`] for [`UnixTime`].
60    //! These implementations can be injected with the proper macros, i.e.,
61    //! `#[serde(with = "path::to::this::module")]`.
62    //!
63    //! This is necessary, as the derived implementation of [`UnixTime`] does
64    //! not produce values which can be used in IndexedDB keys.
65
66    use std::time::Duration;
67
68    use serde::{Deserializer, Serializer};
69
70    use crate::media_store::types::UnixTime;
71
72    /// Serializes a [`UnixTime`] as an `i64` which represents an amount of
73    /// seconds relative to the [`UNIX_EPOCH`](ruma::time::UNIX_EPOCH).
74    /// [`UnixTime::BeforeEpoch`] is represented as a negative value
75    /// and [`UnixTime::AfterEpoch`] is represented as a positive value.
76    pub fn serialize<S>(unix_time: &UnixTime, s: S) -> Result<S::Ok, S::Error>
77    where
78        S: Serializer,
79    {
80        s.serialize_i64(match unix_time {
81            UnixTime::BeforeEpoch(duration) => {
82                -i64::try_from(duration.as_secs()).map_err(serde::ser::Error::custom)?
83            }
84            UnixTime::AfterEpoch(duration) => {
85                i64::try_from(duration.as_secs()).map_err(serde::ser::Error::custom)?
86            }
87        })
88    }
89
90    /// Deserializes an `i64` into a [`UnixTime`]. Negative values represent
91    /// the number of seconds before the [`UNIX_EPOCH`][1] and are deserialized
92    /// into [`UnixTime::BeforeEpoch`]. Positive values represent
93    /// the number of seconds after the [`UNIX_EPOCH`][1] and are deserialized
94    /// into [`UnixTime::AfterEpoch`].
95    ///
96    /// [1]: ruma::time::UNIX_EPOCH
97    pub fn deserialize<'de, D>(d: D) -> Result<UnixTime, D::Error>
98    where
99        D: Deserializer<'de>,
100    {
101        let seconds: i64 = serde::de::Deserialize::deserialize(d)?;
102        Ok(match seconds {
103            seconds @ ..0 => UnixTime::BeforeEpoch(Duration::from_secs(seconds.unsigned_abs())),
104            seconds @ 0.. => UnixTime::AfterEpoch(Duration::from_secs(seconds.unsigned_abs())),
105        })
106    }
107}