Skip to content

Commit

Permalink
Create AsView/IntoView/AsMut/IntoMut traits
Browse files Browse the repository at this point in the history
These 'verb' traits are more in line with our plans for the common message operations.

PiperOrigin-RevId: 655163895
  • Loading branch information
protobuf-github-bot authored and copybara-github committed Jul 23, 2024
1 parent be3d8cb commit 3c95fc8
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 103 deletions.
2 changes: 1 addition & 1 deletion rust/codegen_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub trait MessageView<'msg>: ViewProxy<'msg, Proxied = Self::Message>

/// A trait that all generated message muts implement.
pub trait MessageMut<'msg>:
MutProxy<'msg, Proxied = Self::Message>
MutProxy<'msg, MutProxied = Self::Message>
// Read traits:
+ Debug + Serialize
// Write traits:
Expand Down
35 changes: 25 additions & 10 deletions rust/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
// https://developers.google.com/open-source/licenses/bsd

use crate::{
IntoProxied, Mut, MutProxied, MutProxy, Proxied, Proxy, View, ViewProxy,
AsMut, AsView, IntoMut, IntoProxied, IntoView, Mut, MutProxied, MutProxy, Proxied, Proxy, View,
ViewProxy,
__internal::Private,
__runtime::{InnerMap, InnerMapMut, RawMap, RawMapIter},
};
Expand Down Expand Up @@ -112,14 +113,18 @@ impl<K: Proxied, V: ProxiedInMapValue<K>> MutProxied for Map<K, V> {
type Mut<'msg> = MapMut<'msg, K, V> where K: 'msg, V: 'msg;
}

impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> Proxy<'msg> for MapView<'msg, K, V> {
impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> Proxy<'msg> for MapView<'msg, K, V> {}

impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> AsView for MapView<'msg, K, V> {
type Proxied = Map<K, V>;

fn as_view(&self) -> View<'_, Self::Proxied> {
fn as_view(&self) -> MapView<'_, K, V> {
*self
}
}

fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied>
impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> IntoView<'msg> for MapView<'msg, K, V> {
fn into_view<'shorter>(self) -> MapView<'shorter, K, V>
where
'msg: 'shorter,
{
Expand All @@ -129,34 +134,44 @@ impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> Proxy<'msg> for MapView<'msg, K,

impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> ViewProxy<'msg> for MapView<'msg, K, V> {}

impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> Proxy<'msg> for MapMut<'msg, K, V> {
impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> Proxy<'msg> for MapMut<'msg, K, V> {}

impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> AsView for MapMut<'msg, K, V> {
type Proxied = Map<K, V>;

fn as_view(&self) -> View<'_, Self::Proxied> {
fn as_view(&self) -> MapView<'_, K, V> {
MapView { raw: self.inner.raw, _phantom: PhantomData }
}
}

fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied>
impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> IntoView<'msg> for MapMut<'msg, K, V> {
fn into_view<'shorter>(self) -> MapView<'shorter, K, V>
where
'msg: 'shorter,
{
MapView { raw: self.inner.raw, _phantom: PhantomData }
}
}

impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> MutProxy<'msg> for MapMut<'msg, K, V> {
fn as_mut(&mut self) -> Mut<'_, Self::Proxied> {
impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> AsMut for MapMut<'msg, K, V> {
type MutProxied = Map<K, V>;

fn as_mut(&mut self) -> MapMut<'_, K, V> {
MapMut { inner: self.inner, _phantom: PhantomData }
}
}

fn into_mut<'shorter>(self) -> Mut<'shorter, Self::Proxied>
impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> IntoMut<'msg> for MapMut<'msg, K, V> {
fn into_mut<'shorter>(self) -> MapMut<'shorter, K, V>
where
'msg: 'shorter,
{
MapMut { inner: self.inner, _phantom: PhantomData }
}
}

impl<'msg, K: Proxied, V: ProxiedInMapValue<K>> MutProxy<'msg> for MapMut<'msg, K, V> {}

impl<K, V> Map<K, V>
where
K: Proxied,
Expand Down
21 changes: 14 additions & 7 deletions rust/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
use crate::__internal::Private;
use crate::{IntoProxied, Proxied, Proxy, View, ViewProxy};
use crate::{AsView, IntoProxied, IntoView, Proxied, Proxy, ViewProxy};

macro_rules! impl_singular_primitives {
($($t:ty),*) => {
Expand All @@ -15,15 +15,22 @@ macro_rules! impl_singular_primitives {
}

impl<'msg> Proxy<'msg> for $t {
}

impl AsView for $t {
type Proxied = $t;

fn as_view(&self) -> View<'_, Self::Proxied> {
*self
}
fn as_view(&self) -> $t {
*self
}
}

fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied> {
self
}
impl<'msg> IntoView<'msg> for $t {
fn into_view<'shorter>(self) -> $t
where
'msg: 'shorter {
self
}
}

impl<'msg> ViewProxy<'msg> for $t {}
Expand Down
131 changes: 81 additions & 50 deletions rust/proxied.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ pub trait MutProxied: Proxied {
/// `&'msg mut T`.
///
/// Most code should use the type alias [`Mut`].
type Mut<'msg>: MutProxy<'msg, Proxied = Self>
type Mut<'msg>: MutProxy<'msg, MutProxied = Self>
where
Self: 'msg;
}
Expand All @@ -90,13 +90,13 @@ pub type View<'msg, T> = <T as Proxied>::View<'msg>;
#[allow(dead_code)]
pub type Mut<'msg, T> = <T as MutProxied>::Mut<'msg>;

/// Declares conversion operations common to all proxies (both views and mut
/// proxies).
/// Used to semantically do a cheap "to-reference" conversion. This is
/// implemented on both owned `Proxied` types as well as ViewProxy and MutProxy
/// types.
///
/// This trait is intentionally made non-object-safe to prevent a potential
/// future incompatible change.
pub trait Proxy<'msg>: 'msg + Sync + Unpin + Sized + Debug {
type Proxied: 'msg + Proxied;
/// On ViewProxy this will behave as a reborrow into a shorter lifetime.
pub trait AsView {
type Proxied: Proxied;

/// Converts a borrow into a `View` with the lifetime of that borrow.
///
Expand All @@ -118,7 +118,16 @@ pub trait Proxy<'msg>: 'msg + Sync + Unpin + Sized + Debug {
///
/// [invariant]: https://doc.rust-lang.org/nomicon/subtyping.html#variance
fn as_view(&self) -> View<'_, Self::Proxied>;
}

/// Used to turn another 'borrow' into a ViewProxy.
///
/// On a MutProxy this borrows to a View (semantically matching turning a `&mut
/// T` into a `&T`).
///
/// On a ViewProxy this will behave as a reborrow into a shorter lifetime
/// (semantically matching a `&'a T` into a `&'b T` where `'a: 'b`).
pub trait IntoView<'msg>: AsView {
/// Converts into a `View` with a potentially shorter lifetime.
///
/// In non-generic code we don't need to use `into_view` because the proxy
Expand Down Expand Up @@ -149,41 +158,22 @@ pub trait Proxy<'msg>: 'msg + Sync + Unpin + Sized + Debug {
'msg: 'shorter;
}

/// Declares conversion operations common to view proxies.
pub trait ViewProxy<'msg>: Proxy<'msg> + Copy + Send {}

/// Declares operations common to all mut proxies.
/// Used to semantically do a cheap "to-mut-reference" conversion. This is
/// implemented on both owned `Proxied` types as well as MutProxy types.
///
/// This trait is intentionally made non-object-safe to prevent a potential
/// future incompatible change.
pub trait MutProxy<'msg>: Proxy<'msg>
where
Self::Proxied: MutProxied,
{
/// Gets an immutable view of this field. This is shorthand for `as_view`.
///
/// This provides a shorter lifetime than `into_view` but can also be called
/// multiple times - if the result of `get` is not living long enough
/// for your use, use that instead.
fn get(&self) -> View<'_, Self::Proxied> {
self.as_view()
}
/// On MutProxy this will behave as a reborrow into a shorter lifetime.
pub trait AsMut: AsView<Proxied = Self::MutProxied> {
type MutProxied: MutProxied;

/// Converts a borrow into a `Mut` with the lifetime of that borrow.
///
/// This function enables calling multiple methods consuming `self`, for
/// example:
///
/// ```ignore
/// let mut sub: Mut<SubMsg> = msg.submsg_mut();
/// sub.as_mut().field_x_mut().set(10); // field_x_mut is fn(self)
/// sub.field_y_mut().set(20); // `sub` is now consumed
/// ```
///
/// `as_mut` is also useful in generic code to explicitly perform the
/// operation that in concrete code coercion would perform implicitly.
fn as_mut(&mut self) -> Mut<'_, Self::Proxied>;
fn as_mut(&mut self) -> Mut<'_, Self::MutProxied>;
}

/// Used to turn another 'borrow' into a MutProxy.
///
/// On a MutProxy this will behave as a reborrow into a shorter lifetime
/// (semantically matching a `&mut 'a T` into a `&mut 'b T` where `'a: 'b`).
pub trait IntoMut<'msg>: AsMut {
/// Converts into a `Mut` with a potentially shorter lifetime.
///
/// In non-generic code we don't need to use `into_mut` because the proxy
Expand All @@ -206,11 +196,36 @@ where
/// ```
///
/// [invariant]: https://doc.rust-lang.org/nomicon/subtyping.html#variance
fn into_mut<'shorter>(self) -> Mut<'shorter, Self::Proxied>
fn into_mut<'shorter>(self) -> Mut<'shorter, Self::MutProxied>
where
'msg: 'shorter;
}

/// Declares conversion operations common to all proxies (both views and mut
/// proxies).
///
/// This trait is intentionally made non-object-safe to prevent a potential
/// future incompatible change.
pub trait Proxy<'msg>: 'msg + IntoView<'msg> + Sync + Unpin + Sized + Debug {}

/// Declares conversion operations common to view proxies.
pub trait ViewProxy<'msg>: Proxy<'msg> + Copy + Send {}

/// Declares operations common to all mut proxies.
///
/// This trait is intentionally made non-object-safe to prevent a potential
/// future incompatible change.
pub trait MutProxy<'msg>: Proxy<'msg> + AsMut + IntoMut<'msg> {
/// Gets an immutable view of this field. This is shorthand for `as_view`.
///
/// This provides a shorter lifetime than `into_view` but can also be called
/// multiple times - if the result of `get` is not living long enough
/// for your use, use that instead.
fn get(&self) -> View<'_, Self::Proxied> {
self.as_view()
}
}

/// A value to `Proxied`-value conversion that consumes the input value.
///
/// All setter functions accept types that implement `IntoProxied`. The purpose
Expand Down Expand Up @@ -263,34 +278,43 @@ mod tests {
}
}

impl<'msg> Proxy<'msg> for MyProxiedView<'msg> {
impl<'msg> Proxy<'msg> for MyProxiedView<'msg> {}

impl<'msg> ViewProxy<'msg> for MyProxiedView<'msg> {}

impl<'msg> AsView for MyProxiedView<'msg> {
type Proxied = MyProxied;

fn as_view(&self) -> View<'msg, MyProxied> {
fn as_view(&self) -> MyProxiedView<'msg> {
*self
}
}

fn into_view<'shorter>(self) -> View<'shorter, MyProxied>
impl<'msg> IntoView<'msg> for MyProxiedView<'msg> {
fn into_view<'shorter>(self) -> MyProxiedView<'shorter>
where
'msg: 'shorter,
{
self
}
}

impl<'msg> ViewProxy<'msg> for MyProxiedView<'msg> {}

#[derive(Debug)]
struct MyProxiedMut<'msg> {
my_proxied_ref: &'msg mut MyProxied,
}

impl<'msg> Proxy<'msg> for MyProxiedMut<'msg> {
impl<'msg> Proxy<'msg> for MyProxiedMut<'msg> {}

impl<'msg> AsView for MyProxiedMut<'msg> {
type Proxied = MyProxied;

fn as_view(&self) -> View<'_, MyProxied> {
fn as_view(&self) -> MyProxiedView<'_> {
MyProxiedView { my_proxied_ref: self.my_proxied_ref }
}
}

impl<'msg> IntoView<'msg> for MyProxiedMut<'msg> {
fn into_view<'shorter>(self) -> View<'shorter, MyProxied>
where
'msg: 'shorter,
Expand All @@ -299,19 +323,25 @@ mod tests {
}
}

impl<'msg> MutProxy<'msg> for MyProxiedMut<'msg> {
fn as_mut(&mut self) -> Mut<'_, MyProxied> {
impl<'msg> AsMut for MyProxiedMut<'msg> {
type MutProxied = MyProxied;

fn as_mut(&mut self) -> MyProxiedMut<'_> {
MyProxiedMut { my_proxied_ref: self.my_proxied_ref }
}
}

fn into_mut<'shorter>(self) -> Mut<'shorter, MyProxied>
impl<'msg> IntoMut<'msg> for MyProxiedMut<'msg> {
fn into_mut<'shorter>(self) -> MyProxiedMut<'shorter>
where
'msg: 'shorter,
{
self
}
}

impl<'msg> MutProxy<'msg> for MyProxiedMut<'msg> {}

#[googletest::test]
fn test_as_view() {
let my_proxied = MyProxied { val: "Hello World".to_string() };
Expand Down Expand Up @@ -427,7 +457,8 @@ mod tests {
// `[x, y]` fails to compile because `'a` is not the same as `'b` and the `Mut`
// lifetime parameter is (conservatively) invariant.
// `[x.as_mut(), y]` fails because that borrow cannot outlive `'b`.
[x.into_mut(), y]
let tmp: Mut<'b, T> = x.into_mut();
[tmp, y]
}

#[googletest::test]
Expand Down
Loading

0 comments on commit 3c95fc8

Please sign in to comment.