matomo-rs 0.1.0

Async client for the Matomo Reporting API, focused on data export and migration
Documentation
use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer};
use serde_json::Value;

/// Matomo encodes "no items" as integer `0` (and occasionally `null`, `[]` or
/// `{}`) but a populated list as an array of objects. Map all of the empty
/// forms to an empty `Vec`, and otherwise deserialize the array.
///
/// One reusable deserializer; do not scatter untagged enums for this.
pub fn empty_or_vec<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
    D: Deserializer<'de>,
    T: DeserializeOwned,
{
    let value = Value::deserialize(deserializer)?;
    match value {
        Value::Array(_) => serde_json::from_value(value).map_err(serde::de::Error::custom),
        Value::Null => Ok(Vec::new()),
        Value::Object(map) if map.is_empty() => Ok(Vec::new()),
        // `0` (or any non-array scalar Matomo uses for "none") → empty.
        Value::Number(_) | Value::Bool(_) | Value::String(_) => Ok(Vec::new()),
        Value::Object(_) => serde_json::from_value(value).map_err(serde::de::Error::custom),
    }
}