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 => {
200 Err(ValueError::Missing(ValueMissing::unset_scalar(*actual, *actual)))
201 }
202 _ => Err(ValueError::TypeMismatch {
203 expected: DataType::String,
204 actual: value.data_type(),
205 }),
206 }
207 }
208}