fundamentum_edge_mcu_http_client/models/api_response/
failed_data.rs

1use core::fmt;
2
3use serde::{
4    de::{Error, IgnoredAny, SeqAccess, Visitor},
5    Deserialize, Deserializer,
6};
7
8use super::ApiStatus;
9
10/// The basic Fundamentum API response scheme for errors with data.
11#[derive(Deserialize)]
12#[cfg_attr(feature = "log", derive(defmt::Format))]
13#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
14pub struct ApiResponseFailedData<'a> {
15    /// The response status
16    #[serde(rename = "status")]
17    pub status: Option<ApiStatus>,
18    /// The error message
19    #[serde(rename = "message")]
20    pub message: Option<&'a str>,
21    /// More information about the error.
22    #[serde(rename = "data")]
23    pub data: Option<ApiErrors<'a>>,
24}
25
26pub const MAX_NUMBER_OF_ERRORS: usize = 8;
27type VectorErrors<'a> = [Option<ApiError<'a>>; MAX_NUMBER_OF_ERRORS];
28
29/// Contains a *Vector* of Fundamentum API errors.
30///
31/// This allows receiving a variable amount of errors from the API.
32///
33/// ### Note
34///
35/// This is a fake vector. It actually only stores a certain number of errors.
36#[derive(Deserialize)]
37#[cfg_attr(feature = "log", derive(defmt::Format))]
38#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
39pub struct ApiErrors<'a> {
40    /// *Vector* of Fundamentum errors
41    #[serde(
42        rename = "errors",
43        borrow,
44        deserialize_with = "deserialize_vector_errors"
45    )]
46    pub errors: Option<VectorErrors<'a>>,
47}
48
49fn deserialize_vector_errors<'de, D: Deserializer<'de>>(
50    deserializer: D,
51) -> Result<Option<VectorErrors<'de>>, D::Error> {
52    deserializer.deserialize_option(VectorVisitor)
53}
54
55struct VectorVisitor;
56impl<'de> Visitor<'de> for VectorVisitor {
57    type Value = Option<VectorErrors<'de>>;
58
59    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
60        formatter.write_str("A vector of FundamentumError")
61    }
62
63    fn visit_none<E: Error>(self) -> Result<Self::Value, E> {
64        Ok(None)
65    }
66
67    fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
68        deserializer.deserialize_seq(Self)
69    }
70
71    fn visit_seq<V: SeqAccess<'de>>(self, mut seq: V) -> Result<Self::Value, V::Error> {
72        let mut errors = [None::<ApiError<'de>>; MAX_NUMBER_OF_ERRORS];
73
74        for error in &mut errors {
75            match seq.next_element()? {
76                Some(maybe_response_error) => *error = maybe_response_error,
77                None => break,
78            }
79        }
80
81        // Skip all remaining elements in the sequence
82        while seq.next_element()? == Some(IgnoredAny) {}
83
84        Ok(Some(errors))
85    }
86}
87
88/// A single Fundamentum API error
89#[derive(Deserialize, Copy, Clone)]
90#[cfg_attr(feature = "log", derive(defmt::Format))]
91#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
92pub struct ApiError<'a> {
93    /// Error type
94    #[serde(rename = "type")]
95    pub r#type: &'a str,
96    /// Value which has an error
97    pub value: &'a str,
98    /// Error Message
99    pub msg: &'a str,
100    /// Path to the error
101    pub path: &'a str,
102    /// Location of the error (header, body, ...)
103    pub location: &'a str,
104}