Add SettableValue for generic field setting
This is a prerequisite for optional types to have proper setters.
PiperOrigin-RevId: 542588427
diff --git a/rust/internal.rs b/rust/internal.rs
index ae07849..a96437d 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 b5b4169..5adab27 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 @@
/// 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<T>) {
+ match self {
+ Optional::Set(x) => x.set(val),
+ Optional::Unset(x) => todo!(),
+ }
}
/// Clears the field; `is_set()` will return `false`.
@@ -181,8 +185,8 @@
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<T>) {
+ val.set_on(Private, self.as_mut())
}
/// See [`FieldEntry::clear`].
@@ -253,7 +257,7 @@
/// 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<T>) -> PresentField<'msg, T> {
todo!("b/285308646: Requires a trait method")
}
diff --git a/rust/proxied.rs b/rust/proxied.rs
index dd4d30f..e8c16df 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 @@
/// 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<Self::Proxied>) {
+ 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 @@
'a: 'shorter;
}
+/// Values that can be used to set a field of `T`.
+pub trait SettableValue<T>
+where
+ T: Proxied + ?Sized,
+{
+ /// Consumes `self` to set the given mutator to its value.
+ #[doc(hidden)]
+ fn set_on(self, _private: Private, mutator: Mut<T>);
+}
+
#[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 @@
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 @@
}
}
+ impl SettableValue<MyProxied> for String {
+ fn set_on(self, _private: Private, mutator: Mut<MyProxied>) {
+ mutator.my_proxied_ref.val = self;
+ }
+ }
+
+ impl SettableValue<MyProxied> for &'_ str {
+ fn set_on(self, _private: Private, mutator: Mut<MyProxied>) {
+ mutator.my_proxied_ref.val.replace_range(.., self);
+ }
+ }
+
+ impl SettableValue<MyProxied> for Cow<'_, str> {
+ fn set_on(self, _private: Private, mutator: Mut<MyProxied>) {
+ 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 @@
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 @@
reborrow_generic_mut_into_mut::<MyProxied>(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 aab8693..b27f363 100644
--- a/rust/shared.rs
+++ b/rust/shared.rs
@@ -47,7 +47,7 @@
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