qubit_value/multi_values/multi_values.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//! # Multiple Values Container
9//!
10//! Provides type-safe storage and access functionality for multiple values.
11// Tests are intentionally distributed across behavior-specific files under
12// tests/multi_values/ rather than collected in multi_values_tests.rs.
13use std::collections::HashMap;
14use std::fmt;
15#[cfg(feature = "json")]
16use std::hash::Hash;
17#[cfg(feature = "json")]
18use std::hash::Hasher;
19#[cfg(feature = "json")]
20use std::mem::discriminant;
21use std::mem::replace;
22use std::time::Duration;
23
24#[cfg(feature = "big-decimal")]
25use bigdecimal::BigDecimal;
26#[cfg(feature = "chrono")]
27use chrono::DateTime;
28#[cfg(feature = "chrono")]
29use chrono::NaiveDate;
30#[cfg(feature = "chrono")]
31use chrono::NaiveDateTime;
32#[cfg(feature = "chrono")]
33use chrono::NaiveTime;
34#[cfg(feature = "chrono")]
35use chrono::Utc;
36#[cfg(feature = "big-integer")]
37use num_bigint::BigInt;
38#[cfg(feature = "json")]
39use qubit_budget::MeasuredBudgetError;
40#[cfg(feature = "json")]
41use qubit_budget::ResourceQuantity;
42#[cfg(feature = "json")]
43use qubit_budget::json::JsonValueBudget;
44#[cfg(feature = "converter")]
45use qubit_datatype::ConversionLimits;
46#[cfg(feature = "converter")]
47use qubit_datatype::ConversionPolicy;
48#[cfg(feature = "converter")]
49use qubit_datatype::ConversionSession;
50#[cfg(feature = "converter")]
51use qubit_datatype::DataConversionError;
52#[cfg(feature = "converter")]
53use qubit_datatype::DataConversionTarget;
54#[cfg(feature = "converter")]
55use qubit_datatype::DataConverter;
56#[cfg(feature = "converter")]
57use qubit_datatype::DataConverters;
58use qubit_datatype::DataType;
59#[cfg(feature = "json")]
60use serde_json::Value as JsonValue;
61#[cfg(feature = "url")]
62use url::Url;
63
64use super::internal::MultiValuesRepr;
65#[cfg(feature = "json")]
66use super::multi_values_identity::hash_non_json_multi_values_payload;
67use super::multi_values_ref::MultiValuesRef;
68use crate::IntoValueDefault;
69use crate::StrictValueRead;
70use crate::Value;
71use crate::ValueError;
72use crate::ValueResult;
73#[cfg(feature = "json")]
74use crate::identity::hash_json;
75#[cfg(feature = "json")]
76use crate::identity::preflight_json;
77use crate::value::ValueRepr;
78
79/// Multiple typed runtime values with private storage representation.
80///
81/// # Equality and hashing
82///
83/// Equality includes the collection variant and preserves element count and
84/// order. An unset collection's declared element type also participates in its
85/// identity. Floating-point elements use the same-width NaN and signed-zero
86/// normalization as [`Value`]. String maps and JSON objects compare and hash
87/// independently of entry order, while JSON arrays preserve element order.
88/// BigDecimal elements use numeric equality with a consistent normalized hash.
89/// Use [`Value::numeric_cmp`] to compare numeric values across runtime types;
90/// `Eq` does not provide cross-type numeric comparison. Hash output is intended
91/// for in-process collections and is not a persistent fingerprint.
92///
93/// # JSON nesting and lifecycle
94///
95/// With the `json` feature, JSON equality and hashing use iterative traversal.
96/// This does not provide the same guarantee for the entire value lifecycle:
97/// cloning, ordinary `Debug` formatting, and dropping JSON payloads still
98/// follow recursive paths in the underlying `serde_json::Value`.
99/// Very deeply nested trees may exhaust the thread stack during those
100/// operations. This applies to JSON elements, not to the outer collection
101/// length.
102///
103/// Keep untrusted JSON nesting bounded, and consider these lifecycle operations
104/// before raising decoder depth limits. Directly constructed in-memory JSON
105/// does not pass through those decoder limits. Borrowed reads avoid unnecessary
106/// clones but do not remove recursive destruction of the source value.
107/// There is no universal safe depth across platforms and thread configurations.
108///
109/// # Examples
110///
111/// ```
112/// use qubit_value::MultiValues;
113///
114/// let values = MultiValues::from(vec![1_i32, 2, 3]);
115/// assert_eq!(values.get_int32s().unwrap(), &[1, 2, 3]);
116/// ```
117///
118/// Equality preserves element order and normalizes NaNs within one float width:
119///
120/// ```
121/// use qubit_value::MultiValues;
122///
123/// assert_ne!(MultiValues::Float64(vec![1.0, 2.0]), MultiValues::Float64(vec![2.0, 1.0]));
124/// assert_eq!(
125/// MultiValues::Float64(vec![f64::NAN]),
126/// MultiValues::Float64(vec![f64::NAN]),
127/// );
128/// ```
129#[must_use]
130#[derive(Clone)]
131pub struct MultiValues {
132 /// Private homogeneous storage backing the stable public accessor API.
133 pub(crate) repr: MultiValuesRepr,
134}
135
136impl fmt::Debug for MultiValues {
137 /// Formats the borrowed semantic view without cloning stored elements.
138 ///
139 /// # Parameters
140 ///
141 /// * `formatter` - Destination and formatting options.
142 ///
143 /// # Returns
144 ///
145 /// `Ok(())` after the view is written.
146 ///
147 /// # Errors
148 ///
149 /// Propagates an error from the formatting destination.
150 #[inline]
151 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
152 self.view().fmt(formatter)
153 }
154}
155
156/// Implements named collection constructors from the shared value table.
157macro_rules! impl_multi_values_constructors {
158 (
159 ;
160 $(
161 (
162 [$($cfg:meta),*],
163 $variant:ident,
164 $type:ty,
165 $data_type:expr,
166 $materialization:ident,
167 $json_class:ident,
168 $number_projection:ident,
169 $value_doc:literal,
170 $multi_doc:literal
171 $(, $_wire:tt)*
172 )
173 ),+ $(,)?
174 ) => {
175 impl MultiValues {
176 /// Creates an unset collection with an explicit element type.
177 ///
178 /// # Parameters
179 ///
180 /// * `data_type` - Element type retained while the collection is unset.
181 ///
182 /// # Returns
183 ///
184 /// An unset collection retaining `data_type`.
185 #[allow(non_snake_case)]
186 #[inline(always)]
187 pub const fn Unset(data_type: DataType) -> Self {
188 Self::new_unset(data_type)
189 }
190
191 /// Creates an unset collection with an explicit element type.
192 ///
193 /// # Parameters
194 ///
195 /// * `data_type` - Element type retained while the collection is unset.
196 ///
197 /// # Returns
198 ///
199 /// An unset collection retaining `data_type`.
200 #[inline(always)]
201 pub const fn new_unset(data_type: DataType) -> Self {
202 Self { repr: MultiValuesRepr::Unset(data_type) }
203 }
204
205 $(
206 #[doc = concat!("Creates a collection of ", $multi_doc, ".")]
207 ///
208 /// # Parameters
209 ///
210 /// * `values` - Homogeneous elements stored by the collection.
211 ///
212 /// # Returns
213 ///
214 /// A typed collection containing `values` in their original order.
215 $(#[$cfg])*
216 $(#[cfg_attr(docsrs, doc($cfg))])*
217 #[allow(non_snake_case)]
218 #[inline(always)]
219 pub fn $variant(values: Vec<$type>) -> Self {
220 Self { repr: MultiValuesRepr::$variant(values) }
221 }
222 )+
223 }
224 };
225}
226
227/// Borrows owned storage through the shared type table.
228macro_rules! owned_view_match {
229 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
230 match &$value.repr {
231 MultiValuesRepr::Unset(data_type) => MultiValuesRef::Unset(*data_type),
232 $($(#[$cfg])* MultiValuesRepr::$variant(value) => MultiValuesRef::$variant(
233 value.as_slice()
234 ),)+
235 }
236 };
237}
238
239for_each_value_type!(impl_multi_values_constructors);
240
241impl MultiValues {
242 /// Strictly borrows the first stored item without allocating.
243 ///
244 /// The returned reference is tied to this collection's lifetime. The
245 /// requested type must match the stored element type.
246 ///
247 /// # Type Parameters
248 ///
249 /// * `T` - Stored element type to borrow.
250 ///
251 /// # Returns
252 ///
253 /// A reference to the first item.
254 ///
255 /// # Errors
256 ///
257 /// Returns [`ValueError::Missing`] when no first item is available, or a
258 /// type conversion error when the stored element type does not match `T`.
259 ///
260 /// # Examples
261 ///
262 /// ```
263 /// use qubit_value::{MultiValues, ValueError};
264 ///
265 /// let values = MultiValues::new(vec![String::from("a"), String::from("b")]);
266 /// let first: &String = values.get_first_ref().unwrap();
267 /// assert_eq!(first, "a");
268 /// let empty = MultiValues::new(Vec::<String>::new());
269 /// assert!(matches!(empty.get_first_ref::<String>(), Err(ValueError::Missing(_))));
270 /// ```
271 ///
272 /// A first-item borrow does not accept a complete slice target:
273 ///
274 /// ```compile_fail
275 /// use qubit_value::MultiValues;
276 ///
277 /// let values = MultiValues::Int32(vec![1, 2]);
278 /// let _: &[i32] = values.get_first_ref::<[i32]>().unwrap();
279 /// ```
280 #[inline(always)]
281 pub fn get_first_ref<'a, T: ?Sized>(&'a self) -> ValueResult<&'a T>
282 where
283 &'a T: TryFrom<&'a Value, Error = ValueError> + TryFrom<&'a Self, Error = ValueError>,
284 {
285 <&'a T>::try_from(self)
286 }
287
288 /// Strictly borrows the complete collection without allocating.
289 ///
290 /// The returned slice is tied to this collection's lifetime. The
291 /// requested element type must match the stored type.
292 ///
293 /// # Type Parameters
294 ///
295 /// * `T` - Stored element type of the borrowed slice.
296 ///
297 /// # Returns
298 ///
299 /// A slice of all stored items, including an empty slice for an empty
300 /// collection.
301 ///
302 /// # Errors
303 ///
304 /// Returns [`ValueError::TypeMismatch`] when the stored element type does
305 /// not match `T`. Returns [`ValueError::Missing`] when the collection is
306 /// unset with the requested stored type, with reason
307 /// [`crate::ValueMissingReason::UnsetCollection`]. A concrete empty
308 /// collection succeeds with an empty slice.
309 ///
310 /// # Examples
311 ///
312 /// ```
313 /// use qubit_value::MultiValues;
314 ///
315 /// let values = MultiValues::new(vec![String::from("a"), String::from("b")]);
316 /// let all: &[String] = values.get_slice().unwrap();
317 /// assert_eq!(all.len(), 2);
318 /// let empty = MultiValues::new(Vec::<String>::new());
319 /// assert!(empty.get_slice::<String>().unwrap().is_empty());
320 /// let unset = MultiValues::Unset(qubit_datatype::DataType::String);
321 /// let error = unset.get_slice::<String>().unwrap_err();
322 /// assert!(matches!(error, qubit_value::ValueError::Missing(_)));
323 /// assert_eq!(
324 /// error.missing().unwrap().reason(),
325 /// qubit_value::ValueMissingReason::UnsetCollection,
326 /// );
327 /// let error = unset.get_slice::<i32>().unwrap_err();
328 /// assert!(matches!(error, qubit_value::ValueError::TypeMismatch { .. }));
329 /// ```
330 #[inline(always)]
331 pub fn get_slice<'a, T>(&'a self) -> ValueResult<&'a [T]>
332 where
333 &'a [T]: TryFrom<&'a Self, Error = ValueError>,
334 {
335 <&'a [T]>::try_from(self)
336 }
337
338 /// Hashes this collection while applying `budget` to JSON elements.
339 ///
340 /// # Type Parameters
341 ///
342 /// * `H` - Hasher receiving the semantic collection identity.
343 /// * `R` - Resource identifier used by the JSON budget.
344 /// * `Q` - Quantity type used by the JSON budget.
345 ///
346 /// # Parameters
347 ///
348 /// * `state` - Hasher that receives the same identity representation as
349 /// [`Hash::hash`].
350 /// * `budget` - Mutable JSON traversal budget, used only for JSON elements.
351 ///
352 /// # Returns
353 ///
354 /// `Ok(())` after the complete semantic identity is hashed.
355 ///
356 /// # Errors
357 ///
358 /// Returns [`qubit_budget::MeasuredBudgetError`] when a JSON element
359 /// exceeds a configured limit.
360 /// On error, neither `state` nor the committed portion of `budget` is
361 /// modified. A hasher panic also drops the staged budget transaction.
362 ///
363 /// # Examples
364 ///
365 /// ```
366 /// use std::collections::hash_map::DefaultHasher;
367 ///
368 /// use qubit_budget::{ResourceLimit, StructureLimits};
369 /// use qubit_budget::json::{JsonResource, JsonValueBudget, JsonValueLimits};
370 /// use qubit_value::MultiValues;
371 ///
372 /// let values = MultiValues::Json(vec![serde_json::json!([null])]);
373 /// let structure = StructureLimits::<JsonResource, usize>::builder().nodes_limit(
374 /// ResourceLimit::new(JsonResource::Nodes, 1_usize),
375 /// ).build();
376 /// let mut budget = JsonValueBudget::new(
377 /// JsonValueLimits::builder().structure_limits(structure).build(),
378 /// );
379 /// let mut hasher = DefaultHasher::new();
380 ///
381 /// assert!(values.hash_with_json_budget(&mut hasher, &mut budget).is_err());
382 /// drop(hasher);
383 /// // The rejected values did not consume committed budget state.
384 /// ```
385 #[cfg(feature = "json")]
386 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
387 pub fn hash_with_json_budget<H, R, Q>(
388 &self,
389 state: &mut H,
390 budget: &mut JsonValueBudget<R, Q>,
391 ) -> Result<(), MeasuredBudgetError<R, Q>>
392 where
393 H: Hasher,
394 R: Clone,
395 Q: ResourceQuantity,
396 {
397 match &self.repr {
398 MultiValuesRepr::Json(values) => {
399 let mut transaction = budget.transaction();
400 for value in values {
401 preflight_json(value, &mut transaction)?;
402 }
403 discriminant(&self.repr).hash(state);
404 values.len().hash(state);
405 for value in values {
406 hash_json(value, state);
407 }
408 transaction.commit()
409 }
410 _ => {
411 discriminant(&self.repr).hash(state);
412 hash_non_json_multi_values_payload(&self.repr, state);
413 Ok(())
414 }
415 }
416 }
417
418 /// Borrows the stable semantic view of this collection.
419 ///
420 /// # Returns
421 ///
422 /// A non-owning homogeneous view that hides private storage details.
423 #[inline(always)]
424 pub fn view(&self) -> MultiValuesRef<'_> {
425 for_each_value_type!(owned_view_match, self)
426 }
427}
428
429// ============================================================================
430// Getter method generation macros
431// ============================================================================
432
433/// Unified multiple values getter generation macro
434///
435/// Generates `get_[xxx]s` methods for `MultiValues`, returning a reference to
436/// value slices.
437///
438/// # Documentation Comment Support
439///
440/// The macro automatically extracts preceding documentation comments, so you
441/// can add `///` comments before macro invocations.
442macro_rules! impl_get_multi_values {
443 // Every generated getter returns a borrowed slice.
444 ($(#[$attr:meta])* slice: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
445 $(#[$attr])*
446 #[doc = ""]
447 #[doc = "# Errors"]
448 #[doc = ""]
449 #[doc = "Returns [`ValueError::Missing`] when the container is unset"]
450 #[doc = "with the requested type, or [`ValueError::TypeMismatch`] when"]
451 #[doc = "the stored data type differs. A concrete empty vector returns"]
452 #[doc = "an empty slice."]
453 #[inline(always)]
454 pub fn $method(&self) -> ValueResult<&[$type]> {
455 match &self.repr {
456 MultiValuesRepr::$variant(v) => Ok(v.as_slice()),
457 MultiValuesRepr::Unset(dt) if *dt == $data_type => {
458 Err(ValueError::Missing($crate::ValueMissing::unset_collection(*dt, *dt)))
459 }
460 _ => Err(ValueError::TypeMismatch {
461 expected: $data_type,
462 actual: self.data_type(),
463 }),
464 }
465 }
466 };
467
468 // Compatibility label for existing internal invocations; use the shared slice implementation.
469 ($(#[$attr:meta])* vec: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
470 impl_get_multi_values! {
471 $(#[$attr])*
472 slice: $method, $variant, $type, $data_type
473 }
474 };
475}
476
477/// Unified multiple values get_first method generation macro
478///
479/// Generates `get_first_[xxx]` methods for `MultiValues`, used to get the first
480/// value.
481///
482/// # Documentation Comment Support
483///
484/// The macro automatically extracts preceding documentation comments, so you
485/// can add `///` comments before macro invocations.
486macro_rules! impl_get_first_value {
487 // Copy type: directly return value
488 ($(#[$attr:meta])* copy: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
489 $(#[$attr])*
490 #[doc = ""]
491 #[doc = "# Errors"]
492 #[doc = ""]
493 #[doc = "Returns [`ValueError::Missing`] when the requested type matches"]
494 #[doc = "but no value is stored, or [`ValueError::TypeMismatch`] when"]
495 #[doc = "the stored data type differs."]
496 #[inline(always)]
497 pub fn $method(&self) -> ValueResult<$type> {
498 match &self.repr {
499 MultiValuesRepr::$variant(v) if !v.is_empty() => Ok(v[0]),
500 MultiValuesRepr::$variant(_) => {
501 Err(ValueError::Missing($crate::ValueMissing::empty_collection($data_type, $data_type)))
502 }
503 MultiValuesRepr::Unset(dt) if *dt == $data_type => {
504 Err(ValueError::Missing($crate::ValueMissing::unset_collection(*dt, *dt)))
505 }
506 _ => Err(ValueError::TypeMismatch {
507 expected: $data_type,
508 actual: self.data_type(),
509 }),
510 }
511 }
512 };
513
514 // Reference type: return reference
515 ($(#[$attr:meta])* ref: $method:ident, $variant:ident, $ret_type:ty, $data_type:expr, $conversion:expr) => {
516 $(#[$attr])*
517 #[doc = ""]
518 #[doc = "# Errors"]
519 #[doc = ""]
520 #[doc = "Returns [`ValueError::Missing`] when the requested type matches"]
521 #[doc = "but no value is stored, or [`ValueError::TypeMismatch`] when"]
522 #[doc = "the stored data type differs."]
523 #[inline(always)]
524 pub fn $method(&self) -> ValueResult<$ret_type> {
525 match &self.repr {
526 MultiValuesRepr::$variant(v) if !v.is_empty() => {
527 let conv_fn: fn(&_) -> $ret_type = $conversion;
528 Ok(conv_fn(&v[0]))
529 },
530 MultiValuesRepr::$variant(_) => {
531 Err(ValueError::Missing($crate::ValueMissing::empty_collection($data_type, $data_type)))
532 }
533 MultiValuesRepr::Unset(dt) if *dt == $data_type => {
534 Err(ValueError::Missing($crate::ValueMissing::unset_collection(*dt, *dt)))
535 }
536 _ => Err(ValueError::TypeMismatch {
537 expected: $data_type,
538 actual: self.data_type(),
539 }),
540 }
541 }
542 };
543}
544
545#[cfg(all(feature = "converter", feature = "json"))]
546#[cfg_attr(docsrs, doc(cfg(all(feature = "converter", feature = "json"))))]
547impl MultiValues {
548 /// Projects this collection to its natural JSON representation.
549 ///
550 /// Unset is `null`; every concrete collection is an array, including empty
551 /// and one-item collections.
552 ///
553 /// # Returns
554 ///
555 /// The natural JSON representation of this collection.
556 ///
557 /// For natural JSON projection, `max_text_bytes` bounds each string value
558 /// and each formatted number or rich-value text by its UTF-8 byte length,
559 /// including strings inside materialized JSON. Object keys are excluded
560 /// from this per-item bound but still consume applicable key and
561 /// cumulative input, output, and payload budgets. This is neither a
562 /// cumulative text limit nor a limit on escaped JSON encoding size.
563 ///
564 /// # Errors
565 ///
566 /// Returns a list conversion error containing the zero-based source index
567 /// when an item cannot be represented as JSON.
568 #[inline]
569 pub fn to_json_value(&self) -> ValueResult<JsonValue> {
570 self.to_json_value_with(
571 ConversionPolicy::default_ref(),
572 ConversionLimits::default_ref(),
573 )
574 }
575
576 /// Projects this collection using explicit conversion policy and limits.
577 ///
578 /// # Parameters
579 ///
580 /// * `policy` - Controls duration units and precision-loss behavior.
581 /// * `limits` - Bounds conversion resource consumption.
582 ///
583 /// # Returns
584 ///
585 /// The natural JSON representation of this collection.
586 ///
587 /// # Errors
588 ///
589 /// Returns [`ValueError::JsonProjectionLimit`] when a projection resource
590 /// limit is exceeded; its collection index is absent for container-wide
591 /// limits and identifies an item for item-specific limits. Returns an
592 /// indexed [`ValueError::ListConversion`] when an item cannot be
593 /// represented under the requested policy, or another structured
594 /// conversion error for unsupported values.
595 #[inline(always)]
596 pub fn to_json_value_with(
597 &self,
598 policy: &ConversionPolicy,
599 limits: &ConversionLimits,
600 ) -> ValueResult<JsonValue> {
601 crate::json::multi_values_to_json_value_with(self, policy, limits)
602 }
603}
604
605/// Maps private collection storage variants to their runtime data types.
606macro_rules! multi_values_data_type_match {
607 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
608 match &$value.repr {
609 MultiValuesRepr::Unset(dt) => *dt,
610 $($(#[$cfg])* MultiValuesRepr::$variant(_) => $data_type,)+
611 }
612 };
613}
614
615/// Returns the concrete element count for each collection storage variant.
616macro_rules! multi_values_count_match {
617 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
618 match &$value.repr {
619 MultiValuesRepr::Unset(_) => 0,
620 $($(#[$cfg])* MultiValuesRepr::$variant(values) => values.len(),)+
621 }
622 };
623}
624
625/// Clears the concrete elements of each collection storage variant.
626macro_rules! multi_values_clear_match {
627 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
628 match &mut $value.repr {
629 MultiValuesRepr::Unset(_) => {}
630 $($(#[$cfg])* MultiValuesRepr::$variant(values) => values.clear(),)+
631 }
632 };
633}
634
635/// Appends same-typed elements to an existing collection storage variant.
636macro_rules! multi_values_append_match {
637 ($left:expr, $right:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
638 match (&mut $left.repr, &mut $right.repr) {
639 $(
640 $(#[$cfg])*
641 (MultiValuesRepr::$variant(values), MultiValuesRepr::$variant(other_values)) => {
642 values.append(other_values);
643 }
644 )+
645 (slot @ MultiValuesRepr::Unset(_), other_values) => {
646 *slot = replace(other_values, MultiValuesRepr::Unset(DataType::String));
647 }
648 _ => unreachable!(),
649 }
650 };
651}
652
653/// Clones the first collection element into a scalar value.
654macro_rules! multi_values_first_value_match {
655 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
656 match &$value.repr {
657 MultiValuesRepr::Unset(data_type) => Value::new_unset(*data_type),
658 $(
659 $(#[$cfg])*
660 MultiValuesRepr::$variant(values) => values
661 .first()
662 .map(|value| materialize_stored!($materialization, value))
663 .map(Value::$variant)
664 .unwrap_or(Value::new_unset($data_type)),
665 )+
666 }
667 };
668}
669
670/// Moves the first collection element into a scalar value.
671macro_rules! multi_values_into_first_value_match {
672 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
673 match $value.repr {
674 MultiValuesRepr::Unset(data_type) => Value::new_unset(data_type),
675 $(
676 $(#[$cfg])*
677 MultiValuesRepr::$variant(values) => values
678 .into_iter()
679 .next()
680 .map(Value::$variant)
681 .unwrap_or(Value::new_unset($data_type)),
682 )+
683 }
684 };
685}
686
687/// Merges same-typed collection storage while preserving element order.
688macro_rules! multi_values_merge_match {
689 ($left:expr, $right:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
690 match (&mut $left.repr, &$right.repr) {
691 $(
692 $(#[$cfg])*
693 (MultiValuesRepr::$variant(values), MultiValuesRepr::$variant(other_values)) => {
694 values.extend_from_slice(other_values)
695 }
696 )+
697 (slot @ MultiValuesRepr::Unset(_), other_values) => *slot = other_values.clone(),
698 _ => unreachable!(),
699 }
700 };
701}
702
703/// Converts one private scalar storage variant into collection storage.
704macro_rules! value_into_multi_values_match {
705 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
706 match $value.repr {
707 ValueRepr::Unset(data_type) => MultiValues::new_unset(data_type),
708 $($(#[$cfg])* ValueRepr::$variant(value) => {
709 MultiValues::$variant(vec![value_storage_into_multi!($variant, value)])
710 },)+
711 }
712 };
713}
714
715impl MultiValues {
716 /// Generic constructor method
717 ///
718 /// Creates `MultiValues` from any supported input form, avoiding direct
719 /// use of type-specific named constructors at call sites.
720 ///
721 /// Supported input forms include single values, vectors, slices, arrays,
722 /// borrowed vectors, and borrowed string collections for supported element
723 /// types.
724 ///
725 /// # Type Parameters
726 ///
727 /// * `S` - Input type convertible into [`MultiValues`].
728 ///
729 /// # Parameters
730 ///
731 /// * `values` - Values to convert into a collection.
732 ///
733 /// # Returns
734 ///
735 /// Returns `MultiValues` wrapping the converted input values.
736 ///
737 /// # Examples
738 ///
739 /// ```rust
740 /// use qubit_value::MultiValues;
741 ///
742 /// // Basic types
743 /// let mv = MultiValues::new(vec![1, 2, 3]);
744 /// assert_eq!(mv.len(), 3);
745 ///
746 /// // Strings
747 /// let mv = MultiValues::new(vec!["a".to_string(), "b".to_string()]);
748 /// assert_eq!(mv.len(), 2);
749 /// ```
750 #[inline(always)]
751 pub fn new<S>(values: S) -> Self
752 where
753 S: Into<Self>,
754 {
755 values.into()
756 }
757
758 /// Generic getter method for multiple values.
759 ///
760 /// Performs a strict typed read of all stored values as `Vec<T>`.
761 ///
762 /// # Type Parameters
763 ///
764 /// * `T` - The target element type to retrieve.
765 ///
766 /// # Returns
767 ///
768 /// Returns the list of values when the stored type matches `T`.
769 ///
770 /// # Errors
771 ///
772 /// Returns [`ValueError::Missing`] when the container is unset with the
773 /// requested type, or [`ValueError::TypeMismatch`] when the stored type
774 /// differs from `T`.
775 ///
776 /// # Examples
777 ///
778 /// ```rust
779 /// use qubit_value::MultiValues;
780 ///
781 /// let multi = MultiValues::Int32(vec![1, 2, 3]);
782 ///
783 /// // Through type inference
784 /// let nums: Vec<i32> = multi.get().unwrap();
785 /// assert_eq!(nums, vec![1, 2, 3]);
786 ///
787 /// // Explicitly specify type parameter
788 /// let nums = multi.get::<i32>().unwrap();
789 /// assert_eq!(nums, vec![1, 2, 3]);
790 /// ```
791 #[inline(always)]
792 pub fn get<T>(&self) -> ValueResult<Vec<T>>
793 where
794 for<'a> Vec<T>: TryFrom<&'a Self, Error = ValueError>,
795 {
796 Vec::<T>::try_from(self)
797 }
798
799 /// Generic getter method with a default value list.
800 ///
801 /// Returns the supplied default only when this container is unset. A
802 /// concrete empty vector remains an empty result.
803 ///
804 /// # Type Parameters
805 ///
806 /// * `T` - Target element type for the strict read.
807 ///
808 /// # Parameters
809 ///
810 /// * `default` - Lazily materialized list used only for unset storage.
811 ///
812 /// # Returns
813 ///
814 /// The concrete stored list, or `default` for unset storage.
815 ///
816 /// # Errors
817 ///
818 /// Returns [`ValueError::TypeMismatch`] when the stored type differs from
819 /// `T`.
820 #[inline(always)]
821 pub fn get_or<T>(&self, default: impl IntoValueDefault<Vec<T>>) -> ValueResult<Vec<T>>
822 where
823 for<'a> Vec<T>: TryFrom<&'a Self, Error = ValueError>,
824 {
825 match self.get() {
826 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_strict_read() => {
827 Ok(default.into_value_default())
828 }
829 result => result,
830 }
831 }
832
833 /// Strictly reads all values or calls `default` only when storage is unset.
834 ///
835 /// A concrete empty collection is returned unchanged and type mismatches
836 /// are preserved without invoking the callback.
837 ///
838 /// # Type Parameters
839 ///
840 /// * `T` - Target element type.
841 /// * `F` - Deferred fallback producing the complete list.
842 ///
843 /// # Parameters
844 ///
845 /// * `default` - Callback invoked only for unset storage.
846 ///
847 /// # Returns
848 ///
849 /// The stored list or the callback result.
850 ///
851 /// # Errors
852 ///
853 /// Returns [`ValueError::TypeMismatch`] for an incompatible concrete
854 /// collection without invoking the callback.
855 #[inline(always)]
856 pub fn get_or_else<T, F>(&self, default: F) -> ValueResult<Vec<T>>
857 where
858 for<'a> Vec<T>: TryFrom<&'a Self, Error = ValueError>,
859 F: FnOnce() -> Vec<T>,
860 {
861 match self.get() {
862 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_strict_read() => {
863 Ok(default())
864 }
865 result => result,
866 }
867 }
868
869 /// Generic getter method for the first value
870 ///
871 /// Reads the first stored value as `T`, performing strict type checking.
872 ///
873 /// `get_first<T>()` does not do cross-type conversion.
874 ///
875 /// # Type Parameters
876 ///
877 /// * `T` - The target element type to retrieve.
878 ///
879 /// # Returns
880 ///
881 /// Returns the first value when the stored type matches `T` and at least
882 /// one value exists.
883 ///
884 /// # Errors
885 ///
886 /// Returns [`ValueError::Missing`] when the requested type matches but no
887 /// value is stored, or [`ValueError::TypeMismatch`] when the stored type
888 /// differs from `T`.
889 ///
890 /// # Examples
891 ///
892 /// ```rust
893 /// use qubit_value::MultiValues;
894 ///
895 /// let multi = MultiValues::Int32(vec![42, 100, 200]);
896 ///
897 /// // Through type inference
898 /// let first: i32 = multi.get_first().unwrap();
899 /// assert_eq!(first, 42);
900 ///
901 /// // Explicitly specify type parameter
902 /// let first = multi.get_first::<i32>().unwrap();
903 /// assert_eq!(first, 42);
904 ///
905 /// // String type
906 /// let multi = MultiValues::String(vec!["hello".to_string(), "world".to_string()]);
907 /// let first: String = multi.get_first().unwrap();
908 /// assert_eq!(first, "hello");
909 /// ```
910 ///
911 /// A first-item read does not accept a complete collection target:
912 ///
913 /// ```compile_fail
914 /// use qubit_value::MultiValues;
915 ///
916 /// let values = MultiValues::Int32(vec![1, 2]);
917 /// let _: Vec<i32> = values.get_first::<Vec<i32>>().unwrap();
918 /// ```
919 #[cfg_attr(
920 feature = "converter",
921 doc = "When the `converter` feature is enabled, use [`Self::to_first`] for compatible cross-type conversion."
922 )]
923 #[cfg_attr(
924 not(feature = "converter"),
925 doc = "With the `converter` feature enabled, `to_first` provides compatible cross-type conversion."
926 )]
927 #[inline(always)]
928 pub fn get_first<T>(&self) -> ValueResult<T>
929 where
930 T: StrictValueRead,
931 {
932 T::read_collection_first(self)
933 }
934
935 /// Generic first-value getter with a default value.
936 ///
937 /// Returns the supplied default only when the container is unset. A
938 /// concrete empty vector returns [`ValueError::Missing`]; type mismatches
939 /// are also preserved.
940 ///
941 /// # Type Parameters
942 ///
943 /// * `T` - Target type for the strict first-item read.
944 ///
945 /// # Parameters
946 ///
947 /// * `default` - Lazily materialized value used only for unset storage.
948 ///
949 /// # Returns
950 ///
951 /// The first concrete item, or `default` for unset storage.
952 ///
953 /// # Errors
954 ///
955 /// Returns [`ValueError::Missing`] for a concrete empty collection or
956 /// [`ValueError::TypeMismatch`] when the stored type differs from `T`.
957 ///
958 /// ```compile_fail
959 /// use qubit_value::MultiValues;
960 ///
961 /// let values = MultiValues::Int32(vec![1, 2]);
962 /// let _: Vec<i32> = values.get_first_or::<Vec<i32>>(Vec::new()).unwrap();
963 /// ```
964 #[inline(always)]
965 pub fn get_first_or<T>(&self, default: impl IntoValueDefault<T>) -> ValueResult<T>
966 where
967 T: StrictValueRead,
968 {
969 match self.get_first() {
970 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_strict_read() => {
971 Ok(default.into_value_default())
972 }
973 result => result,
974 }
975 }
976
977 /// Strictly reads the first value or calls `default` only when unset.
978 ///
979 /// # Type Parameters
980 ///
981 /// * `T` - Target element type.
982 /// * `F` - Deferred fallback producing one element.
983 ///
984 /// # Parameters
985 ///
986 /// * `default` - Callback invoked only for unset storage.
987 ///
988 /// # Returns
989 ///
990 /// The first stored item or the callback result.
991 ///
992 /// # Errors
993 ///
994 /// Preserves empty-collection and type-mismatch errors without invoking
995 /// the callback.
996 ///
997 /// ```compile_fail
998 /// use qubit_value::MultiValues;
999 ///
1000 /// let values = MultiValues::Int32(vec![1, 2]);
1001 /// let _: Vec<i32> = values.get_first_or_else::<Vec<i32>, _>(Vec::new).unwrap();
1002 /// ```
1003 #[inline(always)]
1004 pub fn get_first_or_else<T, F>(&self, default: F) -> ValueResult<T>
1005 where
1006 T: StrictValueRead,
1007 F: FnOnce() -> T,
1008 {
1009 match self.get_first() {
1010 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_strict_read() => {
1011 Ok(default())
1012 }
1013 result => result,
1014 }
1015 }
1016
1017 /// Get the data type of the values
1018 ///
1019 /// # Returns
1020 ///
1021 /// Returns the data type corresponding to these multiple values
1022 ///
1023 /// # Examples
1024 ///
1025 /// ```rust
1026 /// use qubit_datatype::DataType;
1027 /// use qubit_value::MultiValues;
1028 ///
1029 /// let values = MultiValues::Int32(vec![1, 2, 3]);
1030 /// assert_eq!(values.data_type(), DataType::Int32);
1031 /// ```
1032 #[must_use = "the collection element type should be used"]
1033 #[inline(always)]
1034 pub fn data_type(&self) -> DataType {
1035 for_each_value_type!(multi_values_data_type_match, self)
1036 }
1037
1038 /// Returns the number of values.
1039 ///
1040 /// # Returns
1041 ///
1042 /// The number of values contained in these multiple values. An unset
1043 /// collection has length zero.
1044 ///
1045 /// # Examples
1046 ///
1047 /// ```rust
1048 /// use qubit_datatype::DataType;
1049 /// use qubit_value::MultiValues;
1050 ///
1051 /// let values = MultiValues::Int32(vec![1, 2, 3]);
1052 /// assert_eq!(values.len(), 3);
1053 ///
1054 /// let empty = MultiValues::Unset(DataType::String);
1055 /// assert_eq!(empty.len(), 0);
1056 /// ```
1057 #[inline(always)]
1058 #[must_use]
1059 pub fn len(&self) -> usize {
1060 for_each_value_type!(multi_values_count_match, self)
1061 }
1062
1063 /// Tests whether this collection contains no values.
1064 ///
1065 /// An unset collection and a concrete empty vector both have length zero.
1066 /// Use [`MultiValues::is_unset`] when the distinction between no collection
1067 /// and a concrete empty collection matters.
1068 ///
1069 /// # Returns
1070 ///
1071 /// `true` when [`Self::len`] is zero; otherwise, `false`.
1072 #[inline(always)]
1073 #[must_use]
1074 pub fn is_empty(&self) -> bool {
1075 self.len() == 0
1076 }
1077
1078 /// Tests whether this container has no concrete vector.
1079 ///
1080 /// # Returns
1081 ///
1082 /// Returns `true` only for [`MultiValues::Unset`]. A concrete empty vector
1083 /// returns `false`.
1084 ///
1085 /// # Examples
1086 ///
1087 /// ```rust
1088 /// use qubit_datatype::DataType;
1089 /// use qubit_value::MultiValues;
1090 ///
1091 /// let values = MultiValues::Int32(vec![]);
1092 /// assert!(!values.is_unset());
1093 ///
1094 /// let empty = MultiValues::Unset(DataType::String);
1095 /// assert!(empty.is_unset());
1096 /// ```
1097 #[inline(always)]
1098 #[must_use]
1099 pub fn is_unset(&self) -> bool {
1100 matches!(self.repr, MultiValuesRepr::Unset(_))
1101 }
1102
1103 /// Tests whether a concrete collection belongs to the numeric type family.
1104 ///
1105 /// A concrete empty numeric vector returns `true`; an unset collection
1106 /// returns `false`, even when its declared type is numeric.
1107 ///
1108 /// # Returns
1109 ///
1110 /// `true` for concrete collections with a numeric element type.
1111 #[inline]
1112 #[must_use]
1113 pub fn is_numeric(&self) -> bool {
1114 !self.is_unset() && self.data_type().is_numeric()
1115 }
1116
1117 /// Converts the first element to a single [`Value`].
1118 ///
1119 /// Returns `Value::Unset` with the same declared type when no element is
1120 /// stored.
1121 ///
1122 /// # Returns
1123 ///
1124 /// A cloned first item, or a typed unset value when no item exists.
1125 #[inline(always)]
1126 pub fn first_value(&self) -> Value {
1127 for_each_value_type!(multi_values_first_value_match, self)
1128 }
1129
1130 /// Consumes this collection and returns its first item as a [`Value`].
1131 ///
1132 /// Empty and unset collections become [`Value::Unset`] with the same data
1133 /// type. Owned element storage is moved instead of cloned.
1134 ///
1135 /// # Returns
1136 ///
1137 /// The owned first item, or a typed unset value when no item exists.
1138 pub fn into_first_value(self) -> Value {
1139 for_each_value_type!(multi_values_into_first_value_match, self)
1140 }
1141
1142 /// Generic setter method
1143 ///
1144 /// Replaces the entire list with the converted input values.
1145 ///
1146 /// This operation updates the stored type to the input element type and
1147 /// does not validate runtime compatibility with the previous variant.
1148 ///
1149 /// Supports any input that can be converted into [`MultiValues`], including
1150 /// single values, vectors, slices, arrays, and borrowed vectors for
1151 /// supported element types.
1152 ///
1153 /// Existing values are replaced, and the stored type becomes the converted
1154 /// input type.
1155 ///
1156 /// # Type Parameters
1157 ///
1158 /// * `S` - Input type convertible into [`MultiValues`].
1159 ///
1160 /// # Parameters
1161 ///
1162 /// * `values` - The values to set.
1163 ///
1164 /// # Compile-time restriction
1165 ///
1166 /// Unsupported input types fail to compile because they do not implement
1167 /// `Into<MultiValues>`.
1168 ///
1169 /// # Examples
1170 ///
1171 /// ```rust
1172 /// use qubit_datatype::DataType;
1173 /// use qubit_value::MultiValues;
1174 ///
1175 /// // 1) Vec<T>
1176 /// let mut mv = MultiValues::Unset(DataType::Int32);
1177 /// mv.set(vec![42, 100, 200]);
1178 /// assert_eq!(mv.get_int32s().unwrap(), &[42, 100, 200]);
1179 ///
1180 /// // 2) &[T]
1181 /// let mut mv = MultiValues::Unset(DataType::Int32);
1182 /// let slice = &[7, 8, 9][..];
1183 /// mv.set(slice);
1184 /// assert_eq!(mv.get_int32s().unwrap(), &[7, 8, 9]);
1185 ///
1186 /// // 3) Single T
1187 /// let mut mv = MultiValues::Unset(DataType::Int32);
1188 /// mv.set(42);
1189 /// assert_eq!(mv.get_int32s().unwrap(), &[42]);
1190 ///
1191 /// // String example
1192 /// let mut mv = MultiValues::Unset(DataType::String);
1193 /// mv.set(vec!["hello".to_string(), "world".to_string()]);
1194 /// assert_eq!(mv.get_strings().unwrap(), &["hello", "world"]);
1195 /// ```
1196 #[inline(always)]
1197 pub fn set<S>(&mut self, values: S)
1198 where
1199 S: Into<Self>,
1200 {
1201 *self = values.into();
1202 }
1203
1204 /// Generic add method
1205 ///
1206 /// Appends converted input values to the existing list with strict type
1207 /// checking.
1208 ///
1209 /// Supports any input that can be converted into [`MultiValues`], including
1210 /// single values, vectors, slices, arrays, and borrowed vectors for
1211 /// supported element types.
1212 ///
1213 /// The converted input must have the same data type as the current
1214 /// container. An empty container keeps its declared type until
1215 /// non-empty values of the same type are appended.
1216 ///
1217 /// # Type Parameters
1218 ///
1219 /// * `S` - Input type convertible into [`MultiValues`].
1220 ///
1221 /// # Parameters
1222 ///
1223 /// * `values` - Values to append.
1224 ///
1225 /// # Returns
1226 ///
1227 /// `Ok(())` after appending, including when the input is empty.
1228 ///
1229 /// # Errors
1230 ///
1231 /// Returns [`ValueError::TypeMismatch`] when the converted input data type
1232 /// differs from the current container data type.
1233 ///
1234 /// # Examples
1235 ///
1236 /// ```rust
1237 /// use qubit_datatype::DataType;
1238 /// use qubit_value::MultiValues;
1239 ///
1240 /// // 1) Single T
1241 /// let mut mv = MultiValues::Int32(vec![42]);
1242 /// mv.add(100).unwrap();
1243 /// assert_eq!(mv.get_int32s().unwrap(), &[42, 100]);
1244 ///
1245 /// // 2) Vec<T>
1246 /// mv.add(vec![200, 300]).unwrap();
1247 /// assert_eq!(mv.get_int32s().unwrap(), &[42, 100, 200, 300]);
1248 ///
1249 /// // 3) &[T]
1250 /// let slice = &[400, 500][..];
1251 /// mv.add(slice).unwrap();
1252 /// assert_eq!(mv.get_int32s().unwrap(), &[42, 100, 200, 300, 400, 500]);
1253 /// ```
1254 pub fn add<S>(&mut self, values: S) -> ValueResult<()>
1255 where
1256 S: Into<Self>,
1257 {
1258 let mut other = values.into();
1259 if self.data_type() != other.data_type() {
1260 return Err(ValueError::TypeMismatch {
1261 expected: self.data_type(),
1262 actual: other.data_type(),
1263 });
1264 }
1265 if other.is_empty() {
1266 return Ok(());
1267 }
1268
1269 for_each_value_type!(multi_values_append_match, self, other);
1270
1271 Ok(())
1272 }
1273
1274 /// Set the data type
1275 ///
1276 /// If the new type differs from the current type, clears all values and
1277 /// sets the new type.
1278 ///
1279 /// # Parameters
1280 ///
1281 /// * `data_type` - The data type to set
1282 ///
1283 /// # Examples
1284 ///
1285 /// ```rust
1286 /// use qubit_datatype::DataType;
1287 /// use qubit_value::MultiValues;
1288 ///
1289 /// let mut values = MultiValues::Int32(vec![1, 2, 3]);
1290 /// values.set_type(DataType::String);
1291 /// assert!(values.is_unset());
1292 /// assert_eq!(values.data_type(), DataType::String);
1293 /// ```
1294 #[inline]
1295 pub fn set_type(&mut self, data_type: DataType) {
1296 if self.data_type() != data_type {
1297 *self = MultiValues::new_unset(data_type);
1298 }
1299 }
1300
1301 /// Appends all values from another container with the same data type.
1302 ///
1303 /// # Parameters
1304 ///
1305 /// * `other` - Collection whose values are cloned and appended.
1306 ///
1307 /// # Returns
1308 ///
1309 /// `Ok(())` after appending, including when `other` is empty.
1310 ///
1311 /// # Errors
1312 ///
1313 /// Returns [`ValueError::TypeMismatch`] when `other` has a different data
1314 /// type.
1315 pub fn merge(&mut self, other: &MultiValues) -> ValueResult<()> {
1316 if self.data_type() != other.data_type() {
1317 return Err(ValueError::TypeMismatch {
1318 expected: self.data_type(),
1319 actual: other.data_type(),
1320 });
1321 }
1322 if other.is_empty() {
1323 return Ok(());
1324 }
1325 for_each_value_type!(multi_values_merge_match, self, other);
1326 Ok(())
1327 }
1328
1329 /// Removes the concrete vector while preserving its declared data type.
1330 #[inline]
1331 pub fn unset(&mut self) {
1332 *self = MultiValues::new_unset(self.data_type());
1333 }
1334
1335 /// Clears all values while preserving a concrete collection and its type.
1336 /// An unset collection remains unset because it has no concrete vector to
1337 /// clear.
1338 ///
1339 /// # Examples
1340 ///
1341 /// ```rust
1342 /// use qubit_datatype::DataType;
1343 /// use qubit_value::MultiValues;
1344 ///
1345 /// let mut values = MultiValues::Int32(vec![1, 2, 3]);
1346 /// values.clear();
1347 /// assert_eq!(values.len(), 0);
1348 /// assert_eq!(values.data_type(), DataType::Int32);
1349 /// ```
1350 #[inline]
1351 pub fn clear(&mut self) {
1352 for_each_value_type!(multi_values_clear_match, self)
1353 }
1354}
1355
1356impl From<Value> for MultiValues {
1357 /// Moves a scalar payload into a one-item collection, preserving its type.
1358 ///
1359 /// An unset scalar becomes an unset collection with the same declared type.
1360 ///
1361 /// # Parameters
1362 ///
1363 /// * `value` - Scalar whose owned storage is transferred to the collection.
1364 ///
1365 /// # Returns
1366 ///
1367 /// A one-item collection, or a typed unset collection for an unset scalar.
1368 fn from(value: Value) -> Self {
1369 for_each_value_type!(value_into_multi_values_match, value)
1370 }
1371}
1372
1373/// Converts the first collection element with a standalone policy and limits.
1374#[cfg(feature = "converter")]
1375macro_rules! multi_values_convert_first_match {
1376 ($value:expr, $policy:expr, $limits:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
1377 match &$value.repr {
1378 MultiValuesRepr::Unset(from) => {
1379 Err(DataConversionError::missing(*from, T::DATA_TYPE).into())
1380 }
1381 $(
1382 $(#[$cfg])*
1383 MultiValuesRepr::$variant(values) => {
1384 convert_first_with(DataConverters::from(values), $policy, $limits)
1385 }
1386 )+
1387 }
1388 };
1389}
1390
1391/// Converts every collection element with a standalone policy and limits.
1392#[cfg(feature = "converter")]
1393macro_rules! multi_values_convert_list_match {
1394 ($value:expr, $policy:expr, $limits:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
1395 match &$value.repr {
1396 MultiValuesRepr::Unset(from) => {
1397 Err(DataConversionError::missing(*from, T::DATA_TYPE).into())
1398 }
1399 $(
1400 $(#[$cfg])*
1401 MultiValuesRepr::$variant(values) => {
1402 convert_values_with(DataConverters::from(values), $policy, $limits)
1403 }
1404 )+
1405 }
1406 };
1407}
1408
1409/// Converts the first collection element through a caller-owned session.
1410#[cfg(feature = "converter")]
1411macro_rules! multi_values_convert_first_in_match {
1412 ($value:expr, $session:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
1413 match &$value.repr {
1414 MultiValuesRepr::Unset(from) => {
1415 Err(DataConversionError::missing(*from, T::DATA_TYPE).into())
1416 }
1417 $(
1418 $(#[$cfg])*
1419 MultiValuesRepr::$variant(values) => {
1420 DataConverters::from(values)
1421 .to_first_in($session)
1422 .map_err(ValueError::from)
1423 }
1424 )+
1425 }
1426 };
1427}
1428
1429/// Converts every collection element through a caller-owned session.
1430#[cfg(feature = "converter")]
1431macro_rules! multi_values_convert_list_in_match {
1432 ($value:expr, $session:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
1433 match &$value.repr {
1434 MultiValuesRepr::Unset(from) => {
1435 Err(DataConversionError::missing(*from, T::DATA_TYPE).into())
1436 }
1437 $(
1438 $(#[$cfg])*
1439 MultiValuesRepr::$variant(values) => {
1440 DataConverters::from(values)
1441 .to_vec_in($session)
1442 .map_err(ValueError::from)
1443 }
1444 )+
1445 }
1446 };
1447}
1448
1449// ============================================================================
1450// Inherent conversion APIs
1451// ============================================================================
1452
1453/// Converts the first item from a batch converter using conversion policy and
1454/// limits.
1455///
1456/// # Type Parameters
1457///
1458/// * `T` - Target type.
1459/// * `I` - Iterator type wrapped by `DataConverters`.
1460///
1461/// # Parameters
1462///
1463/// * `values` - Batch converter containing source values.
1464/// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1465/// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1466///
1467/// # Returns
1468///
1469/// Returns the converted first value.
1470///
1471/// # Errors
1472///
1473/// Returns the mapped single-value conversion error for an empty source or an
1474/// invalid first source value.
1475#[inline(always)]
1476#[cfg(feature = "converter")]
1477fn convert_first_with<'a, T, I>(
1478 values: DataConverters<I>,
1479 policy: &ConversionPolicy,
1480 limits: &ConversionLimits,
1481) -> ValueResult<T>
1482where
1483 T: DataConversionTarget,
1484 I: Iterator,
1485 I::Item: Into<DataConverter<'a>>,
1486{
1487 values
1488 .to_first_with(policy, limits)
1489 .map_err(ValueError::from)
1490}
1491
1492/// Converts every item from a batch converter using conversion policy and
1493/// limits.
1494///
1495/// # Type Parameters
1496///
1497/// * `T` - Target element type.
1498/// * `I` - Iterator type wrapped by `DataConverters`.
1499///
1500/// # Parameters
1501///
1502/// * `values` - Batch converter containing source values.
1503/// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1504/// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1505///
1506/// # Returns
1507///
1508/// Returns converted values in the original order.
1509///
1510/// # Errors
1511///
1512/// Returns a mapped batch conversion error containing the failing source index.
1513#[inline(always)]
1514#[cfg(feature = "converter")]
1515fn convert_values_with<'a, T, I>(
1516 values: DataConverters<I>,
1517 policy: &ConversionPolicy,
1518 limits: &ConversionLimits,
1519) -> ValueResult<Vec<T>>
1520where
1521 T: DataConversionTarget,
1522 I: Iterator,
1523 I::Item: Into<DataConverter<'a>>,
1524{
1525 values.to_vec_with(policy, limits).map_err(ValueError::from)
1526}
1527
1528#[cfg(feature = "converter")]
1529impl MultiValues {
1530 /// Converts the first stored value to `T`.
1531 ///
1532 /// Unlike [`Self::get_first`], this method uses shared `DataConverter`
1533 /// conversion rules instead of strict type matching. For example, a stored
1534 /// `String("1")` can be converted to `bool`.
1535 ///
1536 /// # Type Parameters
1537 ///
1538 /// * `T` - Target type.
1539 ///
1540 /// # Returns
1541 ///
1542 /// The converted first value.
1543 ///
1544 /// # Errors
1545 ///
1546 /// Returns a structured missing-value conversion error when the container
1547 /// is unset, an empty-collection error for a concrete empty vector, or a
1548 /// conversion error when the first value cannot be converted to `T`.
1549 #[inline(always)]
1550 pub fn to_first<T>(&self) -> ValueResult<T>
1551 where
1552 T: DataConversionTarget,
1553 {
1554 self.to_first_with(
1555 ConversionPolicy::default_ref(),
1556 ConversionLimits::default_ref(),
1557 )
1558 }
1559
1560 /// Converts the first stored value to `T`, or returns `default` when the
1561 /// collection is unset.
1562 ///
1563 /// An unset collection can use the default. A concrete empty collection
1564 /// and a policy-missing collection item (including the first item) remain
1565 /// errors and do not use the default; ordinary conversion errors are also
1566 /// preserved.
1567 ///
1568 /// # Type Parameters
1569 ///
1570 /// * `T` - Target type.
1571 ///
1572 /// # Parameters
1573 ///
1574 /// * `default` - Value returned for unset storage. Errors from concrete
1575 /// collection items are returned.
1576 ///
1577 /// # Returns
1578 ///
1579 /// The converted first value, or `default` for an unset collection.
1580 ///
1581 /// # Errors
1582 ///
1583 /// Returns an empty-collection error for a concrete empty vector, a
1584 /// policy-missing first-item error, or another conversion error when the
1585 /// first value cannot be converted to `T`.
1586 #[inline]
1587 pub fn to_first_or<T>(&self, default: impl IntoValueDefault<T>) -> ValueResult<T>
1588 where
1589 T: DataConversionTarget,
1590 {
1591 match self.to_first() {
1592 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
1593 Ok(default.into_value_default())
1594 }
1595 result => result,
1596 }
1597 }
1598
1599 /// Converts the first value or calls `default` when the collection is
1600 /// unset.
1601 ///
1602 /// # Type Parameters
1603 ///
1604 /// * `T` - Target conversion type.
1605 /// * `F` - Deferred fallback producing `T`.
1606 ///
1607 /// # Parameters
1608 ///
1609 /// * `default` - Callback invoked only for unset storage.
1610 ///
1611 /// # Returns
1612 ///
1613 /// The converted first item or the callback result for an unset
1614 /// collection.
1615 ///
1616 /// # Errors
1617 ///
1618 /// Returns an empty-collection error or a conversion error for a concrete
1619 /// value that cannot be converted to `T`. A policy-missing item, including
1620 /// item zero, remains an error and does not invoke the callback.
1621 #[inline]
1622 pub fn to_first_or_else<T, F>(&self, default: F) -> ValueResult<T>
1623 where
1624 T: DataConversionTarget,
1625 F: FnOnce() -> T,
1626 {
1627 match self.to_first() {
1628 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
1629 Ok(default())
1630 }
1631 result => result,
1632 }
1633 }
1634
1635 /// Converts the first stored value to `T` using conversion policy and
1636 /// limits.
1637 ///
1638 /// Stored strings are collection items and are never split again by scalar
1639 /// string collection policy.
1640 ///
1641 /// # Type Parameters
1642 ///
1643 /// * `T` - Target type.
1644 ///
1645 /// # Parameters
1646 ///
1647 /// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1648 /// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1649 ///
1650 /// # Returns
1651 ///
1652 /// The converted first value.
1653 ///
1654 /// # Errors
1655 ///
1656 /// Returns a structured missing-value conversion error when the container
1657 /// is unset, an empty-collection error for a concrete empty vector, or a
1658 /// conversion error when the first value cannot be converted to `T`.
1659 pub fn to_first_with<T>(
1660 &self,
1661 policy: &ConversionPolicy,
1662 limits: &ConversionLimits,
1663 ) -> ValueResult<T>
1664 where
1665 T: DataConversionTarget,
1666 {
1667 for_each_value_type!(multi_values_convert_first_match, self, policy, limits)
1668 .map_err(|error| self.contextual_conversion_error(error, true))
1669 }
1670
1671 /// Converts the first stored value using an existing conversion session.
1672 ///
1673 /// # Type Parameters
1674 ///
1675 /// * `T` - Target element type supported by the shared conversion layer.
1676 ///
1677 /// # Parameters
1678 ///
1679 /// * `session` - Caller-owned session providing policy, limits, and budget.
1680 ///
1681 /// # Returns
1682 ///
1683 /// The converted first element.
1684 ///
1685 /// # Errors
1686 ///
1687 /// Returns a structured missing, conversion, or budget error when the
1688 /// first element cannot be produced as `T`.
1689 pub fn to_first_in<T>(&self, session: &mut ConversionSession<'_>) -> ValueResult<T>
1690 where
1691 T: DataConversionTarget,
1692 {
1693 for_each_value_type!(multi_values_convert_first_in_match, self, session)
1694 .map_err(|error| self.contextual_conversion_error(error, true))
1695 }
1696
1697 /// Converts the first stored value to `T` using conversion policy and
1698 /// limits, or returns `default` when the collection is unset.
1699 ///
1700 /// # Type Parameters
1701 ///
1702 /// * `T` - Target conversion type.
1703 ///
1704 /// # Parameters
1705 ///
1706 /// * `default` - Value used only when storage is unset.
1707 /// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1708 /// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1709 ///
1710 /// # Returns
1711 ///
1712 /// The converted first item, or `default` for an unset collection.
1713 ///
1714 /// # Errors
1715 ///
1716 /// Returns an empty-collection error, a policy-missing error at item zero,
1717 /// or an ordinary conversion error for concrete values that cannot be
1718 /// converted under the provided policy and limits. These errors do not
1719 /// invoke the fallback.
1720 ///
1721 /// # Examples
1722 ///
1723 /// ```rust
1724 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1725 /// use qubit_datatype::{ConversionLimits, ConversionPolicy, DataType};
1726 /// use qubit_value::MultiValues;
1727 ///
1728 /// let policy = ConversionPolicy::env_friendly();
1729 /// let limits = ConversionLimits::default();
1730 /// let unset = MultiValues::new_unset(DataType::String);
1731 /// assert_eq!(unset.to_first_or_with::<u16>(8080, &policy, &limits)?, 8080);
1732 ///
1733 /// let concrete = MultiValues::new([""]);
1734 /// assert!(concrete.to_first_or_with::<u16>(8080, &policy, &limits).is_err());
1735 /// # Ok(())
1736 /// # }
1737 /// ```
1738 #[inline]
1739 pub fn to_first_or_with<T>(
1740 &self,
1741 default: impl IntoValueDefault<T>,
1742 policy: &ConversionPolicy,
1743 limits: &ConversionLimits,
1744 ) -> ValueResult<T>
1745 where
1746 T: DataConversionTarget,
1747 {
1748 match self.to_first_with(policy, limits) {
1749 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
1750 Ok(default.into_value_default())
1751 }
1752 result => result,
1753 }
1754 }
1755
1756 /// Converts the first value with the provided policy and limits, or calls
1757 /// `default` when the collection is unset.
1758 ///
1759 /// # Type Parameters
1760 ///
1761 /// * `T` - Target conversion type.
1762 /// * `F` - Deferred fallback producing `T`.
1763 ///
1764 /// # Parameters
1765 ///
1766 /// * `default` - Callback invoked only for unset storage.
1767 /// * `policy` - Conversion policy forwarded to the shared converter.
1768 /// * `limits` - Conversion limits forwarded to the shared converter.
1769 ///
1770 /// # Returns
1771 ///
1772 /// The converted first item or the callback result for an unset
1773 /// collection.
1774 ///
1775 /// # Errors
1776 ///
1777 /// Returns an empty-collection error or a conversion error for concrete
1778 /// values. A policy-missing collection item, including item zero, remains
1779 /// an error and does not invoke the callback.
1780 #[inline]
1781 pub fn to_first_or_else_with<T, F>(
1782 &self,
1783 default: F,
1784 policy: &ConversionPolicy,
1785 limits: &ConversionLimits,
1786 ) -> ValueResult<T>
1787 where
1788 T: DataConversionTarget,
1789 F: FnOnce() -> T,
1790 {
1791 match self.to_first_with(policy, limits) {
1792 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
1793 Ok(default())
1794 }
1795 result => result,
1796 }
1797 }
1798
1799 /// Converts all stored values to `T`.
1800 ///
1801 /// Unlike [`Self::get`], this method uses shared `DataConverter` conversion
1802 /// rules for every element instead of strict type matching. A concrete
1803 /// empty vector returns an empty vector; an unset container reports a
1804 /// missing-value conversion error.
1805 ///
1806 /// # Type Parameters
1807 ///
1808 /// * `T` - Target element type.
1809 ///
1810 /// # Returns
1811 ///
1812 /// A vector containing all converted values in the original order.
1813 ///
1814 /// # Errors
1815 ///
1816 /// Returns the first conversion error encountered while converting an
1817 /// element.
1818 #[inline]
1819 pub fn to_list<T>(&self) -> ValueResult<Vec<T>>
1820 where
1821 T: DataConversionTarget,
1822 {
1823 self.to_list_with(
1824 ConversionPolicy::default_ref(),
1825 ConversionLimits::default_ref(),
1826 )
1827 }
1828
1829 /// Converts all stored values to `T`, or returns `default` when the
1830 /// collection is unset.
1831 ///
1832 /// # Type Parameters
1833 ///
1834 /// * `T` - Target element type.
1835 ///
1836 /// # Parameters
1837 ///
1838 /// * `default` - List used only when storage is unset.
1839 ///
1840 /// # Returns
1841 ///
1842 /// All converted items, or `default` for an unset collection. A concrete
1843 /// empty collection produces an empty vector; a policy-missing item or an
1844 /// ordinary conversion error never uses the default.
1845 ///
1846 /// # Errors
1847 ///
1848 /// Returns the first indexed item-conversion error for concrete storage.
1849 /// A policy-missing collection item is preserved and does not use the
1850 /// fallback.
1851 #[inline]
1852 pub fn to_list_or<T>(&self, default: impl IntoValueDefault<Vec<T>>) -> ValueResult<Vec<T>>
1853 where
1854 T: DataConversionTarget,
1855 {
1856 match self.to_list() {
1857 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
1858 Ok(default.into_value_default())
1859 }
1860 result => result,
1861 }
1862 }
1863
1864 /// Converts all values or calls `default` when the collection is unset.
1865 ///
1866 /// # Type Parameters
1867 ///
1868 /// * `T` - Target element conversion type.
1869 /// * `F` - Deferred fallback producing the complete list.
1870 ///
1871 /// # Parameters
1872 ///
1873 /// * `default` - Callback invoked only for unset storage.
1874 ///
1875 /// # Returns
1876 ///
1877 /// The converted list or the callback result for an unset collection.
1878 ///
1879 /// # Errors
1880 ///
1881 /// Returns the first indexed item-conversion error for concrete storage
1882 /// without invoking the callback.
1883 #[inline]
1884 pub fn to_list_or_else<T, F>(&self, default: F) -> ValueResult<Vec<T>>
1885 where
1886 T: DataConversionTarget,
1887 F: FnOnce() -> Vec<T>,
1888 {
1889 match self.to_list() {
1890 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
1891 Ok(default())
1892 }
1893 result => result,
1894 }
1895 }
1896
1897 /// Converts all stored values to `T` using conversion policy and limits.
1898 ///
1899 /// Stored strings are collection items and are never split again by scalar
1900 /// string collection policy.
1901 ///
1902 /// # Type Parameters
1903 ///
1904 /// * `T` - Target element type.
1905 ///
1906 /// # Parameters
1907 ///
1908 /// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1909 /// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1910 ///
1911 /// # Returns
1912 ///
1913 /// A vector containing all converted values in the original order.
1914 ///
1915 /// # Errors
1916 ///
1917 /// Returns the first conversion or budget error encountered while
1918 /// converting an element. A policy-missing item returns
1919 /// [`ValueError::Missing`]; its source index is retained by
1920 /// [`crate::ValueMissing::source_index`]. Other element conversion failures
1921 /// can return [`ValueError::ListConversion`].
1922 pub fn to_list_with<T>(
1923 &self,
1924 policy: &ConversionPolicy,
1925 limits: &ConversionLimits,
1926 ) -> ValueResult<Vec<T>>
1927 where
1928 T: DataConversionTarget,
1929 {
1930 for_each_value_type!(multi_values_convert_list_match, self, policy, limits)
1931 .map_err(|error| self.contextual_conversion_error(error, false))
1932 }
1933
1934 /// Converts every stored value using an existing conversion session.
1935 ///
1936 /// # Type Parameters
1937 ///
1938 /// * `T` - Target element type supported by the shared conversion layer.
1939 ///
1940 /// # Parameters
1941 ///
1942 /// * `session` - Caller-owned session providing policy, limits, and budget.
1943 ///
1944 /// # Returns
1945 ///
1946 /// Converted elements in their original order.
1947 ///
1948 /// # Errors
1949 ///
1950 /// Returns the first structured missing, conversion, or budget error.
1951 pub fn to_list_in<T>(&self, session: &mut ConversionSession<'_>) -> ValueResult<Vec<T>>
1952 where
1953 T: DataConversionTarget,
1954 {
1955 for_each_value_type!(multi_values_convert_list_in_match, self, session)
1956 .map_err(|error| self.contextual_conversion_error(error, false))
1957 }
1958
1959 /// Converts all stored values to `T` using conversion policy and limits,
1960 /// or returns `default` when the collection is unset.
1961 ///
1962 /// # Type Parameters
1963 ///
1964 /// * `T` - Target element type.
1965 ///
1966 /// # Parameters
1967 ///
1968 /// * `default` - List used only when storage is unset.
1969 /// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1970 /// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1971 ///
1972 /// # Returns
1973 ///
1974 /// All converted items, or `default` for an unset collection. A concrete
1975 /// empty collection produces an empty vector; a missing collection item
1976 /// or ordinary conversion error never uses the default.
1977 ///
1978 /// # Errors
1979 ///
1980 /// Returns the first indexed item-conversion error for concrete storage.
1981 /// Missing collection items and ordinary conversion errors are preserved.
1982 #[inline]
1983 pub fn to_list_or_with<T>(
1984 &self,
1985 default: impl IntoValueDefault<Vec<T>>,
1986 policy: &ConversionPolicy,
1987 limits: &ConversionLimits,
1988 ) -> ValueResult<Vec<T>>
1989 where
1990 T: DataConversionTarget,
1991 {
1992 match self.to_list_with(policy, limits) {
1993 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
1994 Ok(default.into_value_default())
1995 }
1996 result => result,
1997 }
1998 }
1999
2000 /// Converts all values with the provided policy and limits, or calls
2001 /// `default` when the collection is unset.
2002 ///
2003 /// # Type Parameters
2004 ///
2005 /// * `T` - Target element conversion type.
2006 /// * `F` - Deferred fallback producing the complete list.
2007 ///
2008 /// # Parameters
2009 ///
2010 /// * `default` - Callback invoked only for unset storage.
2011 /// * `policy` - Conversion policy forwarded to the shared converter.
2012 /// * `limits` - Conversion limits forwarded to the shared converter.
2013 ///
2014 /// # Returns
2015 ///
2016 /// The converted list or the callback result for an unset collection.
2017 ///
2018 /// # Errors
2019 ///
2020 /// Returns the first indexed policy-missing item or ordinary conversion
2021 /// error for concrete storage without invoking the callback.
2022 #[inline]
2023 pub fn to_list_or_else_with<T, F>(
2024 &self,
2025 default: F,
2026 policy: &ConversionPolicy,
2027 limits: &ConversionLimits,
2028 ) -> ValueResult<Vec<T>>
2029 where
2030 T: DataConversionTarget,
2031 F: FnOnce() -> Vec<T>,
2032 {
2033 match self.to_list_with(policy, limits) {
2034 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
2035 Ok(default())
2036 }
2037 result => result,
2038 }
2039 }
2040
2041 /// Enriches only missing failures after conversion, retaining
2042 /// resource-error priority.
2043 ///
2044 /// # Parameters
2045 ///
2046 /// * `error` - Conversion failure to enrich only when it denotes a missing
2047 /// value.
2048 /// * `first` - Whether to attach the first-item index to missing-value
2049 /// context.
2050 ///
2051 /// # Returns
2052 ///
2053 /// The missing failure with storage context, or the original non-missing
2054 /// failure.
2055 fn contextual_conversion_error(&self, error: ValueError, first: bool) -> ValueError {
2056 let ValueError::Missing(missing) = error else {
2057 return error;
2058 };
2059 let reason = if self.is_unset() {
2060 crate::ValueMissingReason::UnsetCollection
2061 } else if self.is_empty() {
2062 crate::ValueMissingReason::EmptyCollection
2063 } else {
2064 crate::ValueMissingReason::Conversion
2065 };
2066 let missing = missing.with_storage(self.data_type(), reason);
2067 ValueError::Missing(if first {
2068 missing.with_first_index()
2069 } else {
2070 missing
2071 })
2072 }
2073}
2074
2075impl MultiValues {
2076 // ========================================================================
2077 // Get first value (as single value access)
2078 // ========================================================================
2079
2080 impl_get_first_value! {
2081 /// Get the first boolean value.
2082 ///
2083 /// # Returns
2084 ///
2085 /// If types match and a value exists, returns the first boolean value; see `# Errors`.
2086 ///
2087 /// # Examples
2088 ///
2089 /// ```rust
2090 /// use qubit_value::MultiValues;
2091 ///
2092 /// let values = MultiValues::Bool(vec![true, false]);
2093 /// assert_eq!(values.get_first_bool().unwrap(), true);
2094 /// ```
2095 copy: get_first_bool, Bool, bool, DataType::Bool
2096 }
2097
2098 impl_get_first_value! {
2099 /// Get the first character value
2100 ///
2101 /// # Returns
2102 ///
2103 /// If types match and a value exists, returns the first character value; see `# Errors`.
2104 copy: get_first_char, Char, char, DataType::Char
2105 }
2106
2107 impl_get_first_value! {
2108 /// Get the first int8 value
2109 ///
2110 /// # Returns
2111 ///
2112 /// If types match and a value exists, returns the first int8 value; see `# Errors`.
2113 copy: get_first_int8, Int8, i8, DataType::Int8
2114 }
2115
2116 impl_get_first_value! {
2117 /// Get the first int16 value
2118 ///
2119 /// # Returns
2120 ///
2121 /// If types match and a value exists, returns the first int16 value; see `# Errors`.
2122 copy: get_first_int16, Int16, i16, DataType::Int16
2123 }
2124
2125 impl_get_first_value! {
2126 /// Get the first int32 value
2127 ///
2128 /// # Returns
2129 ///
2130 /// If types match and a value exists, returns the first int32 value; see `# Errors`.
2131 copy: get_first_int32, Int32, i32, DataType::Int32
2132 }
2133
2134 impl_get_first_value! {
2135 /// Get the first int64 value
2136 ///
2137 /// # Returns
2138 ///
2139 /// If types match and a value exists, returns the first int64 value; see `# Errors`.
2140 copy: get_first_int64, Int64, i64, DataType::Int64
2141 }
2142
2143 impl_get_first_value! {
2144 /// Get the first int128 value
2145 ///
2146 /// # Returns
2147 ///
2148 /// If types match and a value exists, returns the first int128 value; see `# Errors`.
2149 copy: get_first_int128, Int128, i128, DataType::Int128
2150 }
2151
2152 impl_get_first_value! {
2153 /// Get the first uint8 value
2154 ///
2155 /// # Returns
2156 ///
2157 /// If types match and a value exists, returns the first uint8 value; see `# Errors`.
2158 copy: get_first_uint8, UInt8, u8, DataType::UInt8
2159 }
2160
2161 impl_get_first_value! {
2162 /// Get the first uint16 value
2163 ///
2164 /// # Returns
2165 ///
2166 /// If types match and a value exists, returns the first uint16 value; see `# Errors`.
2167 copy: get_first_uint16, UInt16, u16, DataType::UInt16
2168 }
2169
2170 impl_get_first_value! {
2171 /// Get the first uint32 value
2172 ///
2173 /// # Returns
2174 ///
2175 /// If types match and a value exists, returns the first uint32 value; see `# Errors`.
2176 copy: get_first_uint32, UInt32, u32, DataType::UInt32
2177 }
2178
2179 impl_get_first_value! {
2180 /// Get the first uint64 value
2181 ///
2182 /// # Returns
2183 ///
2184 /// If types match and a value exists, returns the first uint64 value; see `# Errors`.
2185 copy: get_first_uint64, UInt64, u64, DataType::UInt64
2186 }
2187
2188 impl_get_first_value! {
2189 /// Get the first uint128 value
2190 ///
2191 /// # Returns
2192 ///
2193 /// If types match and a value exists, returns the first uint128 value; see `# Errors`.
2194 copy: get_first_uint128, UInt128, u128, DataType::UInt128
2195 }
2196
2197 impl_get_first_value! {
2198 /// Get the first float32 value
2199 ///
2200 /// # Returns
2201 ///
2202 /// If types match and a value exists, returns the first float32 value; see `# Errors`.
2203 copy: get_first_float32, Float32, f32, DataType::Float32
2204 }
2205
2206 impl_get_first_value! {
2207 /// Get the first float64 value
2208 ///
2209 /// # Returns
2210 ///
2211 /// If types match and a value exists, returns the first float64 value; see `# Errors`.
2212 copy: get_first_float64, Float64, f64, DataType::Float64
2213 }
2214
2215 impl_get_first_value! {
2216 /// Get the first string reference
2217 ///
2218 /// # Returns
2219 ///
2220 /// If types match and a value exists, returns a reference to the first
2221 /// string; see `# Errors`.
2222 ref: get_first_string, String, &str, DataType::String, |s: &String| s.as_str()
2223 }
2224
2225 #[cfg(feature = "chrono")]
2226 impl_get_first_value! {
2227 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2228 /// Get the first date value
2229 ///
2230 /// # Returns
2231 ///
2232 /// If types match and a value exists, returns the first date value; see `# Errors`.
2233 copy: get_first_date, Date, NaiveDate, DataType::Date
2234 }
2235
2236 #[cfg(feature = "chrono")]
2237 impl_get_first_value! {
2238 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2239 /// Get the first time value
2240 ///
2241 /// # Returns
2242 ///
2243 /// If types match and a value exists, returns the first time value; see `# Errors`.
2244 copy: get_first_time, Time, NaiveTime, DataType::Time
2245 }
2246
2247 #[cfg(feature = "chrono")]
2248 impl_get_first_value! {
2249 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2250 /// Get the first datetime value
2251 ///
2252 /// # Returns
2253 ///
2254 /// If types match and a value exists, returns the first datetime value; see `# Errors`.
2255 copy: get_first_datetime, DateTime, NaiveDateTime, DataType::DateTime
2256 }
2257
2258 #[cfg(feature = "chrono")]
2259 impl_get_first_value! {
2260 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2261 /// Get the first UTC instant value
2262 ///
2263 /// # Returns
2264 ///
2265 /// If types match and a value exists, returns the first UTC instant
2266 /// value; see `# Errors`.
2267 copy: get_first_instant, Instant, DateTime<Utc>, DataType::Instant
2268 }
2269
2270 #[cfg(feature = "big-integer")]
2271 impl_get_first_value! {
2272 #[cfg_attr(docsrs, doc(cfg(feature = "big-integer")))]
2273 /// Get the first big integer value
2274 ///
2275 /// # Returns
2276 ///
2277 /// If types match and a value exists, returns the first big integer
2278 /// value; see `# Errors`.
2279 ref: get_first_biginteger, BigInteger, BigInt, DataType::BigInteger, |v: &BigInt| v.clone()
2280 }
2281
2282 #[cfg(feature = "big-decimal")]
2283 impl_get_first_value! {
2284 #[cfg_attr(docsrs, doc(cfg(feature = "big-decimal")))]
2285 /// Get the first big decimal value
2286 ///
2287 /// # Returns
2288 ///
2289 /// If types match and a value exists, returns the first big decimal
2290 /// value; see `# Errors`.
2291 ref: get_first_bigdecimal, BigDecimal, BigDecimal, DataType::BigDecimal, |v: &BigDecimal| v.clone()
2292 }
2293
2294 impl_get_first_value! {
2295 /// Get the first Duration value
2296 ///
2297 /// # Returns
2298 ///
2299 /// The first duration when the stored type matches.
2300 copy: get_first_duration, Duration, Duration, DataType::Duration
2301 }
2302
2303 #[cfg(feature = "url")]
2304 impl_get_first_value! {
2305 #[cfg_attr(docsrs, doc(cfg(feature = "url")))]
2306 /// Get the first Url value
2307 ///
2308 /// # Returns
2309 ///
2310 /// A clone of the first URL when the stored type matches.
2311 ref: get_first_url, Url, Url, DataType::Url, |v: &Url| v.clone()
2312 }
2313
2314 impl_get_first_value! {
2315 /// Get the first StringMap value
2316 ///
2317 /// # Returns
2318 ///
2319 /// A clone of the first string map when the stored type matches.
2320 ref: get_first_string_map, StringMap, HashMap<String, String>, DataType::StringMap, |v: &HashMap<String, String>| v.clone()
2321 }
2322
2323 #[cfg(feature = "json")]
2324 impl_get_first_value! {
2325 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
2326 /// Get the first Json value
2327 ///
2328 /// # Returns
2329 ///
2330 /// A clone of the first JSON value when the stored type matches.
2331 ref: get_first_json, Json, JsonValue, DataType::Json, |v: &JsonValue| v.clone()
2332 }
2333
2334 // ========================================================================
2335 // Get all values (type checking)
2336 // ========================================================================
2337
2338 impl_get_multi_values! {
2339 /// Get reference to all boolean values
2340 ///
2341 /// # Returns
2342 ///
2343 /// If types match, returns a reference to the boolean value array; see `# Errors`.
2344 ///
2345 /// # Examples
2346 ///
2347 /// ```rust
2348 /// use qubit_value::MultiValues;
2349 ///
2350 /// let values = MultiValues::Bool(vec![true, false, true]);
2351 /// assert_eq!(values.get_bools().unwrap(), &[true, false, true]);
2352 /// ```
2353 slice: get_bools, Bool, bool, DataType::Bool
2354 }
2355
2356 impl_get_multi_values! {
2357 /// Get reference to all character values
2358 ///
2359 /// # Returns
2360 ///
2361 /// If types match, returns a reference to the character value array; see `# Errors`.
2362 slice: get_chars, Char, char, DataType::Char
2363 }
2364
2365 impl_get_multi_values! {
2366 /// Get reference to all int8 values
2367 ///
2368 /// # Returns
2369 ///
2370 /// If types match, returns a reference to the int8 value array; see `# Errors`.
2371 slice: get_int8s, Int8, i8, DataType::Int8
2372 }
2373
2374 impl_get_multi_values! {
2375 /// Get reference to all int16 values
2376 ///
2377 /// # Returns
2378 ///
2379 /// If types match, returns a reference to the int16 value array; see `# Errors`.
2380 slice: get_int16s, Int16, i16, DataType::Int16
2381 }
2382
2383 impl_get_multi_values! {
2384 /// Get reference to all int32 values
2385 ///
2386 /// # Returns
2387 ///
2388 /// If types match, returns a reference to the int32 value array; see `# Errors`.
2389 slice: get_int32s, Int32, i32, DataType::Int32
2390 }
2391
2392 impl_get_multi_values! {
2393 /// Get reference to all int64 values
2394 ///
2395 /// # Returns
2396 ///
2397 /// If types match, returns a reference to the int64 value array; see `# Errors`.
2398 slice: get_int64s, Int64, i64, DataType::Int64
2399 }
2400
2401 impl_get_multi_values! {
2402 /// Get reference to all int128 values
2403 ///
2404 /// # Returns
2405 ///
2406 /// If types match, returns a reference to the int128 value array; see `# Errors`.
2407 slice: get_int128s, Int128, i128, DataType::Int128
2408 }
2409
2410 impl_get_multi_values! {
2411 /// Get reference to all uint8 values
2412 ///
2413 /// # Returns
2414 ///
2415 /// If types match, returns a reference to the uint8 value array; see `# Errors`.
2416 slice: get_uint8s, UInt8, u8, DataType::UInt8
2417 }
2418
2419 impl_get_multi_values! {
2420 /// Get reference to all uint16 values
2421 ///
2422 /// # Returns
2423 ///
2424 /// If types match, returns a reference to the uint16 value array; see `# Errors`.
2425 slice: get_uint16s, UInt16, u16, DataType::UInt16
2426 }
2427
2428 impl_get_multi_values! {
2429 /// Get reference to all uint32 values
2430 ///
2431 /// # Returns
2432 ///
2433 /// If types match, returns a reference to the uint32 value array; see `# Errors`.
2434 slice: get_uint32s, UInt32, u32, DataType::UInt32
2435 }
2436
2437 impl_get_multi_values! {
2438 /// Get reference to all uint64 values
2439 ///
2440 /// # Returns
2441 ///
2442 /// If types match, returns a reference to the uint64 value array; see `# Errors`.
2443 slice: get_uint64s, UInt64, u64, DataType::UInt64
2444 }
2445
2446 impl_get_multi_values! {
2447 /// Get reference to all uint128 values
2448 ///
2449 /// # Returns
2450 ///
2451 /// If types match, returns a reference to the uint128 value array; see `# Errors`.
2452 slice: get_uint128s, UInt128, u128, DataType::UInt128
2453 }
2454
2455 impl_get_multi_values! {
2456 /// Get reference to all float32 values
2457 ///
2458 /// # Returns
2459 ///
2460 /// If types match, returns a reference to the float32 value array; see `# Errors`.
2461 slice: get_float32s, Float32, f32, DataType::Float32
2462 }
2463
2464 impl_get_multi_values! {
2465 /// Get reference to all float64 values
2466 ///
2467 /// # Returns
2468 ///
2469 /// If types match, returns a reference to the float64 value array; see `# Errors`.
2470 slice: get_float64s, Float64, f64, DataType::Float64
2471 }
2472
2473 impl_get_multi_values! {
2474 /// Get reference to all strings
2475 ///
2476 /// # Returns
2477 ///
2478 /// If types match, returns a reference to the string array; otherwise
2479 /// returns an error
2480 vec: get_strings, String, String, DataType::String
2481 }
2482
2483 #[cfg(feature = "chrono")]
2484 impl_get_multi_values! {
2485 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2486 /// Get reference to all date values
2487 ///
2488 /// # Returns
2489 ///
2490 /// If types match, returns a reference to the date value array; see `# Errors`.
2491 slice: get_dates, Date, NaiveDate, DataType::Date
2492 }
2493
2494 #[cfg(feature = "chrono")]
2495 impl_get_multi_values! {
2496 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2497 /// Get reference to all time values
2498 ///
2499 /// # Returns
2500 ///
2501 /// If types match, returns a reference to the time value array; see `# Errors`.
2502 slice: get_times, Time, NaiveTime, DataType::Time
2503 }
2504
2505 #[cfg(feature = "chrono")]
2506 impl_get_multi_values! {
2507 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2508 /// Get reference to all datetime values
2509 ///
2510 /// # Returns
2511 ///
2512 /// If types match, returns a reference to the datetime value array; see `# Errors`.
2513 slice: get_datetimes, DateTime, NaiveDateTime, DataType::DateTime
2514 }
2515
2516 #[cfg(feature = "chrono")]
2517 impl_get_multi_values! {
2518 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2519 /// Get reference to all UTC instant values
2520 ///
2521 /// # Returns
2522 ///
2523 /// If types match, returns a reference to the UTC instant value array; see `# Errors`.
2524 slice: get_instants, Instant, DateTime<Utc>, DataType::Instant
2525 }
2526
2527 #[cfg(feature = "big-integer")]
2528 impl_get_multi_values! {
2529 #[cfg_attr(docsrs, doc(cfg(feature = "big-integer")))]
2530 /// Get reference to all big integers
2531 ///
2532 /// # Returns
2533 ///
2534 /// If types match, returns a reference to the big integer array; see `# Errors`.
2535 vec: get_bigintegers, BigInteger, BigInt, DataType::BigInteger
2536 }
2537
2538 #[cfg(feature = "big-decimal")]
2539 impl_get_multi_values! {
2540 #[cfg_attr(docsrs, doc(cfg(feature = "big-decimal")))]
2541 /// Get reference to all big decimals
2542 ///
2543 /// # Returns
2544 ///
2545 /// If types match, returns a reference to the big decimal array; see `# Errors`.
2546 vec: get_bigdecimals, BigDecimal, BigDecimal, DataType::BigDecimal
2547 }
2548
2549 impl_get_multi_values! {
2550 /// Get reference to all Duration values
2551 ///
2552 /// # Returns
2553 ///
2554 /// A slice containing all stored durations.
2555 slice: get_durations, Duration, Duration, DataType::Duration
2556 }
2557
2558 #[cfg(feature = "url")]
2559 impl_get_multi_values! {
2560 #[cfg_attr(docsrs, doc(cfg(feature = "url")))]
2561 /// Get reference to all Url values
2562 ///
2563 /// # Returns
2564 ///
2565 /// A borrowed slice containing all stored URLs. The slice borrows from this
2566 /// collection; no elements are cloned.
2567 vec: get_urls, Url, Url, DataType::Url
2568 }
2569
2570 impl_get_multi_values! {
2571 /// Get reference to all StringMap values
2572 ///
2573 /// # Returns
2574 ///
2575 /// A borrowed slice containing all stored string maps. The slice borrows from
2576 /// this collection; no maps or entries are cloned.
2577 vec: get_string_maps, StringMap, HashMap<String, String>, DataType::StringMap
2578 }
2579
2580 #[cfg(feature = "json")]
2581 impl_get_multi_values! {
2582 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
2583 /// Get reference to all Json values
2584 ///
2585 /// # Returns
2586 ///
2587 /// A borrowed slice containing all stored JSON values. The slice borrows from
2588 /// this collection; no JSON trees are cloned.
2589 vec: get_jsons, Json, JsonValue, DataType::Json
2590 }
2591}