mongodb 3.2.3

The official MongoDB driver for Rust
Documentation
use std::time::Duration;

use serde::{Deserialize, Deserializer, Serialize, Serializer};

use crate::{
    bson::{doc, Bson, Document},
    bson_util::get_u64,
    error::{Error, Result},
    options::WriteConcern,
};

pub(crate) mod duration_option_as_int_seconds {
    use super::*;

    pub(crate) fn serialize<S: Serializer>(
        val: &Option<Duration>,
        serializer: S,
    ) -> std::result::Result<S::Ok, S::Error> {
        match val {
            Some(duration) if duration.as_secs() > i32::MAX as u64 => serializer.serialize_i64(
                duration
                    .as_secs()
                    .try_into()
                    .map_err(serde::ser::Error::custom)?,
            ),
            #[allow(clippy::cast_possible_truncation)]
            Some(duration) => serializer.serialize_i32(duration.as_secs() as i32),
            None => serializer.serialize_none(),
        }
    }

    pub(crate) fn deserialize<'de, D>(
        deserializer: D,
    ) -> std::result::Result<Option<Duration>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let millis = Option::<u64>::deserialize(deserializer)?;
        Ok(millis.map(Duration::from_secs))
    }
}

pub(crate) fn serialize_duration_option_as_int_millis<S: Serializer>(
    val: &Option<Duration>,
    serializer: S,
) -> std::result::Result<S::Ok, S::Error> {
    match val {
        Some(duration) if duration.as_millis() > i32::MAX as u128 => serializer.serialize_i64(
            duration
                .as_millis()
                .try_into()
                .map_err(serde::ser::Error::custom)?,
        ),
        #[allow(clippy::cast_possible_truncation)]
        Some(duration) => serializer.serialize_i32(duration.as_millis() as i32),
        None => serializer.serialize_none(),
    }
}

pub(crate) fn deserialize_duration_option_from_u64_millis<'de, D>(
    deserializer: D,
) -> std::result::Result<Option<Duration>, D::Error>
where
    D: Deserializer<'de>,
{
    let millis = Option::<u64>::deserialize(deserializer)?;
    Ok(millis.map(Duration::from_millis))
}

#[allow(clippy::trivially_copy_pass_by_ref)]
pub(crate) fn serialize_u32_option_as_i32<S: Serializer>(
    val: &Option<u32>,
    serializer: S,
) -> std::result::Result<S::Ok, S::Error> {
    match val {
        Some(ref val) => bson::serde_helpers::serialize_u32_as_i32(val, serializer),
        None => serializer.serialize_none(),
    }
}

#[allow(clippy::trivially_copy_pass_by_ref)]
pub(crate) fn serialize_u32_option_as_batch_size<S: Serializer>(
    val: &Option<u32>,
    serializer: S,
) -> std::result::Result<S::Ok, S::Error> {
    match val {
        #[allow(clippy::cast_possible_wrap)]
        Some(val) if *val <= i32::MAX as u32 => (doc! {
            "batchSize": (*val as i32)
        })
        .serialize(serializer),
        None => Document::new().serialize(serializer),
        _ => Err(serde::ser::Error::custom(
            "batch size must be able to fit into a signed 32-bit integer",
        )),
    }
}

pub(crate) fn serialize_u64_option_as_i64<S: Serializer>(
    val: &Option<u64>,
    serializer: S,
) -> std::result::Result<S::Ok, S::Error> {
    match val {
        Some(ref v) => bson::serde_helpers::serialize_u64_as_i64(v, serializer),
        None => serializer.serialize_none(),
    }
}

pub(crate) fn deserialize_u64_from_bson_number<'de, D>(
    deserializer: D,
) -> std::result::Result<u64, D::Error>
where
    D: Deserializer<'de>,
{
    let bson = Bson::deserialize(deserializer)?;
    get_u64(&bson).ok_or_else(|| {
        serde::de::Error::custom(format!("could not deserialize u64 from {:?}", bson))
    })
}

pub(crate) fn serialize_error_as_string<S: Serializer>(
    val: &Error,
    serializer: S,
) -> std::result::Result<S::Ok, S::Error> {
    serializer.serialize_str(&val.to_string())
}

pub(crate) fn serialize_result_error_as_string<S: Serializer, T: Serialize>(
    val: &Result<T>,
    serializer: S,
) -> std::result::Result<S::Ok, S::Error> {
    val.as_ref()
        .map_err(|e| e.to_string())
        .serialize(serializer)
}

#[cfg(feature = "aws-auth")]
pub(crate) fn deserialize_datetime_option_from_double_or_string<'de, D>(
    deserializer: D,
) -> std::result::Result<Option<bson::DateTime>, D::Error>
where
    D: Deserializer<'de>,
{
    #[derive(Deserialize)]
    #[serde(untagged)]
    enum AwsDateTime {
        Double(f64),
        String(String),
    }

    let date_time = match AwsDateTime::deserialize(deserializer)? {
        #[allow(clippy::cast_possible_truncation)]
        AwsDateTime::Double(seconds) => {
            let millis = seconds * 1000.0;
            bson::DateTime::from_millis(millis as i64)
        }
        AwsDateTime::String(string) => bson::DateTime::parse_rfc3339_str(string)
            .map_err(|e| serde::de::Error::custom(format!("invalid RFC 3339 string: {}", e)))?,
    };

    Ok(Some(date_time))
}

pub(crate) fn write_concern_is_empty(write_concern: &Option<WriteConcern>) -> bool {
    write_concern
        .as_ref()
        .map_or(true, |write_concern| write_concern.is_empty())
}

#[cfg(test)]
pub(crate) fn deserialize_nonempty_vec<'de, D, T>(
    deserializer: D,
) -> std::result::Result<Option<Vec<T>>, D::Error>
where
    D: Deserializer<'de>,
    T: serde::de::DeserializeOwned,
{
    let vec: Vec<T> = Vec::deserialize(deserializer)?;
    if vec.is_empty() {
        return Err(serde::de::Error::custom(format!(
            "list provided for {} cannot be empty",
            std::any::type_name::<T>()
        )));
    }
    Ok(Some(vec))
}

#[cfg(test)]
pub(crate) fn serialize_indexed_map<S: Serializer, T: Serialize>(
    map: &std::collections::HashMap<usize, T>,
    serializer: S,
) -> std::result::Result<S::Ok, S::Error> {
    let string_map: std::collections::BTreeMap<_, _> = map
        .iter()
        .map(|(index, result)| (index.to_string(), result))
        .collect();
    string_map.serialize(serializer)
}

#[cfg(test)]
pub(crate) fn deserialize_indexed_map<'de, D, T>(
    deserializer: D,
) -> std::result::Result<Option<std::collections::HashMap<usize, T>>, D::Error>
where
    D: Deserializer<'de>,
    T: serde::de::DeserializeOwned,
{
    use std::{collections::HashMap, str::FromStr};

    let string_map: HashMap<String, T> = HashMap::deserialize(deserializer)?;
    Ok(Some(string_map.into_iter().try_fold(
        HashMap::new(),
        |mut map, (index, t)| {
            let index = usize::from_str(&index).map_err(serde::de::Error::custom)?;
            map.insert(index, t);
            Ok(map)
        },
    )?))
}

pub(crate) fn serialize_bool_or_true<S: Serializer>(
    val: &Option<bool>,
    serializer: S,
) -> std::result::Result<S::Ok, S::Error> {
    let val = val.unwrap_or(true);
    serializer.serialize_bool(val)
}