navajo 0.0.4

cryptographic APIs
Documentation
use core::fmt::Display;

use alloc::{
    string::{String, ToString},
    vec,
    vec::Vec,
};
use serde::{de::Visitor, Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StringOrStrings {
    String(String),
    Strings(Vec<String>),
}
impl Display for StringOrStrings {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        match self {
            Self::String(s) => write!(f, "{s}"),
            Self::Strings(v) => write!(f, "{}", v.join(", ")),
        }
    }
}
impl StringOrStrings {
    pub fn push(&mut self, value: String) {
        match self {
            Self::String(s) => {
                let v = vec![s.clone(), value];
                *self = Self::Strings(v);
            }
            Self::Strings(v) => v.push(value),
        }
    }
    pub fn as_vec(&self) -> Vec<&str> {
        match self {
            Self::String(s) => vec![s],
            Self::Strings(v) => v.iter().map(|s| s.as_str()).collect(),
        }
    }
    pub fn contains(&self, value: &str) -> bool {
        match self {
            Self::String(s) => s == value,
            Self::Strings(v) => v.contains(&value.to_string()),
        }
    }
}
impl Extend<String> for StringOrStrings {
    fn extend<T: IntoIterator<Item = String>>(&mut self, iter: T) {
        match self {
            Self::String(s) => {
                let mut v = Vec::with_capacity(2);
                v.push(s.clone());
                v.extend(iter);
                *self = Self::Strings(v);
            }
            Self::Strings(v) => v.extend(iter),
        }
    }
}

impl Serialize for StringOrStrings {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        match self {
            Self::String(s) => serializer.serialize_str(s),
            Self::Strings(v) => serializer.collect_seq(v),
        }
    }
}

impl<'de> Deserialize<'de> for StringOrStrings {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct StringOrStringsVisitor;

        impl<'de> Visitor<'de> for StringOrStringsVisitor {
            type Value = StringOrStrings;

            fn expecting(&self, formatter: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
                formatter.write_str("a string or an array of strings")
            }
            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                Ok(StringOrStrings::String(v.to_string()))
            }
            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
            where
                A: serde::de::SeqAccess<'de>,
            {
                let mut strings = Vec::new();
                while let Some(s) = seq.next_element()? {
                    strings.push(s);
                }
                Ok(StringOrStrings::Strings(strings))
            }
        }

        deserializer.deserialize_any(StringOrStringsVisitor)
    }
}

impl From<String> for StringOrStrings {
    fn from(s: String) -> Self {
        Self::String(s)
    }
}
impl From<Vec<String>> for StringOrStrings {
    fn from(v: Vec<String>) -> Self {
        Self::Strings(v)
    }
}

impl From<&str> for StringOrStrings {
    fn from(s: &str) -> Self {
        Self::String(s.to_string())
    }
}
impl From<&String> for StringOrStrings {
    fn from(s: &String) -> Self {
        Self::String(s.to_string())
    }
}
impl From<&[String]> for StringOrStrings {
    fn from(v: &[String]) -> Self {
        Self::Strings(v.to_vec())
    }
}
impl From<&[&str]> for StringOrStrings {
    fn from(v: &[&str]) -> Self {
        Self::Strings(v.iter().map(|s| s.to_string()).collect())
    }
}

impl From<Vec<&str>> for StringOrStrings {
    fn from(v: Vec<&str>) -> Self {
        Self::from(&v[..])
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_serde() {
        #[derive(Serialize, Debug)]
        struct Input {
            string: String,
            strings: Vec<String>,
        }

        #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
        struct Expected {
            string: StringOrStrings,
            strings: StringOrStrings,
        }
        let strings = vec!["string_1".to_string(), "string_2".to_string()];
        let string = "string val".to_string();
        let input = Input {
            string: string.clone(),
            strings: strings.clone(),
        };

        let input_json = serde_json::to_string(&input).unwrap();

        let expected = Expected {
            string: string.into(),
            strings: strings.into(),
        };
        let result = serde_json::from_str::<Expected>(&input_json).unwrap();

        assert_eq!(expected, result);
    }
}