1pub(crate) const SPANNER_TIMESTAMP_FORMAT: &[time::format_description::FormatItem<'static>] = time::macros::format_description!(
16 "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:9]Z"
17);
18pub(crate) const SPANNER_DATE_FORMAT: &[time::format_description::FormatItem<'static>] =
19 time::macros::format_description!("[year]-[month]-[day]");
20
21pub use crate::from_value::FromValue;
22pub use crate::to_value::ToValue;
23pub use crate::types::{Type, TypeCode};
24
25use prost_types::Value as ProtoValue;
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
32#[allow(clippy::exhaustive_enums, reason = "Value kinds are frozen JSON types")]
33pub enum Kind {
34 Null,
36 Number,
38 String,
41 Bool,
43 Struct,
45 List,
47}
48
49#[repr(transparent)]
52#[derive(Clone, Debug, PartialEq, Default)]
53pub struct Value(pub(crate) ProtoValue);
54
55impl Value {
56 pub fn null() -> Self {
58 Value(ProtoValue {
59 kind: Some(prost_types::value::Kind::NullValue(0)),
60 })
61 }
62
63 pub(crate) fn from_ref(v: &ProtoValue) -> &Self {
66 unsafe { &*(v as *const ProtoValue as *const Value) }
70 }
71
72 pub fn kind(&self) -> Kind {
74 match &self.0.kind {
75 Some(prost_types::value::Kind::NullValue(_)) => Kind::Null,
76 Some(prost_types::value::Kind::NumberValue(_)) => Kind::Number,
77 Some(prost_types::value::Kind::StringValue(_)) => Kind::String,
78 Some(prost_types::value::Kind::BoolValue(_)) => Kind::Bool,
79 Some(prost_types::value::Kind::StructValue(_)) => Kind::Struct,
80 Some(prost_types::value::Kind::ListValue(_)) => Kind::List,
81 None => Kind::Null,
82 }
83 }
84
85 pub fn try_as_string(&self) -> Option<&str> {
87 match &self.0.kind {
88 Some(prost_types::value::Kind::StringValue(s)) => Some(s),
89 _ => None,
90 }
91 }
92
93 pub fn as_string(&self) -> &str {
95 self.try_as_string().expect("value is not a String")
96 }
97
98 pub fn try_as_bool(&self) -> Option<bool> {
100 match &self.0.kind {
101 Some(prost_types::value::Kind::BoolValue(b)) => Some(*b),
102 _ => None,
103 }
104 }
105
106 pub fn as_bool(&self) -> bool {
108 self.try_as_bool().expect("value is not a Bool")
109 }
110
111 pub fn try_as_f64(&self) -> Option<f64> {
113 match &self.0.kind {
114 Some(prost_types::value::Kind::NumberValue(n)) => Some(*n),
115 _ => None,
116 }
117 }
118
119 pub fn as_f64(&self) -> f64 {
121 self.try_as_f64().expect("value is not a Number")
122 }
123
124 pub fn try_as_struct(&self) -> Option<&Struct> {
126 match &self.0.kind {
127 Some(prost_types::value::Kind::StructValue(s)) => Some(Struct::from_ref(s)),
128 _ => None,
129 }
130 }
131
132 pub fn as_struct(&self) -> &Struct {
134 self.try_as_struct().expect("value is not a Struct")
135 }
136
137 pub fn try_as_list(&self) -> Option<&List> {
139 match &self.0.kind {
140 Some(prost_types::value::Kind::ListValue(l)) => Some(List::from_ref(l)),
141 _ => None,
142 }
143 }
144
145 pub fn as_list(&self) -> &List {
147 self.try_as_list().expect("value is not a List")
148 }
149}
150
151impl Value {
152 pub(crate) fn into_serde_value(self) -> serde_json::Value {
156 match self.0.kind {
157 Some(prost_types::value::Kind::NullValue(_)) => serde_json::Value::Null,
158 Some(prost_types::value::Kind::NumberValue(n)) => {
159 if let Some(num) = serde_json::Number::from_f64(n) {
160 serde_json::Value::Number(num)
161 } else {
162 serde_json::Value::Null
163 }
164 }
165 Some(prost_types::value::Kind::StringValue(s)) => serde_json::Value::String(s),
166 Some(prost_types::value::Kind::BoolValue(b)) => serde_json::Value::Bool(b),
167 Some(prost_types::value::Kind::StructValue(s)) => serde_json::Value::Object(
168 s.fields
169 .into_iter()
170 .map(|(k, v)| (k, Value(v).into_serde_value()))
171 .collect(),
172 ),
173 Some(prost_types::value::Kind::ListValue(l)) => serde_json::Value::Array(
174 l.values
175 .into_iter()
176 .map(|v| Value(v).into_serde_value())
177 .collect(),
178 ),
179 None => serde_json::Value::Null,
180 }
181 }
182}
183
184#[repr(transparent)]
186#[derive(Clone, Debug, PartialEq, Default)]
187pub struct Struct(pub(crate) prost_types::Struct);
188
189impl Struct {
190 pub(crate) fn from_ref(v: &prost_types::Struct) -> &Self {
192 unsafe { &*(v as *const prost_types::Struct as *const Struct) }
194 }
195
196 pub fn get(&self, key: &str) -> Option<&Value> {
198 self.0.fields.get(key).map(Value::from_ref)
199 }
200
201 pub fn len(&self) -> usize {
203 self.0.fields.len()
204 }
205
206 pub fn is_empty(&self) -> bool {
208 self.0.fields.is_empty()
209 }
210
211 pub fn fields(&self) -> impl Iterator<Item = (&String, &Value)> {
213 self.0.fields.iter().map(|(k, v)| (k, Value::from_ref(v)))
214 }
215}
216
217#[repr(transparent)]
219#[derive(Clone, Debug, PartialEq, Default)]
220pub struct List(pub(crate) prost_types::ListValue);
221
222impl List {
223 pub(crate) fn from_ref(v: &prost_types::ListValue) -> &Self {
225 unsafe { &*(v as *const prost_types::ListValue as *const List) }
227 }
228
229 pub fn get(&self, index: usize) -> Option<&Value> {
231 self.0.values.get(index).map(Value::from_ref)
232 }
233
234 pub fn len(&self) -> usize {
236 self.0.values.len()
237 }
238
239 pub fn is_empty(&self) -> bool {
241 self.0.values.is_empty()
242 }
243
244 pub fn iter(&self) -> impl Iterator<Item = &Value> {
246 self.0.values.iter().map(Value::from_ref)
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253 use std::hash::Hash;
254
255 #[test]
256 fn test_value_kind_and_accessors() {
257 let v_null = Value(ProtoValue {
258 kind: Some(prost_types::value::Kind::NullValue(0)),
259 });
260 assert_eq!(v_null.kind(), Kind::Null);
261 assert!(v_null.try_as_string().is_none());
262
263 let v_string = Value(ProtoValue {
264 kind: Some(prost_types::value::Kind::StringValue("foo".to_string())),
265 });
266 assert_eq!(v_string.kind(), Kind::String);
267 assert_eq!(v_string.try_as_string(), Some("foo"));
268 assert_eq!(v_string.as_string(), "foo");
269 assert!(v_string.try_as_bool().is_none());
270
271 let v_bool = Value(ProtoValue {
272 kind: Some(prost_types::value::Kind::BoolValue(true)),
273 });
274 assert_eq!(v_bool.kind(), Kind::Bool);
275 assert_eq!(v_bool.try_as_bool(), Some(true));
276 assert!(v_bool.as_bool());
277
278 let v_number = Value(ProtoValue {
279 kind: Some(prost_types::value::Kind::NumberValue(42.0)),
280 });
281 assert_eq!(v_number.kind(), Kind::Number);
282 assert_eq!(v_number.try_as_f64(), Some(42.0));
283 assert_eq!(v_number.as_f64(), 42.0);
284
285 let v_list = Value(ProtoValue {
286 kind: Some(prost_types::value::Kind::ListValue(
287 prost_types::ListValue {
288 values: vec![ProtoValue {
289 kind: Some(prost_types::value::Kind::NumberValue(1.0)),
290 }],
291 },
292 )),
293 });
294 assert_eq!(v_list.kind(), Kind::List);
295 let list = v_list.try_as_list().unwrap();
296 assert_eq!(list.len(), 1);
297 assert_eq!(list.get(0).unwrap().try_as_f64(), Some(1.0));
298 assert_eq!(v_list.as_list().len(), 1);
299
300 let v_struct = Value(ProtoValue {
301 kind: Some(prost_types::value::Kind::StructValue(prost_types::Struct {
302 fields: std::collections::BTreeMap::from([(
303 "a".to_string(),
304 ProtoValue {
305 kind: Some(prost_types::value::Kind::NumberValue(1.0)),
306 },
307 )]),
308 })),
309 });
310 assert_eq!(v_struct.kind(), Kind::Struct);
311 let map = v_struct.try_as_struct().unwrap();
312 assert_eq!(map.len(), 1);
313 assert_eq!(map.get("a").unwrap().try_as_f64(), Some(1.0));
314 assert_eq!(v_struct.as_struct().len(), 1);
315 }
316
317 #[test]
318 fn test_auto_traits() {
319 static_assertions::assert_impl_all!(Value: Send, Sync, Clone, std::fmt::Debug);
320 static_assertions::assert_impl_all!(Struct: Send, Sync, Clone, std::fmt::Debug);
321 static_assertions::assert_impl_all!(List: Send, Sync, Clone, std::fmt::Debug);
322 static_assertions::assert_impl_all!(
323 Kind: Send,
324 Sync,
325 Clone,
326 Copy,
327 std::fmt::Debug,
328 PartialEq,
329 Eq,
330 Hash
331 );
332 }
333}