diff --git a/rust/internal.rs b/rust/internal.rs index ae078490f6..a96437d828 100644 --- a/rust/internal.rs +++ b/rust/internal.rs @@ -34,6 +34,9 @@ use std::slice; +/// Used to protect internal-only items from being used accidentally. +pub struct Private; + /// Represents an ABI-stable version of `NonNull<[u8]>`/`string_view` (a /// borrowed slice of bytes) for FFI use only. /// diff --git a/rust/optional.rs b/rust/optional.rs index b5b4169760..5adab2791b 100644 --- a/rust/optional.rs +++ b/rust/optional.rs @@ -32,7 +32,8 @@ #![allow(dead_code)] #![allow(unused)] -use crate::{Mut, MutProxy, Proxied, View, ViewProxy}; +use crate::__internal::Private; +use crate::{Mut, MutProxy, Proxied, SettableValue, View, ViewProxy}; use std::convert::{AsMut, AsRef}; use std::fmt::{self, Debug}; @@ -118,8 +119,11 @@ impl<'msg, T: Proxied + ?Sized + 'msg> FieldEntry<'msg, T> { /// Sets the value of this field to `val`. /// /// Equivalent to `self.or_default().set(val)`. - pub fn set(&mut self, val: Todo) { - todo!("b/285308646: Requires a trait method") + pub fn set(&mut self, val: impl SettableValue) { + match self { + Optional::Set(x) => x.set(val), + Optional::Unset(x) => todo!(), + } } /// Clears the field; `is_set()` will return `false`. @@ -181,8 +185,8 @@ impl<'msg, T: Proxied + ?Sized + 'msg> PresentField<'msg, T> { self.into_view() } - pub fn set(&mut self, val: Todo) { - todo!("b/285308646: Requires a trait method") + pub fn set(&mut self, val: impl SettableValue) { + val.set_on(Private, self.as_mut()) } /// See [`FieldEntry::clear`]. @@ -253,7 +257,7 @@ impl<'msg, T: Proxied + ?Sized> AbsentField<'msg, T> { /// See [`FieldEntry::set`]. Note that this consumes and returns a /// `PresentField`. - pub fn set(self, val: Todo) -> PresentField<'msg, T> { + pub fn set(self, val: impl SettableValue) -> PresentField<'msg, T> { todo!("b/285308646: Requires a trait method") } diff --git a/rust/proxied.rs b/rust/proxied.rs index dd4d30f964..e8c16dfb5e 100644 --- a/rust/proxied.rs +++ b/rust/proxied.rs @@ -67,6 +67,7 @@ //! implemented the concept of "proxy" types. Proxy types are a reference-like //! indirection between the user and the internal memory representation. +use crate::__internal::Private; use std::fmt::Debug; use std::marker::{Send, Sync}; @@ -169,6 +170,13 @@ pub trait ViewProxy<'a>: 'a + Sized + Sync + Unpin + Sized + Debug { /// This trait is intentionally made non-object-safe to prevent a potential /// future incompatible change. pub trait MutProxy<'a>: ViewProxy<'a> { + /// Sets this field to the given `val`. + /// + /// Any borrowed data from `val` will be cloned. + fn set(&mut self, val: impl SettableValue) { + val.set_on(Private, self.as_mut()) + } + /// Converts a borrow into a `Mut` with the lifetime of that borrow. /// /// This function enables calling multiple methods consuming `self`, for @@ -211,11 +219,22 @@ pub trait MutProxy<'a>: ViewProxy<'a> { 'a: 'shorter; } +/// Values that can be used to set a field of `T`. +pub trait SettableValue +where + T: Proxied + ?Sized, +{ + /// Consumes `self` to set the given mutator to its value. + #[doc(hidden)] + fn set_on(self, _private: Private, mutator: Mut); +} + #[cfg(test)] mod tests { use super::*; + use std::borrow::Cow; - #[derive(Debug, PartialEq)] + #[derive(Debug, Default, PartialEq)] struct MyProxied { val: String, } @@ -266,12 +285,6 @@ mod tests { my_proxied_ref: &'a mut MyProxied, } - impl MyProxiedMut<'_> { - fn set_val(&mut self, new_val: String) { - self.my_proxied_ref.val = new_val; - } - } - impl<'a> ViewProxy<'a> for MyProxiedMut<'a> { type Proxied = MyProxied; @@ -299,6 +312,27 @@ mod tests { } } + impl SettableValue for String { + fn set_on(self, _private: Private, mutator: Mut) { + mutator.my_proxied_ref.val = self; + } + } + + impl SettableValue for &'_ str { + fn set_on(self, _private: Private, mutator: Mut) { + mutator.my_proxied_ref.val.replace_range(.., self); + } + } + + impl SettableValue for Cow<'_, str> { + fn set_on(self, _private: Private, mutator: Mut) { + match self { + Cow::Owned(x) => x.set_on(Private, mutator), + Cow::Borrowed(x) => x.set_on(Private, mutator), + } + } + } + #[test] fn test_as_view() { let my_proxied = MyProxied { val: "Hello World".to_string() }; @@ -313,7 +347,7 @@ mod tests { let mut my_proxied = MyProxied { val: "Hello World".to_string() }; let mut my_mut = my_proxied.as_mut(); - my_mut.set_val("Hello indeed".to_string()); + my_mut.set("Hello indeed".to_string()); let val_after_set = my_mut.as_view().val().to_string(); assert_eq!(my_proxied.val, val_after_set); @@ -443,4 +477,17 @@ mod tests { reborrow_generic_mut_into_mut::(my_mut, other_mut); } } + + #[test] + fn test_set() { + let mut my_proxied = MyProxied::default(); + my_proxied.as_mut().set("hello"); + assert_eq!(my_proxied.as_view().val(), "hello"); + + my_proxied.as_mut().set(String::from("hello2")); + assert_eq!(my_proxied.as_view().val(), "hello2"); + + my_proxied.as_mut().set(Cow::Borrowed("hello3")); + assert_eq!(my_proxied.as_view().val(), "hello3"); + } } diff --git a/rust/shared.rs b/rust/shared.rs index aab8693ebc..b27f36303a 100644 --- a/rust/shared.rs +++ b/rust/shared.rs @@ -47,7 +47,7 @@ mod optional; mod proxied; pub use optional::{AbsentField, FieldEntry, Optional, PresentField}; -pub use proxied::{Mut, MutProxy, Proxied, View, ViewProxy}; +pub use proxied::{Mut, MutProxy, Proxied, SettableValue, View, ViewProxy}; /// Everything in `__internal` is allowed to change without it being considered /// a breaking change for the protobuf library. Nothing in here should be