librespot-core 0.8.0

The core functionality provided by librespot
Documentation
use base64::Engine;
use base64::prelude::BASE64_STANDARD;
use protobuf::MessageFull;
use serde::de::{Error, Unexpected};
use serde::{Deserialize, Deserializer};
use serde_json::Value;

const IGNORE_UNKNOWN: protobuf_json_mapping::ParseOptions = protobuf_json_mapping::ParseOptions {
    ignore_unknown_fields: true,
    _future_options: (),
};

fn parse_value_to_msg<T: MessageFull>(
    value: &Value,
) -> Result<T, protobuf_json_mapping::ParseError> {
    protobuf_json_mapping::parse_from_str_with_options::<T>(&value.to_string(), &IGNORE_UNKNOWN)
}

pub fn base64_proto<'de, T, D>(de: D) -> Result<Option<T>, D::Error>
where
    T: MessageFull,
    D: Deserializer<'de>,
{
    let v: String = Deserialize::deserialize(de)?;
    let bytes = BASE64_STANDARD
        .decode(v)
        .map_err(|e| Error::custom(e.to_string()))?;

    T::parse_from_bytes(&bytes).map(Some).map_err(Error::custom)
}

pub fn json_proto<'de, T, D>(de: D) -> Result<T, D::Error>
where
    T: MessageFull,
    D: Deserializer<'de>,
{
    let v: Value = Deserialize::deserialize(de)?;
    parse_value_to_msg(&v).map_err(Error::custom)
}

pub fn option_json_proto<'de, T, D>(de: D) -> Result<Option<T>, D::Error>
where
    T: MessageFull,
    D: Deserializer<'de>,
{
    let v: Value = Deserialize::deserialize(de)?;
    parse_value_to_msg(&v).map(Some).map_err(Error::custom)
}

pub fn vec_json_proto<'de, T, D>(de: D) -> Result<Vec<T>, D::Error>
where
    T: MessageFull,
    D: Deserializer<'de>,
{
    let v: Value = Deserialize::deserialize(de)?;
    let array = match v {
        Value::Array(array) => array,
        _ => return Err(Error::custom("the value wasn't an array")),
    };

    let res = array
        .iter()
        .flat_map(parse_value_to_msg)
        .collect::<Vec<T>>();

    Ok(res)
}

pub fn boxed<'de, T, D>(de: D) -> Result<Box<T>, D::Error>
where
    T: Deserialize<'de>,
    D: Deserializer<'de>,
{
    let v: T = Deserialize::deserialize(de)?;
    Ok(Box::new(v))
}

pub fn bool_from_string<'de, D>(de: D) -> Result<bool, D::Error>
where
    D: Deserializer<'de>,
{
    match String::deserialize(de)?.as_ref() {
        "true" => Ok(true),
        "false" => Ok(false),
        other => Err(Error::invalid_value(
            Unexpected::Str(other),
            &"true or false",
        )),
    }
}