Skip to main content

buffa/
message_field.rs

1//! Optional message field wrapper that provides ergonomic access.
2//!
3//! `MessageField<T>` replaces `Option<Box<T>>` for optional/singular message
4//! fields. It dereferences to a default instance when unset, avoiding the
5//! `Option<Box<M>>` unwrapping ceremony that plagues prost-generated code.
6
7use alloc::boxed::Box;
8use core::fmt;
9use core::ops::Deref;
10
11/// Provides access to a lazily-initialized, immutable default instance of a
12/// type.
13///
14/// Types that implement this trait can be used as the target of
15/// [`MessageField<T>`] dereferences when the field is unset. It is also a
16/// supertrait of [`Message`](crate::Message), so every generated message type
17/// must implement it.
18///
19/// **Codegen implements this automatically** for every generated message
20/// type. You only need to implement it by hand when manually implementing
21/// [`Message`](crate::Message) for a custom type.
22///
23/// # Recommended implementation
24///
25/// The pattern codegen uses — and the recommended pattern for manual
26/// implementations — stores the instance in a `static`
27/// [`once_cell::race::OnceBox`] (re-exported as
28/// `::buffa::__private::OnceBox`), which works in both `no_std + alloc` and
29/// `std` environments:
30///
31/// ```rust,ignore
32/// impl DefaultInstance for MyMessage {
33///     fn default_instance() -> &'static Self {
34///         static VALUE: ::buffa::__private::OnceBox<MyMessage>
35///             = ::buffa::__private::OnceBox::new();
36///         VALUE.get_or_init(|| ::alloc::boxed::Box::new(MyMessage::default()))
37///     }
38/// }
39/// ```
40///
41/// In `std`-only environments [`std::sync::OnceLock`] is also available and
42/// avoids the `alloc::boxed::Box` wrapping:
43///
44/// ```rust,ignore
45/// impl DefaultInstance for MyMessage {
46///     fn default_instance() -> &'static Self {
47///         static VALUE: std::sync::OnceLock<MyMessage> = std::sync::OnceLock::new();
48///         VALUE.get_or_init(MyMessage::default)
49///     }
50/// }
51/// ```
52pub trait DefaultInstance: Default + 'static {
53    /// Return a reference to the single default instance of this type.
54    fn default_instance() -> &'static Self;
55}
56
57/// A wrapper for optional message fields that provides transparent access
58/// to a default instance when the field is not set.
59///
60/// This type is used for singular message fields in generated code. It avoids
61/// the ergonomic pain of `Option<Box<M>>` while still being heap-allocated
62/// only when set (no allocation for unset fields).
63///
64/// # Access patterns
65///
66/// ```rust,ignore
67/// // Reading through an unset field gives the default:
68/// let msg = Outer::default();
69/// assert_eq!(msg.inner.name, "");  // No unwrap needed, derefs to default
70///
71/// // Check if set:
72/// if msg.inner.is_set() { ... }
73///
74/// // Set a value:
75/// msg.inner = MessageField::some(Inner { name: "hello".into(), ..Default::default() });
76///
77/// // Clear:
78/// msg.inner = MessageField::none();
79/// ```
80pub struct MessageField<T: Default> {
81    inner: Option<Box<T>>,
82}
83
84impl<T: Default> MessageField<T> {
85    /// Create a `MessageField` with no value set.
86    #[inline]
87    pub const fn none() -> Self {
88        Self { inner: None }
89    }
90
91    /// Create a `MessageField` with a value.
92    #[inline]
93    pub fn some(value: T) -> Self {
94        Self {
95            inner: Some(Box::new(value)),
96        }
97    }
98
99    /// Create a `MessageField` from a boxed value.
100    #[inline]
101    pub fn from_box(value: Box<T>) -> Self {
102        Self { inner: Some(value) }
103    }
104
105    /// Returns `true` if the field has a value set.
106    #[inline]
107    pub fn is_set(&self) -> bool {
108        self.inner.is_some()
109    }
110
111    /// Returns `true` if the field has no value set.
112    #[inline]
113    pub fn is_unset(&self) -> bool {
114        self.inner.is_none()
115    }
116
117    /// Get a reference to the inner value, or `None` if unset.
118    #[inline]
119    pub fn as_option(&self) -> Option<&T> {
120        self.inner.as_deref()
121    }
122
123    /// Get a mutable reference to the inner value, or `None` if unset.
124    #[inline]
125    pub fn as_option_mut(&mut self) -> Option<&mut T> {
126        self.inner.as_deref_mut()
127    }
128
129    /// Take the inner value, leaving the field unset.
130    #[inline]
131    pub fn take(&mut self) -> Option<T> {
132        self.inner.take().map(|b| *b)
133    }
134
135    /// Get a mutable reference to the value, initializing to the default if unset.
136    #[inline]
137    pub fn get_or_insert_default(&mut self) -> &mut T {
138        self.inner.get_or_insert_default()
139    }
140
141    /// Call `f` with a mutable reference to the inner value, initializing to
142    /// the default if the field is currently unset.
143    ///
144    /// This is the ergonomic write counterpart to the transparent read
145    /// provided by `Deref`. Instead of calling `get_or_insert_default` once
146    /// per assignment:
147    ///
148    /// ```rust,ignore
149    /// msg.address.get_or_insert_default().street = "123 Main St".into();
150    /// msg.address.get_or_insert_default().city   = "Springfield".into();
151    /// ```
152    ///
153    /// use `modify` to initialize the field once and set all sub-fields in
154    /// the closure:
155    ///
156    /// ```rust,ignore
157    /// msg.address.modify(|a| {
158    ///     a.street = "123 Main St".into();
159    ///     a.city   = "Springfield".into();
160    /// });
161    /// ```
162    #[inline]
163    pub fn modify<F: FnOnce(&mut T)>(&mut self, f: F) {
164        f(self.get_or_insert_default());
165    }
166
167    /// Consume the field, returning `Some(T)` if set or `None` if unset.
168    ///
169    /// This unboxes the inner value. For in-place extraction that leaves the
170    /// field unset without consuming the enclosing struct, see [`take`](Self::take).
171    #[inline]
172    pub fn into_option(self) -> Option<T> {
173        self.inner.map(|b| *b)
174    }
175
176    /// Consume the field, returning `Ok(T)` if set or `Err(err)` if unset.
177    ///
178    /// Mirrors [`Option::ok_or`]. Useful for enforcing presence of
179    /// semantically-required fields that the proto schema leaves optional:
180    ///
181    /// ```rust,ignore
182    /// let cmd = request.normalized_command.ok_or(Error::MissingCommand)?;
183    /// ```
184    #[inline]
185    pub fn ok_or<E>(self, err: E) -> Result<T, E> {
186        match self.inner {
187            Some(b) => Ok(*b),
188            None => Err(err),
189        }
190    }
191
192    /// Consume the field, returning `Ok(T)` if set or `Err(err())` if unset.
193    ///
194    /// Mirrors [`Option::ok_or_else`]. The closure is only called if the
195    /// field is unset, so use this over [`ok_or`](Self::ok_or) when
196    /// constructing the error is non-trivial:
197    ///
198    /// ```rust,ignore
199    /// let cmd = request.normalized_command.ok_or_else(|| {
200    ///     ConnectError::invalid_argument("missing normalized_command in request")
201    /// })?;
202    /// ```
203    #[inline]
204    pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
205        match self.inner {
206            Some(b) => Ok(*b),
207            None => Err(err()),
208        }
209    }
210}
211
212impl<T: Default> Default for MessageField<T> {
213    #[inline]
214    fn default() -> Self {
215        Self::none()
216    }
217}
218
219impl<T: DefaultInstance> Deref for MessageField<T> {
220    type Target = T;
221
222    #[inline]
223    fn deref(&self) -> &T {
224        match &self.inner {
225            Some(value) => value,
226            None => T::default_instance(),
227        }
228    }
229}
230
231impl<T: Default + Clone> Clone for MessageField<T> {
232    fn clone(&self) -> Self {
233        Self {
234            inner: self.inner.clone(),
235        }
236    }
237}
238
239impl<T: DefaultInstance + PartialEq> PartialEq for MessageField<T> {
240    fn eq(&self, other: &Self) -> bool {
241        match (&self.inner, &other.inner) {
242            (Some(a), Some(b)) => a == b,
243            (None, None) => true,
244            // An unset field equals a set-to-default field. Use default_instance()
245            // to avoid allocating a temporary value for the comparison.
246            (Some(a), None) => **a == *T::default_instance(),
247            (None, Some(b)) => *T::default_instance() == **b,
248        }
249    }
250}
251
252impl<T: DefaultInstance + Eq + PartialEq> Eq for MessageField<T> {}
253
254impl<T: Default + fmt::Debug> fmt::Debug for MessageField<T> {
255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256        match &self.inner {
257            Some(value) => f.debug_tuple("MessageField::Set").field(value).finish(),
258            None => f.write_str("MessageField::Unset"),
259        }
260    }
261}
262
263impl<T: Default> From<Option<T>> for MessageField<T> {
264    fn from(opt: Option<T>) -> Self {
265        match opt {
266            Some(v) => Self::some(v),
267            None => Self::none(),
268        }
269    }
270}
271
272impl<T: Default> From<T> for MessageField<T> {
273    fn from(value: T) -> Self {
274        Self::some(value)
275    }
276}
277
278#[cfg(feature = "json")]
279impl<T: Default + serde::Serialize> serde::Serialize for MessageField<T> {
280    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
281        match self.inner.as_deref() {
282            Some(v) => s.serialize_some(v),
283            None => s.serialize_none(),
284        }
285    }
286}
287
288#[cfg(feature = "json")]
289impl<'de, T: Default + serde::Deserialize<'de>> serde::Deserialize<'de> for MessageField<T> {
290    fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
291        Option::<T>::deserialize(d).map(|opt| match opt {
292            Some(v) => Self::some(v),
293            None => Self::none(),
294        })
295    }
296}
297
298#[cfg(feature = "arbitrary")]
299impl<'a, T: Default + arbitrary::Arbitrary<'a>> arbitrary::Arbitrary<'a> for MessageField<T> {
300    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
301        Ok(if bool::arbitrary(u)? {
302            MessageField::some(T::arbitrary(u)?)
303        } else {
304            MessageField::none()
305        })
306    }
307}
308
309#[cfg(test)]
310mod tests {
311    use super::*;
312
313    #[derive(Clone, Debug, Default, PartialEq)]
314    struct Inner {
315        value: i32,
316        name: alloc::string::String,
317    }
318
319    impl DefaultInstance for Inner {
320        fn default_instance() -> &'static Self {
321            static VALUE: crate::__private::OnceBox<Inner> = crate::__private::OnceBox::new();
322            VALUE.get_or_init(|| alloc::boxed::Box::new(Inner::default()))
323        }
324    }
325
326    #[test]
327    fn test_unset_derefs_to_default() {
328        let field: MessageField<Inner> = MessageField::none();
329        assert!(!field.is_set());
330        assert_eq!(field.value, 0);
331        assert_eq!(field.name, "");
332    }
333
334    #[test]
335    fn test_set_derefs_to_value() {
336        let field = MessageField::some(Inner {
337            value: 42,
338            name: "hello".into(),
339        });
340        assert!(field.is_set());
341        assert_eq!(field.value, 42);
342        assert_eq!(field.name, "hello");
343    }
344
345    #[test]
346    fn test_get_or_insert_default() {
347        let mut field: MessageField<Inner> = MessageField::none();
348        assert!(!field.is_set());
349        field.get_or_insert_default().value = 10;
350        assert!(field.is_set());
351        assert_eq!(field.value, 10);
352    }
353
354    #[test]
355    fn test_equality() {
356        let a: MessageField<Inner> = MessageField::none();
357        let b: MessageField<Inner> = MessageField::some(Inner::default());
358        // An unset field and a set-to-default field are equal.
359        assert_eq!(a, b);
360    }
361
362    #[test]
363    fn test_take() {
364        let mut field = MessageField::some(Inner {
365            value: 7,
366            name: "taken".into(),
367        });
368        let taken = field.take();
369        assert!(field.is_unset());
370        assert_eq!(taken.unwrap().value, 7);
371    }
372
373    #[test]
374    fn test_clone() {
375        let field = MessageField::some(Inner {
376            value: 99,
377            name: "clone".into(),
378        });
379        let cloned = field.clone();
380        assert_eq!(field, cloned);
381    }
382
383    #[test]
384    fn test_modify_initializes_unset_field() {
385        let mut field: MessageField<Inner> = MessageField::none();
386        field.modify(|inner| {
387            inner.value = 42;
388            inner.name = "hello".into();
389        });
390        assert!(field.is_set());
391        assert_eq!(field.value, 42);
392        assert_eq!(field.name, "hello");
393    }
394
395    #[test]
396    fn test_modify_updates_already_set_field() {
397        let mut field = MessageField::some(Inner {
398            value: 1,
399            name: "original".into(),
400        });
401        field.modify(|inner| {
402            inner.value = 99;
403        });
404        // Existing value is mutated in place, not reset to default.
405        assert_eq!(field.value, 99);
406        assert_eq!(field.name, "original");
407    }
408
409    #[test]
410    fn test_modify_multiple_fields_in_one_call() {
411        // Demonstrates the primary motivation: one initialization, many assignments.
412        let mut field: MessageField<Inner> = MessageField::none();
413        field.modify(|inner| {
414            inner.value = 10;
415            inner.name = "multi".into();
416        });
417        assert_eq!(field.value, 10);
418        assert_eq!(field.name, "multi");
419    }
420
421    #[test]
422    fn test_modify_noop_still_initializes_unset_field() {
423        // Even a no-op closure causes the field to become set (to the default).
424        let mut field: MessageField<Inner> = MessageField::none();
425        field.modify(|_| {});
426        assert!(field.is_set());
427        assert_eq!(field.value, 0);
428        assert_eq!(field.name, "");
429    }
430
431    #[test]
432    fn test_modify_closure_can_move_captured_values() {
433        // Verifies that the FnOnce bound is in effect: a closure that moves a
434        // captured value (String) into the field compiles and works correctly.
435        let mut field: MessageField<Inner> = MessageField::none();
436        let name = alloc::string::String::from("moved");
437        field.modify(|inner| {
438            inner.name = name; // moves `name` -- only valid with FnOnce
439        });
440        assert_eq!(field.name, "moved");
441    }
442
443    #[cfg(feature = "json")]
444    mod serde_tests {
445        use super::*;
446
447        #[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
448        struct Msg {
449            value: i32,
450        }
451
452        #[test]
453        fn unset_serializes_as_null() {
454            let f: MessageField<Msg> = MessageField::none();
455            assert_eq!(serde_json::to_string(&f).unwrap(), "null");
456        }
457
458        #[test]
459        fn set_serializes_as_inner_json() {
460            let f = MessageField::some(Msg { value: 42 });
461            let json = serde_json::to_string(&f).unwrap();
462            assert_eq!(json, r#"{"value":42}"#);
463        }
464
465        #[test]
466        fn null_deserializes_as_unset() {
467            let f: MessageField<Msg> = serde_json::from_str("null").unwrap();
468            assert!(f.is_unset());
469        }
470
471        #[test]
472        fn object_deserializes_as_set() {
473            let f: MessageField<Msg> = serde_json::from_str(r#"{"value":7}"#).unwrap();
474            assert!(f.is_set());
475            assert_eq!(f.as_option().unwrap().value, 7);
476        }
477
478        #[test]
479        fn round_trip_set_field() {
480            let original = MessageField::some(Msg { value: 99 });
481            let json = serde_json::to_string(&original).unwrap();
482            let recovered: MessageField<Msg> = serde_json::from_str(&json).unwrap();
483            assert_eq!(
484                original.as_option().unwrap().value,
485                recovered.as_option().unwrap().value
486            );
487        }
488    }
489
490    #[test]
491    fn test_into_option_unboxes() {
492        let field = MessageField::some(Inner {
493            value: 5,
494            name: "x".into(),
495        });
496        // Type annotation asserts this is Option<Inner>, not Option<Box<Inner>>.
497        let opt: Option<Inner> = field.into_option();
498        assert_eq!(opt.unwrap().value, 5);
499
500        let field: MessageField<Inner> = MessageField::none();
501        assert!(field.into_option().is_none());
502    }
503
504    #[test]
505    fn test_ok_or() {
506        let set = MessageField::some(Inner {
507            value: 1,
508            name: "set".into(),
509        });
510        let r: Result<Inner, &str> = set.ok_or("missing");
511        assert_eq!(r.unwrap().value, 1);
512
513        let unset: MessageField<Inner> = MessageField::none();
514        assert_eq!(unset.ok_or("missing"), Err("missing"));
515    }
516
517    #[test]
518    fn test_ok_or_else() {
519        let set = MessageField::some(Inner {
520            value: 2,
521            name: "set".into(),
522        });
523        assert_eq!(set.ok_or_else(|| "unreachable").unwrap().value, 2);
524
525        let unset: MessageField<Inner> = MessageField::none();
526        assert_eq!(unset.ok_or_else(|| "missing"), Err("missing"));
527    }
528
529    #[test]
530    fn test_ok_or_else_closure_not_called_when_set() {
531        let set = MessageField::some(Inner::default());
532        let _ = set.ok_or_else(|| -> &str { panic!("closure must not run") });
533    }
534
535    #[test]
536    fn test_ok_or_else_partial_move() {
537        // The motivating pattern: destructure several required fields out of
538        // an owned request struct, one ok_or_else per field. Each is a partial
539        // move; the remaining fields stay accessible.
540        #[derive(Default)]
541        struct Request {
542            a: MessageField<Inner>,
543            b: MessageField<Inner>,
544        }
545        let req = Request {
546            a: MessageField::some(Inner {
547                value: 1,
548                ..Default::default()
549            }),
550            b: MessageField::some(Inner {
551                value: 2,
552                ..Default::default()
553            }),
554        };
555        let a = req.a.ok_or_else(|| "missing a").unwrap();
556        let b = req.b.ok_or_else(|| "missing b").unwrap();
557        assert_eq!(a.value, 1);
558        assert_eq!(b.value, 2);
559    }
560
561    #[test]
562    fn test_from_conversions() {
563        let field: MessageField<Inner> = Inner {
564            value: 1,
565            name: "from".into(),
566        }
567        .into();
568        assert!(field.is_set());
569
570        let field: MessageField<Inner> = None.into();
571        assert!(field.is_unset());
572
573        let field: MessageField<Inner> = Some(Inner {
574            value: 2,
575            name: "some".into(),
576        })
577        .into();
578        assert!(field.is_set());
579    }
580}