restrepo 0.5.12

A collection of components for building restful webservices with actix-web
Documentation
//! Random tools and helpers

use actix_service::boxed::BoxServiceFactory;
use actix_web::{
    Error,
    body::BoxBody,
    dev::{ServiceRequest, ServiceResponse},
};
use serde::{Deserialize, de};

pub(crate) type BoxedServiceFactory =
    BoxServiceFactory<(), ServiceRequest, ServiceResponse<BoxBody>, Error, ()>;

#[inline]
pub(crate) fn sanitize_path(mut p: String) -> String {
    if p.is_empty() {
        return p;
    }
    if p.len() > 1 && !p.starts_with('/') {
        p.insert(0, '/');
    }
    if p.ends_with('/') {
        p.pop();
    }
    p.replace("_", "-")
        .replace("..", "")
        .replace("\\", "/")
        .replace("//", "/")
        .to_lowercase()
}

pub(crate) fn deserialize_one_or_many_strings<'de, D>(
    deserializer: D,
) -> Result<Vec<String>, D::Error>
where
    D: serde::Deserializer<'de>,
{
    struct StringOrVecVisitor;

    impl<'de> de::Visitor<'de> for StringOrVecVisitor {
        type Value = Vec<String>;

        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
            formatter.write_str("a string or a list of strings")
        }

        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
        where
            E: de::Error,
        {
            Ok(vec![value.to_owned()])
        }

        fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
        where
            A: de::SeqAccess<'de>,
        {
            Vec::<String>::deserialize(de::value::SeqAccessDeserializer::new(seq))
        }
    }

    deserializer.deserialize_any(StringOrVecVisitor)
}

#[cfg(test)]
mod tests {
    use serde::Deserialize;

    #[derive(Debug, Deserialize, PartialEq)]
    struct TestStruct {
        #[serde(deserialize_with = "super::deserialize_one_or_many_strings")]
        field: Vec<String>,
    }

    #[test]
    fn test_string_or_string_vector_deserializer() {
        let input_str: TestStruct = serde_json::from_str(r#"{"field": "foo"}"#).unwrap();
        let input_seq: TestStruct = serde_json::from_str(r#"{"field": ["foo"]}"#).unwrap();
        let input_check = TestStruct {
            field: vec!["foo".to_string()],
        };

        assert_eq!(input_str, input_check);
        assert_eq!(input_seq, input_check);
    }
}