qubit_value/multi_values/multi_values_getter.rs
1// =============================================================================
2// Copyright (c) 2025 - 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8
9//! `TryFrom<&MultiValues>` implementations for strict typed reads.
10
11use qubit_datatype::DataType;
12
13use super::MultiValuesRepr;
14use super::multi_values::MultiValues;
15use crate::ValueMissing;
16use crate::value_error::ValueError;
17use crate::value_error::ValueResult;
18
19/// Implements strict borrowed collection reads from the shared value table.
20macro_rules! impl_multi_values_try_from_table {
21 (
22 ;
23 $(
24 (
25 [$($cfg:meta),*],
26 $variant:ident,
27 $type:ty,
28 $data_type:expr,
29 $materialization:ident,
30 $json_class:ident,
31 $number_projection:ident,
32 $value_doc:literal,
33 $multi_doc:literal
34 $(, $_wire:tt)*
35 )
36 ),+ $(,)?
37 ) => {
38 $(
39 $(#[$cfg])*
40 $(#[cfg_attr(docsrs, doc($cfg))])*
41 impl TryFrom<&MultiValues> for $type {
42 /// Reports a missing value or an exact runtime type mismatch.
43 type Error = ValueError;
44
45 /// Copies or clones the first element without converting its runtime type.
46 ///
47 /// # Parameters
48 ///
49 /// - `values`: The collection to read without modifying its storage.
50 ///
51 /// # Returns
52 ///
53 /// An owned copy or clone of the first element.
54 ///
55 /// # Errors
56 ///
57 /// Returns a missing-value error for an empty or matching unset collection,
58 /// or a type-mismatch error when the runtime element type differs.
59 #[inline(always)]
60 fn try_from(values: &MultiValues) -> ValueResult<$type> {
61 match &values.repr {
62 MultiValuesRepr::$variant(values) => values
63 .first()
64 .map(|value| materialize_stored!($materialization, value))
65 .ok_or(ValueError::Missing(ValueMissing::empty_collection($data_type, $data_type))),
66 MultiValuesRepr::Unset(actual) if *actual == $data_type => {
67 Err(ValueError::Missing(ValueMissing::unset_collection(*actual, *actual)))
68 }
69 _ => Err(ValueError::TypeMismatch {
70 expected: $data_type,
71 actual: values.data_type(),
72 }),
73 }
74 }
75 }
76
77 $(#[$cfg])*
78 $(#[cfg_attr(docsrs, doc($cfg))])*
79 impl TryFrom<&MultiValues> for Vec<$type> {
80 /// Reports a missing value or an exact runtime type mismatch.
81 type Error = ValueError;
82
83 /// Copies or clones all elements while preserving their order.
84 ///
85 /// # Parameters
86 ///
87 /// - `values`: The collection to read without modifying its storage.
88 ///
89 /// # Returns
90 ///
91 /// An owned vector, including an empty vector for matching empty storage.
92 ///
93 /// # Errors
94 ///
95 /// Returns a missing-value error for a matching unset collection,
96 /// or a type-mismatch error when the runtime element type differs.
97 #[inline(always)]
98 fn try_from(values: &MultiValues) -> ValueResult<Vec<$type>> {
99 match &values.repr {
100 MultiValuesRepr::$variant(values) => Ok(values
101 .iter()
102 .map(|value| materialize_stored!($materialization, value))
103 .collect()),
104 MultiValuesRepr::Unset(actual) if *actual == $data_type => {
105 Err(ValueError::Missing(ValueMissing::unset_collection(*actual, *actual)))
106 }
107 _ => Err(ValueError::TypeMismatch {
108 expected: $data_type,
109 actual: values.data_type(),
110 }),
111 }
112 }
113 }
114 )+
115 };
116}
117
118for_each_value_type!(impl_multi_values_try_from_table);
119
120/// Implements borrowed and consuming collection reads from the shared table.
121macro_rules! impl_multi_values_borrowed_and_owned_table {
122 (
123 ;
124 $(
125 (
126 [$($cfg:meta),*],
127 $variant:ident,
128 $type:ty,
129 $data_type:expr,
130 $materialization:ident,
131 $json_class:ident,
132 $number_projection:ident,
133 $value_doc:literal,
134 $multi_doc:literal
135 $(, $_wire:tt)*
136 )
137 ),+ $(,)?
138 ) => {
139 $(
140 $(#[$cfg])*
141 $(#[cfg_attr(docsrs, doc($cfg))])*
142 impl<'a> TryFrom<&'a MultiValues> for &'a $type {
143 /// Reports a missing value or an exact runtime type mismatch.
144 type Error = ValueError;
145
146 /// Borrows the first element without allocating or converting its runtime type.
147 ///
148 /// # Parameters
149 ///
150 /// - `values`: The collection whose storage is borrowed for the returned lifetime.
151 ///
152 /// # Returns
153 ///
154 /// A reference to the first element, valid for the input borrow.
155 ///
156 /// # Errors
157 ///
158 /// Returns a missing-value error for an empty or matching unset collection,
159 /// or a type-mismatch error when the runtime element type differs.
160 #[inline(always)]
161 fn try_from(values: &'a MultiValues) -> ValueResult<Self> {
162 match &values.repr {
163 MultiValuesRepr::$variant(values) => values.first().ok_or(
164 ValueError::Missing(ValueMissing::empty_collection($data_type, $data_type)),
165 ),
166 MultiValuesRepr::Unset(actual) if *actual == $data_type => {
167 Err(ValueError::Missing(ValueMissing::unset_collection(*actual, *actual)))
168 }
169 _ => Err(ValueError::TypeMismatch {
170 expected: $data_type,
171 actual: values.data_type(),
172 }),
173 }
174 }
175 }
176
177 $(#[$cfg])*
178 $(#[cfg_attr(docsrs, doc($cfg))])*
179 impl<'a> TryFrom<&'a MultiValues> for &'a [$type] {
180 /// Reports a missing value or an exact runtime type mismatch.
181 type Error = ValueError;
182
183 /// Borrows the complete element slice without allocating.
184 ///
185 /// # Parameters
186 ///
187 /// - `values`: The collection whose storage is borrowed for the returned lifetime.
188 ///
189 /// # Returns
190 ///
191 /// The stored slice, possibly empty, valid for the input borrow.
192 ///
193 /// # Errors
194 ///
195 /// Returns a missing-value error for a matching unset collection,
196 /// or a type-mismatch error when the runtime element type differs.
197 #[inline(always)]
198 fn try_from(values: &'a MultiValues) -> ValueResult<Self> {
199 match &values.repr {
200 MultiValuesRepr::$variant(values) => Ok(values.as_slice()),
201 MultiValuesRepr::Unset(actual) if *actual == $data_type => {
202 Err(ValueError::Missing(ValueMissing::unset_collection(*actual, *actual)))
203 }
204 _ => Err(ValueError::TypeMismatch {
205 expected: $data_type,
206 actual: values.data_type(),
207 }),
208 }
209 }
210 }
211
212 $(#[$cfg])*
213 $(#[cfg_attr(docsrs, doc($cfg))])*
214 impl TryFrom<MultiValues> for Vec<$type> {
215 /// Reports a missing value or an exact runtime type mismatch.
216 type Error = ValueError;
217
218 /// Moves the stored vector out of the collection without cloning its elements.
219 ///
220 /// # Parameters
221 ///
222 /// - `values`: The collection consumed by this conversion.
223 ///
224 /// # Returns
225 ///
226 /// The owned vector in its original order, possibly empty.
227 ///
228 /// # Errors
229 ///
230 /// Returns a missing-value error for a matching unset collection,
231 /// or a type-mismatch error when the runtime element type differs.
232 #[inline(always)]
233 fn try_from(values: MultiValues) -> ValueResult<Self> {
234 match values.repr {
235 MultiValuesRepr::$variant(values) => Ok(values),
236 MultiValuesRepr::Unset(actual) if actual == $data_type => {
237 Err(ValueError::Missing(ValueMissing::unset_collection(actual, actual)))
238 }
239 other => {
240 let actual = MultiValues { repr: other }.data_type();
241 Err(ValueError::TypeMismatch { expected: $data_type, actual })
242 }
243 }
244 }
245 }
246 )+
247 };
248}
249
250for_each_value_type!(impl_multi_values_borrowed_and_owned_table);
251
252impl<'a> TryFrom<&'a MultiValues> for &'a str {
253 /// Reports a missing string or an exact runtime type mismatch.
254 type Error = ValueError;
255
256 /// Borrows the first stored string as a slice without allocating.
257 ///
258 /// # Parameters
259 ///
260 /// - `values`: The collection borrowed for the returned slice's lifetime.
261 ///
262 /// # Returns
263 ///
264 /// The first string slice, valid for the input borrow.
265 ///
266 /// # Errors
267 ///
268 /// Returns a missing-value error for an empty or matching unset collection,
269 /// or a type-mismatch error when the runtime element type is not string.
270 #[inline(always)]
271 fn try_from(values: &'a MultiValues) -> ValueResult<Self> {
272 match &values.repr {
273 MultiValuesRepr::String(values) => {
274 values
275 .first()
276 .map(String::as_str)
277 .ok_or(ValueError::Missing(ValueMissing::empty_collection(
278 DataType::String,
279 DataType::String,
280 )))
281 }
282 MultiValuesRepr::Unset(actual) if *actual == DataType::String => Err(
283 ValueError::Missing(ValueMissing::unset_collection(*actual, *actual)),
284 ),
285 _ => Err(ValueError::TypeMismatch {
286 expected: DataType::String,
287 actual: values.data_type(),
288 }),
289 }
290 }
291}