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(crate) fn from_ref(v: &ProtoValue) -> &Self {
59 unsafe { &*(v as *const ProtoValue as *const Value) }
63 }
64
65 pub fn kind(&self) -> Kind {
67 match &self.0.kind {
68 Some(prost_types::value::Kind::NullValue(_)) => Kind::Null,
69 Some(prost_types::value::Kind::NumberValue(_)) => Kind::Number,
70 Some(prost_types::value::Kind::StringValue(_)) => Kind::String,
71 Some(prost_types::value::Kind::BoolValue(_)) => Kind::Bool,
72 Some(prost_types::value::Kind::StructValue(_)) => Kind::Struct,
73 Some(prost_types::value::Kind::ListValue(_)) => Kind::List,
74 None => Kind::Null,
75 }
76 }
77
78 pub fn try_as_string(&self) -> Option<&str> {
80 match &self.0.kind {
81 Some(prost_types::value::Kind::StringValue(s)) => Some(s),
82 _ => None,
83 }
84 }
85
86 pub fn as_string(&self) -> &str {
88 self.try_as_string().expect("value is not a String")
89 }
90
91 pub fn try_as_bool(&self) -> Option<bool> {
93 match &self.0.kind {
94 Some(prost_types::value::Kind::BoolValue(b)) => Some(*b),
95 _ => None,
96 }
97 }
98
99 pub fn as_bool(&self) -> bool {
101 self.try_as_bool().expect("value is not a Bool")
102 }
103
104 pub fn try_as_f64(&self) -> Option<f64> {
106 match &self.0.kind {
107 Some(prost_types::value::Kind::NumberValue(n)) => Some(*n),
108 _ => None,
109 }
110 }
111
112 pub fn as_f64(&self) -> f64 {
114 self.try_as_f64().expect("value is not a Number")
115 }
116
117 pub fn try_as_struct(&self) -> Option<&Struct> {
119 match &self.0.kind {
120 Some(prost_types::value::Kind::StructValue(s)) => Some(Struct::from_ref(s)),
121 _ => None,
122 }
123 }
124
125 pub fn as_struct(&self) -> &Struct {
127 self.try_as_struct().expect("value is not a Struct")
128 }
129
130 pub fn try_as_list(&self) -> Option<&List> {
132 match &self.0.kind {
133 Some(prost_types::value::Kind::ListValue(l)) => Some(List::from_ref(l)),
134 _ => None,
135 }
136 }
137
138 pub fn as_list(&self) -> &List {
140 self.try_as_list().expect("value is not a List")
141 }
142}
143
144impl Value {
145 pub(crate) fn into_serde_value(self) -> serde_json::Value {
149 match self.0.kind {
150 Some(prost_types::value::Kind::NullValue(_)) => serde_json::Value::Null,
151 Some(prost_types::value::Kind::NumberValue(n)) => {
152 if let Some(num) = serde_json::Number::from_f64(n) {
153 serde_json::Value::Number(num)
154 } else {
155 serde_json::Value::Null
156 }
157 }
158 Some(prost_types::value::Kind::StringValue(s)) => serde_json::Value::String(s),
159 Some(prost_types::value::Kind::BoolValue(b)) => serde_json::Value::Bool(b),
160 Some(prost_types::value::Kind::StructValue(s)) => serde_json::Value::Object(
161 s.fields
162 .into_iter()
163 .map(|(k, v)| (k, Value(v).into_serde_value()))
164 .collect(),
165 ),
166 Some(prost_types::value::Kind::ListValue(l)) => serde_json::Value::Array(
167 l.values
168 .into_iter()
169 .map(|v| Value(v).into_serde_value())
170 .collect(),
171 ),
172 None => serde_json::Value::Null,
173 }
174 }
175}
176
177#[repr(transparent)]
179#[derive(Clone, Debug, PartialEq, Default)]
180pub struct Struct(pub(crate) prost_types::Struct);
181
182impl Struct {
183 pub(crate) fn from_ref(v: &prost_types::Struct) -> &Self {
185 unsafe { &*(v as *const prost_types::Struct as *const Struct) }
187 }
188
189 pub fn get(&self, key: &str) -> Option<&Value> {
191 self.0.fields.get(key).map(Value::from_ref)
192 }
193
194 pub fn len(&self) -> usize {
196 self.0.fields.len()
197 }
198
199 pub fn is_empty(&self) -> bool {
201 self.0.fields.is_empty()
202 }
203
204 pub fn fields(&self) -> impl Iterator<Item = (&String, &Value)> {
206 self.0.fields.iter().map(|(k, v)| (k, Value::from_ref(v)))
207 }
208}
209
210#[repr(transparent)]
212#[derive(Clone, Debug, PartialEq, Default)]
213pub struct List(pub(crate) prost_types::ListValue);
214
215impl List {
216 pub(crate) fn from_ref(v: &prost_types::ListValue) -> &Self {
218 unsafe { &*(v as *const prost_types::ListValue as *const List) }
220 }
221
222 pub fn get(&self, index: usize) -> Option<&Value> {
224 self.0.values.get(index).map(Value::from_ref)
225 }
226
227 pub fn len(&self) -> usize {
229 self.0.values.len()
230 }
231
232 pub fn is_empty(&self) -> bool {
234 self.0.values.is_empty()
235 }
236
237 pub fn iter(&self) -> impl Iterator<Item = &Value> {
239 self.0.values.iter().map(Value::from_ref)
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246 use std::hash::Hash;
247
248 #[test]
249 fn test_value_kind_and_accessors() {
250 let v_null = Value(ProtoValue {
251 kind: Some(prost_types::value::Kind::NullValue(0)),
252 });
253 assert_eq!(v_null.kind(), Kind::Null);
254 assert!(v_null.try_as_string().is_none());
255
256 let v_string = Value(ProtoValue {
257 kind: Some(prost_types::value::Kind::StringValue("foo".to_string())),
258 });
259 assert_eq!(v_string.kind(), Kind::String);
260 assert_eq!(v_string.try_as_string(), Some("foo"));
261 assert_eq!(v_string.as_string(), "foo");
262 assert!(v_string.try_as_bool().is_none());
263
264 let v_bool = Value(ProtoValue {
265 kind: Some(prost_types::value::Kind::BoolValue(true)),
266 });
267 assert_eq!(v_bool.kind(), Kind::Bool);
268 assert_eq!(v_bool.try_as_bool(), Some(true));
269 assert!(v_bool.as_bool());
270
271 let v_number = Value(ProtoValue {
272 kind: Some(prost_types::value::Kind::NumberValue(42.0)),
273 });
274 assert_eq!(v_number.kind(), Kind::Number);
275 assert_eq!(v_number.try_as_f64(), Some(42.0));
276 assert_eq!(v_number.as_f64(), 42.0);
277
278 let v_list = Value(ProtoValue {
279 kind: Some(prost_types::value::Kind::ListValue(
280 prost_types::ListValue {
281 values: vec![ProtoValue {
282 kind: Some(prost_types::value::Kind::NumberValue(1.0)),
283 }],
284 },
285 )),
286 });
287 assert_eq!(v_list.kind(), Kind::List);
288 let list = v_list.try_as_list().unwrap();
289 assert_eq!(list.len(), 1);
290 assert_eq!(list.get(0).unwrap().try_as_f64(), Some(1.0));
291 assert_eq!(v_list.as_list().len(), 1);
292
293 let v_struct = Value(ProtoValue {
294 kind: Some(prost_types::value::Kind::StructValue(prost_types::Struct {
295 fields: std::collections::BTreeMap::from([(
296 "a".to_string(),
297 ProtoValue {
298 kind: Some(prost_types::value::Kind::NumberValue(1.0)),
299 },
300 )]),
301 })),
302 });
303 assert_eq!(v_struct.kind(), Kind::Struct);
304 let map = v_struct.try_as_struct().unwrap();
305 assert_eq!(map.len(), 1);
306 assert_eq!(map.get("a").unwrap().try_as_f64(), Some(1.0));
307 assert_eq!(v_struct.as_struct().len(), 1);
308 }
309
310 #[test]
311 fn test_auto_traits() {
312 static_assertions::assert_impl_all!(Value: Send, Sync, Clone, std::fmt::Debug);
313 static_assertions::assert_impl_all!(Struct: Send, Sync, Clone, std::fmt::Debug);
314 static_assertions::assert_impl_all!(List: Send, Sync, Clone, std::fmt::Debug);
315 static_assertions::assert_impl_all!(
316 Kind: Send,
317 Sync,
318 Clone,
319 Copy,
320 std::fmt::Debug,
321 PartialEq,
322 Eq,
323 Hash
324 );
325 }
326}