Skip to main content

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            impl TryFrom<&MultiValues> for $type {
41                type Error = ValueError;
42
43                #[inline(always)]
44                fn try_from(values: &MultiValues) -> ValueResult<$type> {
45                    match &values.repr {
46                        MultiValuesRepr::$variant(values) => values
47                            .first()
48                            .map(|value| materialize_stored!($materialization, value))
49                            .ok_or(ValueError::Missing(ValueMissing::empty_collection($data_type, $data_type))),
50                        MultiValuesRepr::Unset(actual) if *actual == $data_type => {
51                            Err(ValueError::Missing(ValueMissing::unset_collection(*actual, *actual)))
52                        }
53                        _ => Err(ValueError::TypeMismatch {
54                            expected: $data_type,
55                            actual: values.data_type(),
56                        }),
57                    }
58                }
59            }
60
61            $(#[$cfg])*
62            impl TryFrom<&MultiValues> for Vec<$type> {
63                type Error = ValueError;
64
65                #[inline(always)]
66                fn try_from(values: &MultiValues) -> ValueResult<Vec<$type>> {
67                    match &values.repr {
68                        MultiValuesRepr::$variant(values) => Ok(values
69                            .iter()
70                            .map(|value| materialize_stored!($materialization, value))
71                            .collect()),
72                        MultiValuesRepr::Unset(actual) if *actual == $data_type => {
73                            Err(ValueError::Missing(ValueMissing::unset_collection(*actual, *actual)))
74                        }
75                        _ => Err(ValueError::TypeMismatch {
76                            expected: $data_type,
77                            actual: values.data_type(),
78                        }),
79                    }
80                }
81            }
82        )+
83    };
84}
85
86for_each_value_type!(impl_multi_values_try_from_table);
87
88/// Implements borrowed and consuming collection reads from the shared table.
89macro_rules! impl_multi_values_borrowed_and_owned_table {
90    (
91        ;
92        $(
93            (
94                [$($cfg:meta),*],
95                $variant:ident,
96                $type:ty,
97                $data_type:expr,
98                $materialization:ident,
99                $json_class:ident,
100                $number_projection:ident,
101                $value_doc:literal,
102                $multi_doc:literal
103                $(, $_wire:tt)*
104            )
105        ),+ $(,)?
106    ) => {
107        $(
108            $(#[$cfg])*
109            impl<'a> TryFrom<&'a MultiValues> for &'a $type {
110                type Error = ValueError;
111
112                #[inline(always)]
113                fn try_from(values: &'a MultiValues) -> ValueResult<Self> {
114                    match &values.repr {
115                        MultiValuesRepr::$variant(values) => values.first().ok_or(
116                            ValueError::Missing(ValueMissing::empty_collection($data_type, $data_type)),
117                        ),
118                        MultiValuesRepr::Unset(actual) if *actual == $data_type => {
119                            Err(ValueError::Missing(ValueMissing::unset_collection(*actual, *actual)))
120                        }
121                        _ => Err(ValueError::TypeMismatch {
122                            expected: $data_type,
123                            actual: values.data_type(),
124                        }),
125                    }
126                }
127            }
128
129            $(#[$cfg])*
130            impl<'a> TryFrom<&'a MultiValues> for &'a [$type] {
131                type Error = ValueError;
132
133                #[inline(always)]
134                fn try_from(values: &'a MultiValues) -> ValueResult<Self> {
135                    match &values.repr {
136                        MultiValuesRepr::$variant(values) => Ok(values.as_slice()),
137                        MultiValuesRepr::Unset(actual) if *actual == $data_type => {
138                            Err(ValueError::Missing(ValueMissing::unset_collection(*actual, *actual)))
139                        }
140                        _ => Err(ValueError::TypeMismatch {
141                            expected: $data_type,
142                            actual: values.data_type(),
143                        }),
144                    }
145                }
146            }
147
148            $(#[$cfg])*
149            impl TryFrom<MultiValues> for Vec<$type> {
150                type Error = ValueError;
151
152                #[inline(always)]
153                fn try_from(values: MultiValues) -> ValueResult<Self> {
154                    match values.repr {
155                        MultiValuesRepr::$variant(values) => Ok(values),
156                        MultiValuesRepr::Unset(actual) if actual == $data_type => {
157                            Err(ValueError::Missing(ValueMissing::unset_collection(actual, actual)))
158                        }
159                        other => {
160                            let actual = MultiValues { repr: other }.data_type();
161                            Err(ValueError::TypeMismatch { expected: $data_type, actual })
162                        }
163                    }
164                }
165            }
166        )+
167    };
168}
169
170for_each_value_type!(impl_multi_values_borrowed_and_owned_table);
171
172impl<'a> TryFrom<&'a MultiValues> for &'a str {
173    type Error = ValueError;
174
175    #[inline(always)]
176    fn try_from(values: &'a MultiValues) -> ValueResult<Self> {
177        match &values.repr {
178            MultiValuesRepr::String(values) => {
179                values
180                    .first()
181                    .map(String::as_str)
182                    .ok_or(ValueError::Missing(ValueMissing::empty_collection(
183                        DataType::String,
184                        DataType::String,
185                    )))
186            }
187            MultiValuesRepr::Unset(actual) if *actual == DataType::String => {
188                Err(ValueError::Missing(ValueMissing::unset_collection(*actual, *actual)))
189            }
190            _ => Err(ValueError::TypeMismatch {
191                expected: DataType::String,
192                actual: values.data_type(),
193            }),
194        }
195    }
196}