1use thiserror::Error;
5use tracing::error;
6
7use crate::variant::*;
8
9#[derive(Debug, Clone, PartialEq)]
13pub struct Array {
14 pub value_type: VariantScalarTypeId,
16
17 pub values: Vec<Variant>,
19
20 pub dimensions: Option<Vec<u32>>,
25}
26
27#[derive(Debug, Error)]
28pub enum ArrayError {
30 #[error("Variant array do not match outer type")]
31 ContentMismatch,
33 #[error("Variant array dimensions multiplied together do not equal the actual array length")]
35 InvalidDimensions,
36}
37
38impl Array {
39 pub fn new<V>(value_type: VariantScalarTypeId, values: V) -> Result<Array, ArrayError>
41 where
42 V: Into<Vec<Variant>>,
43 {
44 let values = values.into();
45 Self::validate_array_type_to_values(value_type, &values)?;
46 Ok(Array {
47 value_type,
48 values,
49 dimensions: None,
50 })
51 }
52
53 pub fn new_multi<V, D>(
57 value_type: VariantScalarTypeId,
58 values: V,
59 dimensions: D,
60 ) -> Result<Array, ArrayError>
61 where
62 V: Into<Vec<Variant>>,
63 D: Into<Vec<u32>>,
64 {
65 let values = values.into();
66 let dimensions: Vec<_> = dimensions.into();
67
68 if !Self::validate_dimensions(values.len(), &dimensions) {
69 return Err(ArrayError::InvalidDimensions);
70 }
71
72 Self::validate_array_type_to_values(value_type, &values)?;
73 Ok(Array {
74 value_type,
75 values,
76 dimensions: Some(dimensions),
77 })
78 }
79
80 fn validate_array_type_to_values(
82 value_type: VariantScalarTypeId,
83 values: &[Variant],
84 ) -> Result<(), ArrayError> {
85 if !values_are_of_type(values, value_type) {
86 Err(ArrayError::ContentMismatch)
88 } else {
89 Ok(())
90 }
91 }
92
93 pub fn is_valid(&self) -> bool {
95 self.is_valid_dimensions() && Self::array_is_valid(&self.values)
96 }
97
98 pub fn encoding_mask(&self) -> u8 {
100 let mut encoding_mask = self.value_type.encoding_mask();
101 encoding_mask |= EncodingMask::ARRAY_VALUES_BIT;
102 if self.dimensions.is_some() {
103 encoding_mask |= EncodingMask::ARRAY_DIMENSIONS_BIT;
104 }
105 encoding_mask
106 }
107
108 fn array_is_valid(values: &[Variant]) -> bool {
110 if values.is_empty() {
111 true
112 } else {
113 let expected_type_id = values[0].type_id();
114 match expected_type_id {
115 VariantTypeId::Array(_, _) => {
116 error!("Variant array contains nested array {:?}", expected_type_id);
118 false
119 }
120 VariantTypeId::Empty => {
121 error!("Variant array contains null values");
122 false
123 }
124 VariantTypeId::Scalar(s) => {
125 if values.len() > 1 {
126 values_are_of_type(&values[1..], s)
127 } else {
128 true
129 }
130 }
131 }
132 }
133 }
134
135 fn validate_dimensions(values_len: usize, dimensions: &[u32]) -> bool {
136 let len = dimensions
137 .iter()
138 .map(|d| *d as usize)
139 .reduce(|a, b| a * b)
140 .unwrap_or(0);
141 len == values_len
142 }
143
144 fn is_valid_dimensions(&self) -> bool {
145 if let Some(ref dimensions) = self.dimensions {
146 Self::validate_dimensions(self.values.len(), dimensions)
147 } else {
148 true
149 }
150 }
151}
152
153pub fn values_are_of_type(values: &[Variant], expected_type: VariantScalarTypeId) -> bool {
155 let found_unexpected = values.iter().any(|v| match v.type_id() {
157 VariantTypeId::Array(_, _) => true,
158 VariantTypeId::Scalar(s) => s != expected_type,
159 VariantTypeId::Empty => true,
160 });
161 if found_unexpected {
162 error!(
163 "Variant array's type is expected to be {:?} but found other types in it",
164 expected_type
165 );
166 };
167 !found_unexpected
168}