Skip to main content

qubit_value/value/
value_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<&Value>` implementations for strict typed reads.
10
11use qubit_datatype::DataType;
12
13use super::ValueRepr;
14use super::value::Value;
15use crate::ValueMissing;
16use crate::value_error::ValueError;
17use crate::value_error::ValueResult;
18
19/// Implements strict borrowed scalar reads from the shared value table.
20macro_rules! impl_value_try_from_table {
21    (
22        ;
23        $(
24            (
25                [$($cfg:meta),*],
26                $variant:ident,
27                $type:ty,
28                $data_type:expr,
29                $materialization:ident,
30                $json_class:ident,
31                $number_projection:ident,
32                $value_doc:literal,
33                $multi_doc:literal
34                $(, $_wire:tt)*
35            )
36        ),+ $(,)?
37    ) => {
38        $(
39            $(#[$cfg])*
40            $(#[cfg_attr(docsrs, doc($cfg))])*
41            impl TryFrom<&Value> for $type {
42                /// Reports an unset value of the requested type or a runtime type mismatch.
43                type Error = ValueError;
44
45                /// Copies or clones the matching payload without changing the container.
46                ///
47                /// # Parameters
48                ///
49                /// - `value` - Container borrowed for the duration of this read.
50                ///
51                /// # Returns
52                ///
53                /// An owned payload; heap-backed payloads are cloned.
54                ///
55                /// # Errors
56                ///
57                /// Returns [`ValueError::Missing`] for an unset value of the requested
58                /// type, or [`ValueError::TypeMismatch`] for any other runtime type.
59                #[inline(always)]
60                fn try_from(value: &Value) -> ValueResult<$type> {
61                    match &value.repr {
62                        ValueRepr::$variant(value) => {
63                            Ok(materialize_value_storage!($variant, $materialization, value))
64                        }
65                        ValueRepr::Unset(actual) if *actual == $data_type => {
66                            Err(ValueError::Missing(ValueMissing::unset_scalar(*actual, *actual)))
67                        }
68                        _ => Err(ValueError::TypeMismatch {
69                            expected: $data_type,
70                            actual: value.data_type(),
71                        }),
72                    }
73                }
74            }
75        )+
76    };
77}
78
79for_each_value_type!(impl_value_try_from_table);
80
81/// Implements zero-copy scalar reads from the shared value table.
82macro_rules! impl_value_borrowed_try_from_table {
83    (
84        ;
85        $(
86            (
87                [$($cfg:meta),*],
88                $variant:ident,
89                $type:ty,
90                $data_type:expr,
91                $materialization:ident,
92                $json_class:ident,
93                $number_projection:ident,
94                $value_doc:literal,
95                $multi_doc:literal
96                $(, $_wire:tt)*
97            )
98        ),+ $(,)?
99    ) => {
100        $(
101            $(#[$cfg])*
102            $(#[cfg_attr(docsrs, doc($cfg))])*
103            impl<'a> TryFrom<&'a Value> for &'a $type {
104                /// Reports an unset value of the requested type or a runtime type mismatch.
105                type Error = ValueError;
106
107                /// Borrows the matching payload without copying or allocating.
108                ///
109                /// # Parameters
110                ///
111                /// - `value` - Container that owns the payload and must outlive the returned reference.
112                ///
113                /// # Returns
114                ///
115                /// A payload reference tied to the lifetime of `value`.
116                ///
117                /// # Errors
118                ///
119                /// Returns [`ValueError::Missing`] for an unset value of the requested
120                /// type, or [`ValueError::TypeMismatch`] for any other runtime type.
121                #[inline(always)]
122                fn try_from(value: &'a Value) -> ValueResult<Self> {
123                    match &value.repr {
124                        ValueRepr::$variant(value) => Ok(value_storage_ref!($variant, value)),
125                        ValueRepr::Unset(actual) if *actual == $data_type => {
126                            Err(ValueError::Missing(ValueMissing::unset_scalar(*actual, *actual)))
127                        }
128                        _ => Err(ValueError::TypeMismatch {
129                            expected: $data_type,
130                            actual: value.data_type(),
131                        }),
132                    }
133                }
134            }
135
136            $(#[$cfg])*
137            $(#[cfg_attr(docsrs, doc($cfg))])*
138            impl TryFrom<Value> for $type {
139                /// Reports an unset value of the requested type or a runtime type mismatch.
140                type Error = ValueError;
141
142                /// Consumes the container and moves out its matching payload without cloning.
143                ///
144                /// # Parameters
145                ///
146                /// - `value` - Container consumed even when its runtime type does not match.
147                ///
148                /// # Returns
149                ///
150                /// The owned payload moved from the container.
151                ///
152                /// # Errors
153                ///
154                /// Returns [`ValueError::Missing`] for an unset value of the requested
155                /// type, or [`ValueError::TypeMismatch`] for any other runtime type.
156                #[inline(always)]
157                fn try_from(value: Value) -> ValueResult<Self> {
158                    match value.repr {
159                        ValueRepr::$variant(value) => Ok(move_value_storage!($variant, value)),
160                        ValueRepr::Unset(actual) if actual == $data_type => {
161                            Err(ValueError::Missing(ValueMissing::unset_scalar(actual, actual)))
162                        }
163                        other => Err(ValueError::TypeMismatch {
164                            expected: $data_type,
165                            actual: Value { repr: other }.data_type(),
166                        }),
167                    }
168                }
169            }
170        )+
171    };
172}
173
174for_each_value_type!(impl_value_borrowed_try_from_table);
175
176impl<'a> TryFrom<&'a Value> for &'a str {
177    /// Reports an unset string value or a runtime type mismatch.
178    type Error = ValueError;
179
180    /// Borrows the stored string as a slice without copying or allocating.
181    ///
182    /// # Parameters
183    ///
184    /// - `value` - Container that owns the string and must outlive the returned
185    ///   slice.
186    ///
187    /// # Returns
188    ///
189    /// A string slice tied to the lifetime of `value`.
190    ///
191    /// # Errors
192    ///
193    /// Returns [`ValueError::Missing`] for an unset string value, or
194    /// [`ValueError::TypeMismatch`] for any other runtime type.
195    #[inline(always)]
196    fn try_from(value: &'a Value) -> ValueResult<Self> {
197        match &value.repr {
198            ValueRepr::String(value) => Ok(value.as_str()),
199            ValueRepr::Unset(actual) if *actual == DataType::String => Err(ValueError::Missing(
200                ValueMissing::unset_scalar(*actual, *actual),
201            )),
202            _ => Err(ValueError::TypeMismatch {
203                expected: DataType::String,
204                actual: value.data_type(),
205            }),
206        }
207    }
208}