1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use super::{Description, DimElement, Name};
use core::ops::{Deref, DerefMut};

/// A single SVD instance or array of instances
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MaybeArray<T> {
    /// A single instance
    Single(T),
    /// An array of instances
    Array(T, DimElement),
}

impl<T> Deref for MaybeArray<T> {
    type Target = T;

    fn deref(&self) -> &T {
        match self {
            Self::Single(info) => info,
            Self::Array(info, _) => info,
        }
    }
}

impl<T> DerefMut for MaybeArray<T> {
    fn deref_mut(&mut self) -> &mut T {
        match self {
            Self::Single(info) => info,
            Self::Array(info, _) => info,
        }
    }
}

impl<T> MaybeArray<T> {
    /// Return `true` if instance is single
    pub const fn is_single(&self) -> bool {
        matches!(self, Self::Single(_))
    }
    /// Return `true` if it is an array
    pub const fn is_array(&self) -> bool {
        matches!(self, Self::Array(_, _))
    }
}

impl<T> Name for MaybeArray<T>
where
    T: Name,
{
    fn name(&self) -> &str {
        T::name(self)
    }
}

impl<T> Description for MaybeArray<T>
where
    T: Description,
{
    fn description(&self) -> Option<&str> {
        T::description(self)
    }
}

/// Return list of names of instances in array
pub fn names<'a, T: Name>(info: &'a T, dim: &'a DimElement) -> impl Iterator<Item = String> + 'a {
    let name = info.name();
    dim.indexes().map(move |i| {
        dim.dim_array_index
            .as_ref()
            .and_then(|dai| {
                dai.values
                    .iter()
                    .find(|e| e.value.map(|v| v.to_string().as_str() == i.deref()) == Some(true))
            })
            .map(|n| n.name.clone())
            .unwrap_or_else(|| name.replace("[%s]", &i).replace("%s", &i))
    })
}

/// Return list of descriptions of instances in array
pub fn descriptions<'a, T: Description>(
    info: &'a T,
    dim: &'a DimElement,
) -> impl Iterator<Item = Option<String>> + 'a {
    let description = info.description();
    dim.indexes().map(move |i| {
        dim.dim_array_index
            .as_ref()
            .and_then(|dai| {
                dai.values
                    .iter()
                    .find(|e| e.value.map(|v| v.to_string().as_str() == i.deref()) == Some(true))
            })
            .and_then(|n| n.description.clone())
            .or_else(|| description.map(|d| d.replace("[%s]", &i).replace("%s", &i)))
    })
}

#[cfg(feature = "serde")]
mod ser_de {
    use super::*;
    use serde::{Deserialize, Deserializer, Serialize, Serializer};

    #[derive(serde::Serialize)]
    struct SerArray<'a, T> {
        #[serde(flatten)]
        dim: &'a DimElement,
        #[serde(flatten)]
        info: &'a T,
    }

    #[derive(serde::Deserialize)]
    struct DeserArray<T> {
        #[serde(flatten, default)]
        dim: Option<DimElement>,
        #[serde(flatten)]
        info: T,
    }

    impl<T> Serialize for MaybeArray<T>
    where
        T: Serialize,
    {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            match self {
                Self::Single(info) => info.serialize(serializer),
                Self::Array(info, dim) => SerArray::<T> { dim, info }.serialize(serializer),
            }
        }
    }

    impl<'de, T> Deserialize<'de> for MaybeArray<T>
    where
        T: Deserialize<'de>,
    {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            let DeserArray { dim, info } = DeserArray::<T>::deserialize(deserializer)?;
            if let Some(dim) = dim {
                Ok(Self::Array(info, dim))
            } else {
                Ok(Self::Single(info))
            }
        }
    }
}