|
| 1 | +//! Collection of helper functions for serializing to and deserializing from BSON using Serde |
| 2 | +
|
| 3 | +use std::{convert::TryFrom, result::Result}; |
| 4 | + |
| 5 | +use serde::{ser, Serialize, Serializer}; |
| 6 | + |
| 7 | +use crate::oid::ObjectId; |
| 8 | + |
| 9 | +pub use bson_datetime_as_iso_string::{ |
| 10 | + deserialize as deserialize_bson_datetime_from_iso_string, |
| 11 | + serialize as serialize_bson_datetime_as_iso_string, |
| 12 | +}; |
| 13 | +pub use chrono_datetime_as_bson_datetime::{ |
| 14 | + deserialize as deserialize_chrono_datetime_from_bson_datetime, |
| 15 | + serialize as serialize_chrono_datetime_as_bson_datetime, |
| 16 | +}; |
| 17 | +pub use iso_string_as_bson_datetime::{ |
| 18 | + deserialize as deserialize_iso_string_from_bson_datetime, |
| 19 | + serialize as serialize_iso_string_as_bson_datetime, |
| 20 | +}; |
| 21 | +pub use timestamp_as_u32::{ |
| 22 | + deserialize as deserialize_timestamp_from_u32, |
| 23 | + serialize as serialize_timestamp_as_u32, |
| 24 | +}; |
| 25 | +pub use u32_as_timestamp::{ |
| 26 | + deserialize as deserialize_u32_from_timestamp, |
| 27 | + serialize as serialize_u32_as_timestamp, |
| 28 | +}; |
| 29 | +pub use uuid_as_binary::{ |
| 30 | + deserialize as deserialize_uuid_from_binary, |
| 31 | + serialize as serialize_uuid_as_binary, |
| 32 | +}; |
| 33 | + |
| 34 | +/// Attempts to serialize a u32 as an i32. Errors if an exact conversion is not possible. |
| 35 | +pub fn serialize_u32_as_i32<S: Serializer>(val: &u32, serializer: S) -> Result<S::Ok, S::Error> { |
| 36 | + match i32::try_from(*val) { |
| 37 | + Ok(val) => serializer.serialize_i32(val), |
| 38 | + Err(_) => Err(ser::Error::custom(format!("cannot convert {} to i32", val))), |
| 39 | + } |
| 40 | +} |
| 41 | + |
| 42 | +/// Serializes a u32 as an i64. |
| 43 | +pub fn serialize_u32_as_i64<S: Serializer>(val: &u32, serializer: S) -> Result<S::Ok, S::Error> { |
| 44 | + serializer.serialize_i64(*val as i64) |
| 45 | +} |
| 46 | + |
| 47 | +/// Attempts to serialize a u64 as an i32. Errors if an exact conversion is not possible. |
| 48 | +pub fn serialize_u64_as_i32<S: Serializer>(val: &u64, serializer: S) -> Result<S::Ok, S::Error> { |
| 49 | + match i32::try_from(*val) { |
| 50 | + Ok(val) => serializer.serialize_i32(val), |
| 51 | + Err(_) => Err(ser::Error::custom(format!("cannot convert {} to i32", val))), |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +/// Attempts to serialize a u64 as an i64. Errors if an exact conversion is not possible. |
| 56 | +pub fn serialize_u64_as_i64<S: Serializer>(val: &u64, serializer: S) -> Result<S::Ok, S::Error> { |
| 57 | + match i64::try_from(*val) { |
| 58 | + Ok(val) => serializer.serialize_i64(val), |
| 59 | + Err(_) => Err(ser::Error::custom(format!("cannot convert {} to i64", val))), |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +/// Contains functions to serialize a chrono::DateTime as a bson::DateTime and deserialize a |
| 64 | +/// chrono::DateTime from a bson::DateTime. |
| 65 | +/// |
| 66 | +/// ```rust |
| 67 | +/// # use serde::{Serialize, Deserialize}; |
| 68 | +/// # use bson::serde_helpers::chrono_datetime_as_bson_datetime; |
| 69 | +/// #[derive(Serialize, Deserialize)] |
| 70 | +/// struct Event { |
| 71 | +/// #[serde(with = "chrono_datetime_as_bson_datetime")] |
| 72 | +/// pub date: chrono::DateTime<chrono::Utc>, |
| 73 | +/// } |
| 74 | +/// ``` |
| 75 | +pub mod chrono_datetime_as_bson_datetime { |
| 76 | + use crate::DateTime; |
| 77 | + use chrono::Utc; |
| 78 | + use serde::{Deserialize, Deserializer, Serialize, Serializer}; |
| 79 | + use std::result::Result; |
| 80 | + |
| 81 | + /// Deserializes a chrono::DateTime from a bson::DateTime. |
| 82 | + pub fn deserialize<'de, D>(deserializer: D) -> Result<chrono::DateTime<Utc>, D::Error> |
| 83 | + where |
| 84 | + D: Deserializer<'de>, |
| 85 | + { |
| 86 | + let datetime = DateTime::deserialize(deserializer)?; |
| 87 | + Ok(datetime.into()) |
| 88 | + } |
| 89 | + |
| 90 | + /// Serializes a chrono::DateTime as a bson::DateTime. |
| 91 | + pub fn serialize<S: Serializer>( |
| 92 | + val: &chrono::DateTime<Utc>, |
| 93 | + serializer: S, |
| 94 | + ) -> Result<S::Ok, S::Error> { |
| 95 | + let datetime = DateTime::from(val.to_owned()); |
| 96 | + datetime.serialize(serializer) |
| 97 | + } |
| 98 | +} |
| 99 | + |
| 100 | +/// Contains functions to serialize an ISO string as a bson::DateTime and deserialize an ISO string |
| 101 | +/// from a bson::DateTime. |
| 102 | +/// |
| 103 | +/// ```rust |
| 104 | +/// # use serde::{Serialize, Deserialize}; |
| 105 | +/// # use bson::serde_helpers::iso_string_as_bson_datetime; |
| 106 | +/// #[derive(Serialize, Deserialize)] |
| 107 | +/// struct Event { |
| 108 | +/// #[serde(with = "iso_string_as_bson_datetime")] |
| 109 | +/// pub date: String, |
| 110 | +/// } |
| 111 | +/// ``` |
| 112 | +pub mod iso_string_as_bson_datetime { |
| 113 | + use crate::{Bson, DateTime}; |
| 114 | + use serde::{ser, Deserialize, Deserializer, Serialize, Serializer}; |
| 115 | + use std::{result::Result, str::FromStr}; |
| 116 | + |
| 117 | + /// Deserializes an ISO string from a DateTime. |
| 118 | + pub fn deserialize<'de, D>(deserializer: D) -> Result<String, D::Error> |
| 119 | + where |
| 120 | + D: Deserializer<'de>, |
| 121 | + { |
| 122 | + let date = DateTime::deserialize(deserializer)?; |
| 123 | + Ok(date.to_string()) |
| 124 | + } |
| 125 | + |
| 126 | + /// Serializes an ISO string as a DateTime. |
| 127 | + pub fn serialize<S: Serializer>(val: &str, serializer: S) -> Result<S::Ok, S::Error> { |
| 128 | + let date = chrono::DateTime::from_str(val).map_err(|_| { |
| 129 | + ser::Error::custom(format!("cannot convert {} to chrono::DateTime", val)) |
| 130 | + })?; |
| 131 | + Bson::DateTime(date).serialize(serializer) |
| 132 | + } |
| 133 | +} |
| 134 | + |
| 135 | +/// Contains functions to serialize a bson::DateTime as an ISO string and deserialize a |
| 136 | +/// bson::DateTime from an ISO string. |
| 137 | +/// |
| 138 | +/// ```rust |
| 139 | +/// # use serde::{Serialize, Deserialize}; |
| 140 | +/// # use bson::serde_helpers::bson_datetime_as_iso_string; |
| 141 | +/// #[derive(Serialize, Deserialize)] |
| 142 | +/// struct Event { |
| 143 | +/// #[serde(with = "bson_datetime_as_iso_string")] |
| 144 | +/// pub date: bson::DateTime, |
| 145 | +/// } |
| 146 | +/// ``` |
| 147 | +pub mod bson_datetime_as_iso_string { |
| 148 | + use crate::DateTime; |
| 149 | + use serde::{de, Deserialize, Deserializer, Serializer}; |
| 150 | + use std::{result::Result, str::FromStr}; |
| 151 | + |
| 152 | + /// Deserializes a bson::DateTime from an ISO string. |
| 153 | + pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime, D::Error> |
| 154 | + where |
| 155 | + D: Deserializer<'de>, |
| 156 | + { |
| 157 | + let iso = String::deserialize(deserializer)?; |
| 158 | + let date = chrono::DateTime::from_str(&iso).map_err(|_| { |
| 159 | + de::Error::custom(format!("cannot convert {} to chrono::DateTime", iso)) |
| 160 | + })?; |
| 161 | + Ok(DateTime::from(date)) |
| 162 | + } |
| 163 | + |
| 164 | + /// Serializes a bson::DateTime as an ISO string. |
| 165 | + pub fn serialize<S: Serializer>(val: &DateTime, serializer: S) -> Result<S::Ok, S::Error> { |
| 166 | + serializer.serialize_str(&val.to_string()) |
| 167 | + } |
| 168 | +} |
| 169 | + |
| 170 | +/// Serializes a hex string as an ObjectId. |
| 171 | +pub fn serialize_hex_string_as_object_id<S: Serializer>( |
| 172 | + val: &str, |
| 173 | + serializer: S, |
| 174 | +) -> Result<S::Ok, S::Error> { |
| 175 | + match ObjectId::with_string(val) { |
| 176 | + Ok(oid) => oid.serialize(serializer), |
| 177 | + Err(_) => Err(ser::Error::custom(format!( |
| 178 | + "cannot convert {} to ObjectId", |
| 179 | + val |
| 180 | + ))), |
| 181 | + } |
| 182 | +} |
| 183 | + |
| 184 | +/// Contains functions to serialize a Uuid as a bson::Binary and deserialize a Uuid from a |
| 185 | +/// bson::Binary. |
| 186 | +/// |
| 187 | +/// ```rust |
| 188 | +/// # use serde::{Serialize, Deserialize}; |
| 189 | +/// # use uuid::Uuid; |
| 190 | +/// # use bson::serde_helpers::uuid_as_binary; |
| 191 | +/// #[derive(Serialize, Deserialize)] |
| 192 | +/// struct Item { |
| 193 | +/// #[serde(with = "uuid_as_binary")] |
| 194 | +/// pub id: Uuid, |
| 195 | +/// } |
| 196 | +/// ``` |
| 197 | +pub mod uuid_as_binary { |
| 198 | + use crate::{spec::BinarySubtype, Binary}; |
| 199 | + use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; |
| 200 | + use std::result::Result; |
| 201 | + use uuid::Uuid; |
| 202 | + |
| 203 | + /// Serializes a Uuid as a Binary. |
| 204 | + pub fn serialize<S: Serializer>(val: &Uuid, serializer: S) -> Result<S::Ok, S::Error> { |
| 205 | + let binary = Binary { |
| 206 | + subtype: BinarySubtype::Uuid, |
| 207 | + bytes: val.as_bytes().to_vec(), |
| 208 | + }; |
| 209 | + binary.serialize(serializer) |
| 210 | + } |
| 211 | + |
| 212 | + /// Deserializes a Uuid from a Binary. |
| 213 | + pub fn deserialize<'de, D>(deserializer: D) -> Result<Uuid, D::Error> |
| 214 | + where |
| 215 | + D: Deserializer<'de>, |
| 216 | + { |
| 217 | + let binary = Binary::deserialize(deserializer)?; |
| 218 | + if binary.subtype == BinarySubtype::Uuid { |
| 219 | + if binary.bytes.len() == 16 { |
| 220 | + let mut bytes = [0u8; 16]; |
| 221 | + bytes.copy_from_slice(&binary.bytes); |
| 222 | + Ok(Uuid::from_bytes(bytes)) |
| 223 | + } else { |
| 224 | + Err(de::Error::custom( |
| 225 | + "cannot convert Binary to Uuid: incorrect bytes length", |
| 226 | + )) |
| 227 | + } |
| 228 | + } else { |
| 229 | + Err(de::Error::custom( |
| 230 | + "cannot convert Binary to Uuid: incorrect binary subtype", |
| 231 | + )) |
| 232 | + } |
| 233 | + } |
| 234 | +} |
| 235 | + |
| 236 | +/// Contains functions to serialize a u32 as a bson::Timestamp and deserialize a u32 from a |
| 237 | +/// bson::Timestamp. The u32 should represent seconds since the Unix epoch. |
| 238 | +/// |
| 239 | +/// ```rust |
| 240 | +/// # use serde::{Serialize, Deserialize}; |
| 241 | +/// # use bson::serde_helpers::u32_as_timestamp; |
| 242 | +/// #[derive(Serialize, Deserialize)] |
| 243 | +/// struct Event { |
| 244 | +/// #[serde(with = "u32_as_timestamp")] |
| 245 | +/// pub time: u32, |
| 246 | +/// } |
| 247 | +/// ``` |
| 248 | +pub mod u32_as_timestamp { |
| 249 | + use crate::{Bson, Timestamp}; |
| 250 | + use serde::{Deserialize, Deserializer, Serialize, Serializer}; |
| 251 | + use std::result::Result; |
| 252 | + |
| 253 | + /// Serializes a u32 as a bson::Timestamp. |
| 254 | + pub fn serialize<S: Serializer>(val: &u32, serializer: S) -> Result<S::Ok, S::Error> { |
| 255 | + let timestamp = Bson::Timestamp(Timestamp { |
| 256 | + time: *val, |
| 257 | + increment: 0, |
| 258 | + }); |
| 259 | + timestamp.serialize(serializer) |
| 260 | + } |
| 261 | + |
| 262 | + /// Deserializes a u32 from a bson::Timestamp. |
| 263 | + pub fn deserialize<'de, D>(deserializer: D) -> Result<u32, D::Error> |
| 264 | + where |
| 265 | + D: Deserializer<'de>, |
| 266 | + { |
| 267 | + let timestamp = Timestamp::deserialize(deserializer)?; |
| 268 | + Ok(timestamp.time) |
| 269 | + } |
| 270 | +} |
| 271 | + |
| 272 | +/// Contains functions to serialize a bson::Timestamp as a u32 and deserialize a bson::Timestamp |
| 273 | +/// from a u32. The u32 should represent seconds since the Unix epoch. Serialization will return an |
| 274 | +/// error if the Timestamp has a non-zero increment. |
| 275 | +/// |
| 276 | +/// ```rust |
| 277 | +/// # use serde::{Serialize, Deserialize}; |
| 278 | +/// # use bson::{serde_helpers::timestamp_as_u32, Timestamp}; |
| 279 | +/// #[derive(Serialize, Deserialize)] |
| 280 | +/// struct Item { |
| 281 | +/// #[serde(with = "timestamp_as_u32")] |
| 282 | +/// pub timestamp: Timestamp, |
| 283 | +/// } |
| 284 | +/// ``` |
| 285 | +pub mod timestamp_as_u32 { |
| 286 | + use crate::Timestamp; |
| 287 | + use serde::{ser, Deserialize, Deserializer, Serializer}; |
| 288 | + use std::result::Result; |
| 289 | + |
| 290 | + /// Serializes a bson::Timestamp as a u32. Returns an error if the conversion is lossy (i.e. the |
| 291 | + /// Timestamp has a non-zero increment). |
| 292 | + pub fn serialize<S: Serializer>(val: &Timestamp, serializer: S) -> Result<S::Ok, S::Error> { |
| 293 | + if val.increment != 0 { |
| 294 | + return Err(ser::Error::custom( |
| 295 | + "Cannot convert Timestamp with a non-zero increment to u32", |
| 296 | + )); |
| 297 | + } |
| 298 | + serializer.serialize_u32(val.time) |
| 299 | + } |
| 300 | + |
| 301 | + /// Deserializes a bson::Timestamp from a u32. |
| 302 | + pub fn deserialize<'de, D>(deserializer: D) -> Result<Timestamp, D::Error> |
| 303 | + where |
| 304 | + D: Deserializer<'de>, |
| 305 | + { |
| 306 | + let time = u32::deserialize(deserializer)?; |
| 307 | + Ok(Timestamp { time, increment: 0 }) |
| 308 | + } |
| 309 | +} |
0 commit comments