Skip to main content

oxiproto_reflect/native/
value.rs

1//! Dynamic field value types for native reflection.
2//!
3//! [`Value`] is the runtime representation of a single protobuf field value,
4//! and [`MapKey`] is the restricted set of scalar types that may appear as a
5//! `map<K, V>` key. The shapes mirror `prost_reflect::Value` / `MapKey` so
6//! callers can move between the two paths with minimal friction.
7
8use std::collections::HashMap;
9
10use super::dynamic::DynamicMessage;
11
12/// A dynamically-typed protobuf field value.
13///
14/// Each variant corresponds to a protobuf scalar type, a nested message, an
15/// enum value (stored by its integer number), a repeated field (`List`), or a
16/// map field (`Map`). For repeated and map fields the *element* value is
17/// stored using the same `Value` enum.
18#[derive(Clone, Debug, PartialEq)]
19pub enum Value {
20    /// A `double` value.
21    F64(f64),
22    /// A `float` value.
23    F32(f32),
24    /// An `int32`, `sint32`, or `sfixed32` value.
25    I32(i32),
26    /// An `int64`, `sint64`, or `sfixed64` value.
27    I64(i64),
28    /// A `uint32` or `fixed32` value.
29    U32(u32),
30    /// A `uint64` or `fixed64` value.
31    U64(u64),
32    /// A `bool` value.
33    Bool(bool),
34    /// A `string` value.
35    String(String),
36    /// A `bytes` value.
37    Bytes(Vec<u8>),
38    /// An enum value, stored as its integer number.
39    EnumNumber(i32),
40    /// A nested message value.
41    Message(Box<DynamicMessage>),
42    /// A repeated field value.
43    List(Vec<Value>),
44    /// A map field value.
45    Map(HashMap<MapKey, Value>),
46}
47
48/// The key of a protobuf `map<K, V>` field.
49///
50/// Protobuf restricts map keys to integral, boolean, and string scalar types.
51#[derive(Clone, Debug, PartialEq, Eq, Hash)]
52pub enum MapKey {
53    /// A `string` key.
54    String(String),
55    /// An `int32`, `sint32`, or `sfixed32` key.
56    I32(i32),
57    /// An `int64`, `sint64`, or `sfixed64` key.
58    I64(i64),
59    /// A `uint32` or `fixed32` key.
60    U32(u32),
61    /// A `uint64` or `fixed64` key.
62    U64(u64),
63    /// A `bool` key.
64    Bool(bool),
65}
66
67impl Value {
68    /// Returns `true` if this value equals the default (zero/empty) value for
69    /// its variant.
70    ///
71    /// This is used to implement proto3 default-value omission on encode: a
72    /// singular field whose value is the default is not written to the wire.
73    pub fn is_default(&self) -> bool {
74        match self {
75            Value::F64(v) => *v == 0.0,
76            Value::F32(v) => *v == 0.0,
77            Value::I32(v) => *v == 0,
78            Value::I64(v) => *v == 0,
79            Value::U32(v) => *v == 0,
80            Value::U64(v) => *v == 0,
81            Value::Bool(v) => !*v,
82            Value::String(s) => s.is_empty(),
83            Value::Bytes(b) => b.is_empty(),
84            Value::EnumNumber(n) => *n == 0,
85            Value::Message(_) => false,
86            Value::List(l) => l.is_empty(),
87            Value::Map(m) => m.is_empty(),
88        }
89    }
90
91    /// Borrow this value as a `f64`, if it is one.
92    pub fn as_f64(&self) -> Option<f64> {
93        match self {
94            Value::F64(v) => Some(*v),
95            _ => None,
96        }
97    }
98
99    /// Borrow this value as a `f32`, if it is one.
100    pub fn as_f32(&self) -> Option<f32> {
101        match self {
102            Value::F32(v) => Some(*v),
103            _ => None,
104        }
105    }
106
107    /// Borrow this value as an `i32`, if it is one.
108    pub fn as_i32(&self) -> Option<i32> {
109        match self {
110            Value::I32(v) => Some(*v),
111            _ => None,
112        }
113    }
114
115    /// Borrow this value as an `i64`, if it is one.
116    pub fn as_i64(&self) -> Option<i64> {
117        match self {
118            Value::I64(v) => Some(*v),
119            _ => None,
120        }
121    }
122
123    /// Borrow this value as a `u32`, if it is one.
124    pub fn as_u32(&self) -> Option<u32> {
125        match self {
126            Value::U32(v) => Some(*v),
127            _ => None,
128        }
129    }
130
131    /// Borrow this value as a `u64`, if it is one.
132    pub fn as_u64(&self) -> Option<u64> {
133        match self {
134            Value::U64(v) => Some(*v),
135            _ => None,
136        }
137    }
138
139    /// Borrow this value as a `bool`, if it is one.
140    pub fn as_bool(&self) -> Option<bool> {
141        match self {
142            Value::Bool(v) => Some(*v),
143            _ => None,
144        }
145    }
146
147    /// Borrow this value as a `&str`, if it is a string.
148    pub fn as_str(&self) -> Option<&str> {
149        match self {
150            Value::String(s) => Some(s.as_str()),
151            _ => None,
152        }
153    }
154
155    /// Borrow this value as a byte slice, if it is `bytes`.
156    pub fn as_bytes(&self) -> Option<&[u8]> {
157        match self {
158            Value::Bytes(b) => Some(b.as_slice()),
159            _ => None,
160        }
161    }
162
163    /// Borrow this value as an enum number, if it is one.
164    pub fn as_enum_number(&self) -> Option<i32> {
165        match self {
166            Value::EnumNumber(n) => Some(*n),
167            _ => None,
168        }
169    }
170
171    /// Borrow this value as a nested [`DynamicMessage`], if it is a message.
172    pub fn as_message(&self) -> Option<&DynamicMessage> {
173        match self {
174            Value::Message(m) => Some(m.as_ref()),
175            _ => None,
176        }
177    }
178
179    /// Borrow this value as a repeated `List`, if it is one.
180    pub fn as_list(&self) -> Option<&[Value]> {
181        match self {
182            Value::List(l) => Some(l.as_slice()),
183            _ => None,
184        }
185    }
186
187    /// Borrow this value as a `Map`, if it is one.
188    pub fn as_map(&self) -> Option<&HashMap<MapKey, Value>> {
189        match self {
190            Value::Map(m) => Some(m),
191            _ => None,
192        }
193    }
194}
195
196impl MapKey {
197    /// Convert this map key into the equivalent [`Value`].
198    pub fn to_value(&self) -> Value {
199        match self {
200            MapKey::String(s) => Value::String(s.clone()),
201            MapKey::I32(v) => Value::I32(*v),
202            MapKey::I64(v) => Value::I64(*v),
203            MapKey::U32(v) => Value::U32(*v),
204            MapKey::U64(v) => Value::U64(*v),
205            MapKey::Bool(v) => Value::Bool(*v),
206        }
207    }
208}
209
210#[cfg(test)]
211mod tests {
212    use super::*;
213
214    #[test]
215    fn is_default_scalars() {
216        assert!(Value::I32(0).is_default());
217        assert!(!Value::I32(1).is_default());
218        assert!(Value::Bool(false).is_default());
219        assert!(!Value::Bool(true).is_default());
220        assert!(Value::String(String::new()).is_default());
221        assert!(!Value::String("x".to_owned()).is_default());
222        assert!(Value::Bytes(Vec::new()).is_default());
223        assert!(Value::F64(0.0).is_default());
224        assert!(Value::EnumNumber(0).is_default());
225        assert!(Value::List(Vec::new()).is_default());
226    }
227
228    #[test]
229    fn accessors() {
230        assert_eq!(Value::I32(7).as_i32(), Some(7));
231        assert_eq!(Value::I32(7).as_i64(), None);
232        assert_eq!(Value::String("hi".to_owned()).as_str(), Some("hi"));
233        assert_eq!(Value::Bytes(vec![1, 2]).as_bytes(), Some(&[1u8, 2][..]));
234        assert_eq!(Value::Bool(true).as_bool(), Some(true));
235        assert_eq!(Value::EnumNumber(3).as_enum_number(), Some(3));
236    }
237
238    #[test]
239    fn map_key_to_value() {
240        assert_eq!(
241            MapKey::String("k".to_owned()).to_value(),
242            Value::String("k".to_owned())
243        );
244        assert_eq!(MapKey::I64(5).to_value(), Value::I64(5));
245        assert_eq!(MapKey::Bool(true).to_value(), Value::Bool(true));
246    }
247}