| // Protocol Buffers - Google's data interchange format | |
| // Copyright 2023 Google LLC. All rights reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file or at | |
| // https://developers.google.com/open-source/licenses/bsd | |
| //! Operating on borrowed data owned by a message is a central concept in | |
| //! Protobuf (and Rust in general). The way this is normally accomplished in | |
| //! Rust is to pass around references and operate on those. Unfortunately, | |
| //! references come with two major drawbacks: | |
| //! | |
| //! * We must store the value somewhere in the memory to create a reference to it. The value must be | |
| //! readable by a single load. However for Protobuf fields it happens that the actual memory | |
| //! representation of a value differs from what users expect and it is an implementation detail | |
| //! that can change as more optimizations are implemented. For example, rarely accessed `int64` | |
| //! fields can be represented in a packed format with 32 bits for the value in the common case. | |
| //! Or, a single logical value can be spread across multiple memory locations. For example, | |
| //! presence information for all the fields in a protobuf message is centralized in a bitset. | |
| //! * We cannot store extra data on the reference that might be necessary for correctly manipulating | |
| //! it (and custom-metadata DSTs do not exist yet in Rust). Concretely, messages, string, bytes, | |
| //! and repeated fields in UPB need to carry around an arena parameter separate from the data | |
| //! pointer to enable mutation (for example adding an element to a repeated field) or potentially | |
| //! to enable optimizations (for example referencing a string value using a Cord-like type instead | |
| //! of copying it if the source and target messages are on the same arena already). Mutable | |
| //! references to messages have one additional drawback: Rust allows users to indiscriminately run | |
| //! a bytewise swap() on mutable references, which could result in pointers to the wrong arena | |
| //! winding up on a message. For example, imagine swapping a submessage across two root messages | |
| //! allocated on distinct arenas A and B; after the swap, the message allocated in A may contain | |
| //! pointers from B by way of the submessage, because the swap does not know to fix up those | |
| //! pointers as needed. The C++ API uses message-owned arenas, and this ends up resembling | |
| //! self-referential types, which need `Pin` in order to be sound. However, `Pin` has much | |
| //! stronger guarantees than we need to uphold. | |
| //! | |
| //! These drawbacks put the "idiomatic Rust" goal in conflict with the | |
| //! "performance", "evolvability", and "safety" goals. Given the project design | |
| //! priorities we decided to not use plain Rust references. Instead, we | |
| //! 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, SealedInternal}; | |
| /// NOTE: This type is primarily an implementation detail in support of trait resolution, and | |
| /// application code should very rarely write this type. | |
| /// | |
| /// An owned Protobuf entity or field type that can be accessed through reference-like proxies. | |
| /// | |
| /// In standard Rust, shared and exclusive access to borrowed data is provided via native | |
| /// references (`&T` and `&mut T`). However, standard references don't provide sufficient power | |
| /// to hide implementation details that Protobuf wants to take advantage of: for example, handing | |
| /// out `&mut` always allows for `std::mem::swap`, which precludes certain optimizations across | |
| /// parenting relationships. It also prevents optimizations like root messages and child messages | |
| /// of the same type having different layouts. | |
| /// | |
| /// To provide safe, ergonomic, and zero-cost or low-cost access across these representations, | |
| /// Protobuf uses "proxy" types: | |
| /// - [`View<'msg, T>`](View): A proxy type that provides shared, read-only access (analogous to | |
| /// `&'msg T`). | |
| /// - [`Mut<'msg, T>`](Mut): A proxy type that provides exclusive mutable access (analogous to | |
| /// `&'msg mut T`). | |
| /// | |
| /// An implementor of `ProtoObject` represents the *owned* target type (for example, a generated | |
| /// message struct `MyMessage`, primitive types like `i32`, `Repeated<T>`, `Map<K, V>`, | |
| /// `ProtoBytes`, or `ProtoString`). It is **not** the proxy itself. | |
| /// | |
| /// # Writing User Code | |
| /// | |
| /// In general, application code should rarely ever need to write the type `ProtoObject`. | |
| /// | |
| /// - **Concrete usage**: Work directly with the owned message types (e.g. `MyMessage`), concrete | |
| /// view types (e.g. `MyMessageView<'msg>`, `MyMessageMut<'msg>`), or the type aliases | |
| /// [`View<'msg, T>`](View) and [`Mut<'msg, T>`](Mut). | |
| /// - **Generic functions**: When writing functions that operate generically on messages or borrows | |
| /// of messages, prefer higher-level traits such as [`Message`](crate::Message), [`AsView`], | |
| /// [`IntoView`], [`AsMut`], or [`IntoMut`]. For example: ```ignore fn process_message(msg: impl | |
| /// AsView<Proxied = MyMessage>) { let view = msg.as_view(); // ... } ``` | |
| /// | |
| /// `ProtoObject` is primarily a foundational plumbing trait connecting owned types with their | |
| /// associated proxy representations for the Protobuf runtime and code generator. | |
| pub trait ProtoObject: SealedInternal + AsView<Proxied = Self> + Sized + 'static { | |
| /// The proxy type that provides shared access to a `T`, like a `&'msg T`. | |
| /// | |
| /// Most code should use the type alias [`View`]. | |
| type View<'msg>: AsView<Proxied = Self> + IntoView<'msg>; | |
| } | |
| /// Deprecated alias for [`ProtoObject`]. | |
| #[deprecated(note = "Use `ProtoObject` instead.")] | |
| pub use self::ProtoObject as Proxied; | |
| /// NOTE: This type is primarily an implementation detail in support of trait resolution, and | |
| /// application code should very rarely write this type. | |
| /// | |
| /// A [`ProtoObject`] that can also be accessed mutably through a reference-like proxy. | |
| /// | |
| /// An instance of a `MutProtoObject` can be accessed mutably via `MutProtoObject::Mut` | |
| /// and immutably via `ProtoObject::View`. | |
| /// | |
| /// `MutProtoObject` is implemented by message, map and repeated field types. | |
| pub trait MutProtoObject: | |
| SealedInternal + ProtoObject + AsMut<MutProxied = Self> + 'static | |
| { | |
| /// The proxy type that provides exclusive mutable access to a `T`, like a | |
| /// `&'msg mut T`. | |
| /// | |
| /// Most code should use the type alias [`Mut`]. | |
| type Mut<'msg>: AsMut<MutProxied = Self> + IntoMut<'msg> + IntoView<'msg>; | |
| } | |
| /// Deprecated alias for [`MutProtoObject`]. | |
| #[deprecated(note = "Use `MutProtoObject` instead.")] | |
| pub use self::MutProtoObject as MutProxied; | |
| /// A proxy type that provides shared access to a `T`, like a `&'msg T`. | |
| /// | |
| /// This is more concise than fully spelling the associated type. | |
| #[allow(dead_code)] | |
| pub type View<'msg, T> = <T as ProtoObject>::View<'msg>; | |
| /// A proxy type that provides exclusive mutable access to a `T`, like a | |
| /// `&'msg mut T`. | |
| /// | |
| /// This is more concise than fully spelling the associated type. | |
| #[allow(dead_code)] | |
| pub type Mut<'msg, T> = <T as MutProtoObject>::Mut<'msg>; | |
| /// Used to semantically do a cheap "to-reference" conversion. This is | |
| /// implemented on both owned `ProtoObject` types as well as view and mut proxy | |
| /// types. | |
| /// | |
| /// On a view proxy this will behave as a reborrow into a shorter lifetime. | |
| #[diagnostic::on_unimplemented( | |
| message = "the trait `AsView` is not implemented for `{Self}`", | |
| note = "consider calling `.as_view()`, or changing the fn to accept \ | |
| `impl AsView<Proxied = T>`" | |
| )] | |
| pub trait AsView: SealedInternal { | |
| type Proxied: ProtoObject; | |
| /// Converts a borrow into a `View` with the lifetime of that borrow. | |
| /// | |
| /// In non-generic code we don't need to use `as_view` because the proxy | |
| /// types are covariant over `'msg`. However, generic code conservatively | |
| /// treats `'msg` as [invariant], therefore we need to call | |
| /// `as_view` to explicitly perform the operation that in concrete code | |
| /// coercion would perform implicitly. | |
| /// | |
| /// For example, the call to `.as_view()` in the following snippet | |
| /// wouldn't be necessary in concrete code: | |
| /// ```ignore | |
| /// fn reborrow<'a, 'b, T>(x: &'b View<'a, T>) -> View<'b, T> | |
| /// where 'a: 'b, T: ProtoObject | |
| /// { | |
| /// x.as_view() | |
| /// } | |
| /// ``` | |
| /// | |
| /// [invariant]: https://doc.rust-lang.org/nomicon/subtyping.html#variance | |
| fn as_view(&self) -> View<'_, Self::Proxied>; | |
| } | |
| impl<T: ProtoObject> AsView for &T { | |
| type Proxied = T::Proxied; | |
| fn as_view(&self) -> View<'_, Self::Proxied> { | |
| (**self).as_view() | |
| } | |
| } | |
| impl<T: ProtoObject> AsView for &mut T { | |
| type Proxied = T::Proxied; | |
| fn as_view(&self) -> View<'_, Self::Proxied> { | |
| (**self).as_view() | |
| } | |
| } | |
| /// Used to turn another 'borrow' into a view proxy. | |
| /// | |
| /// On a mut proxy this borrows to a View (semantically matching turning a `&mut | |
| /// T` into a `&T`). | |
| /// | |
| /// On a view proxy this will behave as a reborrow into a shorter lifetime | |
| /// (semantically matching a `&'a T` into a `&'b T` where `'a: 'b`). | |
| #[diagnostic::on_unimplemented( | |
| message = "the trait `IntoView` is not implemented for `{Self}` (consider calling `.as_view()` \ | |
| or borrowing)", | |
| note = "consider calling `.as_view()` or `.into_view()`" | |
| )] | |
| pub trait IntoView<'msg>: SealedInternal + 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 | |
| /// types are covariant over `'msg`. However, generic code conservatively | |
| /// treats `'msg` as [invariant], therefore we need to call | |
| /// `into_view` to explicitly perform the operation that in concrete | |
| /// code coercion would perform implicitly. | |
| /// | |
| /// ```ignore | |
| /// fn reborrow_generic_view_into_view<'a, 'b, T>( | |
| /// x: View<'a, T>, | |
| /// y: View<'b, T>, | |
| /// ) -> [View<'b, T>; 2] | |
| /// where | |
| /// T: MutProtoObject, | |
| /// 'a: 'b, | |
| /// { | |
| /// // `[x, y]` fails to compile because `'a` is not the same as `'b` and the `View` | |
| /// // lifetime parameter is (conservatively) invariant. | |
| /// // `[x.as_view(), y]` fails because that borrow cannot outlive `'b`. | |
| /// [x.into_view(), y] | |
| /// } | |
| /// ``` | |
| /// | |
| /// [invariant]: https://doc.rust-lang.org/nomicon/subtyping.html#variance | |
| fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied> | |
| where | |
| 'msg: 'shorter; | |
| } | |
| impl<'msg, T: ProtoObject> IntoView<'msg> for &'msg T { | |
| fn into_view<'shorter>(self) -> View<'shorter, T> | |
| where | |
| 'msg: 'shorter, | |
| { | |
| (*self).as_view() | |
| } | |
| } | |
| impl<'msg, T: ProtoObject> IntoView<'msg> for &'msg mut T { | |
| fn into_view<'shorter>(self) -> View<'shorter, T> | |
| where | |
| 'msg: 'shorter, | |
| { | |
| (*self).as_view() | |
| } | |
| } | |
| /// Used to semantically do a cheap "to-mut-reference" conversion. This is | |
| /// implemented on both owned `ProtoObject` types as well as mut proxy types. | |
| /// | |
| /// On a mut proxy this will behave as a reborrow into a shorter lifetime. | |
| #[diagnostic::on_unimplemented( | |
| message = "the trait `AsMut` is not implemented for `{Self}`", | |
| note = "consider calling `.as_mut()`, or changing the fn to accept \ | |
| `impl AsMut<MutProxied = T>`" | |
| )] | |
| pub trait AsMut: SealedInternal + AsView<Proxied = Self::MutProxied> { | |
| type MutProxied: MutProtoObject; | |
| /// Converts a borrow into a `Mut` with the lifetime of that borrow. | |
| fn as_mut(&mut self) -> Mut<'_, Self::MutProxied>; | |
| } | |
| impl<T: MutProtoObject> AsMut for &mut T { | |
| type MutProxied = T::MutProxied; | |
| fn as_mut(&mut self) -> Mut<'_, Self::MutProxied> { | |
| (*self).as_mut() | |
| } | |
| } | |
| /// Used to turn another 'borrow' into a mut proxy. | |
| /// | |
| /// On a mut proxy this will behave as a reborrow into a shorter lifetime | |
| /// (semantically matching a `&mut 'a T` into a `&mut 'b T` where `'a: 'b`). | |
| #[diagnostic::on_unimplemented( | |
| message = "the trait `IntoMut` is not implemented for `{Self}` (consider calling `.as_mut()` \ | |
| or mutably borrowing)", | |
| note = "consider calling `.as_mut()` or `.into_mut()`" | |
| )] | |
| pub trait IntoMut<'msg>: SealedInternal + 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 | |
| /// types are covariant over `'msg`. However, generic code conservatively | |
| /// treats `'msg` as [invariant], therefore we need to call | |
| /// `into_mut` to explicitly perform the operation that in concrete code | |
| /// coercion would perform implicitly. | |
| /// | |
| /// ```ignore | |
| /// fn reborrow_generic_mut_into_mut<'a, 'b, T>(x: Mut<'a, T>, y: Mut<'b, T>) -> [Mut<'b, T>; 2] | |
| /// where | |
| /// T: ProtoObject, | |
| /// 'a: 'b, | |
| /// { | |
| /// // `[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] | |
| /// } | |
| /// ``` | |
| /// | |
| /// [invariant]: https://doc.rust-lang.org/nomicon/subtyping.html#variance | |
| fn into_mut<'shorter>(self) -> Mut<'shorter, Self::MutProxied> | |
| where | |
| 'msg: 'shorter; | |
| } | |
| impl<'msg, T: MutProtoObject> IntoMut<'msg> for &'msg mut T { | |
| fn into_mut<'shorter>(self) -> Mut<'shorter, T> | |
| where | |
| 'msg: 'shorter, | |
| { | |
| (*self).as_mut() | |
| } | |
| } | |
| /// A value to `ProtoObject`-value conversion that consumes the input value. | |
| /// | |
| /// All setter functions accept types that implement `IntoProxied`. The purpose | |
| /// of `IntoProxied` is to allow setting arbitrary values on Protobuf fields | |
| /// with the minimal number of copies. | |
| /// | |
| /// This trait must not be implemented on types outside the Protobuf codegen and | |
| /// runtime. We expect it to change in backwards incompatible ways in the | |
| /// future. | |
| pub trait IntoProxied<T: ProtoObject> { | |
| #[doc(hidden)] | |
| fn into_proxied(self, _private: Private) -> T; | |
| } | |
| impl<T: ProtoObject> IntoProxied<T> for T { | |
| fn into_proxied(self, _private: Private) -> T { | |
| self | |
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| use googletest::prelude::*; | |
| #[derive(Debug, Default, PartialEq)] | |
| struct MyProxied { | |
| val: String, | |
| } | |
| impl MyProxied { | |
| fn as_view(&self) -> View<'_, Self> { | |
| MyProxiedView { my_proxied_ref: self } | |
| } | |
| fn as_mut(&mut self) -> Mut<'_, Self> { | |
| MyProxiedMut { my_proxied_ref: self } | |
| } | |
| } | |
| impl SealedInternal for MyProxied {} | |
| impl ProtoObject for MyProxied { | |
| type View<'msg> = MyProxiedView<'msg>; | |
| } | |
| #[gtest] | |
| #[allow(deprecated)] | |
| fn test_deprecated_proxied_alias() { | |
| fn check_proxied<T: Proxied>() {} | |
| check_proxied::<MyProxied>(); | |
| fn check_mut_proxied<T: MutProxied>() {} | |
| check_mut_proxied::<MyProxied>(); | |
| } | |
| impl AsView for MyProxied { | |
| type Proxied = Self; | |
| fn as_view(&self) -> MyProxiedView<'_> { | |
| self.as_view() | |
| } | |
| } | |
| impl MutProtoObject for MyProxied { | |
| type Mut<'msg> = MyProxiedMut<'msg>; | |
| } | |
| impl AsMut for MyProxied { | |
| type MutProxied = Self; | |
| fn as_mut(&mut self) -> MyProxiedMut<'_> { | |
| self.as_mut() | |
| } | |
| } | |
| #[derive(Debug, Clone, Copy)] | |
| struct MyProxiedView<'msg> { | |
| my_proxied_ref: &'msg MyProxied, | |
| } | |
| impl<'msg> SealedInternal for MyProxiedView<'msg> {} | |
| impl MyProxiedView<'_> { | |
| fn val(&self) -> &str { | |
| &self.my_proxied_ref.val | |
| } | |
| } | |
| impl<'msg> AsView for MyProxiedView<'msg> { | |
| type Proxied = MyProxied; | |
| fn as_view(&self) -> MyProxiedView<'msg> { | |
| *self | |
| } | |
| } | |
| impl<'msg> IntoView<'msg> for MyProxiedView<'msg> { | |
| fn into_view<'shorter>(self) -> MyProxiedView<'shorter> | |
| where | |
| 'msg: 'shorter, | |
| { | |
| self | |
| } | |
| } | |
| #[derive(Debug)] | |
| struct MyProxiedMut<'msg> { | |
| my_proxied_ref: &'msg mut MyProxied, | |
| } | |
| impl<'msg> SealedInternal for MyProxiedMut<'msg> {} | |
| impl<'msg> AsView for MyProxiedMut<'msg> { | |
| type Proxied = 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, | |
| { | |
| MyProxiedView { my_proxied_ref: self.my_proxied_ref } | |
| } | |
| } | |
| impl<'msg> AsMut for MyProxiedMut<'msg> { | |
| type MutProxied = MyProxied; | |
| fn as_mut(&mut self) -> MyProxiedMut<'_> { | |
| MyProxiedMut { my_proxied_ref: self.my_proxied_ref } | |
| } | |
| } | |
| impl<'msg> IntoMut<'msg> for MyProxiedMut<'msg> { | |
| fn into_mut<'shorter>(self) -> MyProxiedMut<'shorter> | |
| where | |
| 'msg: 'shorter, | |
| { | |
| self | |
| } | |
| } | |
| #[gtest] | |
| fn test_as_view() { | |
| let my_proxied = MyProxied { val: "Hello World".to_string() }; | |
| let my_view = my_proxied.as_view(); | |
| assert_that!(my_view.val(), eq(&my_proxied.val)); | |
| } | |
| fn reborrow_mut_into_view<'msg>(x: Mut<'msg, MyProxied>) -> View<'msg, MyProxied> { | |
| // x.as_view() fails to compile with: | |
| // `ERROR: attempt to return function-local borrowed content` | |
| x.into_view() // OK: we return the same lifetime as we got in. | |
| } | |
| #[gtest] | |
| fn test_mut_into_view() { | |
| let mut my_proxied = MyProxied { val: "Hello World".to_string() }; | |
| reborrow_mut_into_view(my_proxied.as_mut()); | |
| } | |
| fn require_unified_lifetimes<'msg>(_x: Mut<'msg, MyProxied>, _y: View<'msg, MyProxied>) {} | |
| #[gtest] | |
| fn test_require_unified_lifetimes() { | |
| let mut my_proxied = MyProxied { val: "Hello1".to_string() }; | |
| let my_mut = my_proxied.as_mut(); | |
| { | |
| let other_proxied = MyProxied { val: "Hello2".to_string() }; | |
| let other_view = other_proxied.as_view(); | |
| require_unified_lifetimes(my_mut, other_view); | |
| } | |
| } | |
| fn reborrow_generic_as_view<'a, 'b, T>( | |
| x: &'b mut Mut<'a, T>, | |
| y: &'b View<'a, T>, | |
| ) -> [View<'b, T>; 2] | |
| where | |
| T: MutProtoObject, | |
| 'a: 'b, | |
| { | |
| // `[x, y]` fails to compile because `'a` is not the same as `'b` and the `View` | |
| // lifetime parameter is (conservatively) invariant. | |
| [x.as_view(), y.as_view()] | |
| } | |
| #[gtest] | |
| fn test_reborrow_generic_as_view() { | |
| let mut my_proxied = MyProxied { val: "Hello1".to_string() }; | |
| let mut my_mut = my_proxied.as_mut(); | |
| let my_ref = &mut my_mut; | |
| { | |
| let other_proxied = MyProxied { val: "Hello2".to_string() }; | |
| let other_view = other_proxied.as_view(); | |
| reborrow_generic_as_view::<MyProxied>(my_ref, &other_view); | |
| } | |
| } | |
| fn reborrow_generic_view_into_view<'a, 'b, T>( | |
| x: View<'a, T>, | |
| y: View<'b, T>, | |
| ) -> [View<'b, T>; 2] | |
| where | |
| T: ProtoObject, | |
| 'a: 'b, | |
| { | |
| // `[x, y]` fails to compile because `'a` is not the same as `'b` and the `View` | |
| // lifetime parameter is (conservatively) invariant. | |
| // `[x.as_view(), y]` fails because that borrow cannot outlive `'b`. | |
| [x.into_view(), y] | |
| } | |
| #[gtest] | |
| fn test_reborrow_generic_into_view() { | |
| let my_proxied = MyProxied { val: "Hello1".to_string() }; | |
| let my_view = my_proxied.as_view(); | |
| { | |
| let other_proxied = MyProxied { val: "Hello2".to_string() }; | |
| let other_view = other_proxied.as_view(); | |
| reborrow_generic_view_into_view::<MyProxied>(my_view, other_view); | |
| } | |
| } | |
| fn reborrow_generic_mut_into_view<'a, 'b, T>(x: Mut<'a, T>, y: View<'b, T>) -> [View<'b, T>; 2] | |
| where | |
| T: MutProtoObject, | |
| 'a: 'b, | |
| { | |
| [x.into_view(), y] | |
| } | |
| #[gtest] | |
| fn test_reborrow_generic_mut_into_view() { | |
| let mut my_proxied = MyProxied { val: "Hello1".to_string() }; | |
| let my_mut = my_proxied.as_mut(); | |
| { | |
| let other_proxied = MyProxied { val: "Hello2".to_string() }; | |
| let other_view = other_proxied.as_view(); | |
| reborrow_generic_mut_into_view::<MyProxied>(my_mut, other_view); | |
| } | |
| } | |
| fn reborrow_generic_mut_into_mut<'a, 'b, T>(x: Mut<'a, T>, y: Mut<'b, T>) -> [Mut<'b, T>; 2] | |
| where | |
| T: MutProtoObject, | |
| 'a: 'b, | |
| { | |
| // `[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`. | |
| let tmp: Mut<'b, T> = x.into_mut(); | |
| [tmp, y] | |
| } | |
| #[gtest] | |
| fn test_reborrow_generic_mut_into_mut() { | |
| let mut my_proxied = MyProxied { val: "Hello1".to_string() }; | |
| let my_mut = my_proxied.as_mut(); | |
| { | |
| let mut other_proxied = MyProxied { val: "Hello2".to_string() }; | |
| let other_mut = other_proxied.as_mut(); | |
| // No need to reborrow, even though lifetime of &other_view is different | |
| // than the lifetiem of my_ref. Rust references are covariant over their | |
| // lifetime. | |
| reborrow_generic_mut_into_mut::<MyProxied>(my_mut, other_mut); | |
| } | |
| } | |
| // Functions written the way the `#[diagnostic::on_unimplemented]` notes suggest: accepting a | |
| // generic proxy bound rather than a concrete view or mut proxy. | |
| fn accepts_as_view(_: impl AsView<Proxied = MyProxied>) {} | |
| fn accepts_as_mut(_: impl AsMut<MutProxied = MyProxied>) {} | |
| fn accepts_into_view<'a>(_: impl IntoView<'a, Proxied = MyProxied>) {} | |
| fn accepts_into_mut<'a>(_: impl IntoMut<'a, MutProxied = MyProxied>) {} | |
| #[gtest] | |
| fn test_suggested_conversions_satisfy_proxy_bounds() { | |
| let mut my_proxied = MyProxied { val: "Hello".to_string() }; | |
| // Callers of an `impl AsView` / `impl AsMut` function don't need to write `.as_view()` or | |
| // `.as_mut()` at all; a plain borrow suffices. | |
| accepts_as_view(&my_proxied); | |
| accepts_as_mut(&mut my_proxied); | |
| // Explicitly converting, as the notes suggest at the call site, also satisfies the bounds. | |
| accepts_as_view(my_proxied.as_view()); | |
| accepts_as_mut(my_proxied.as_mut()); | |
| // A view is not itself `AsMut`, but reborrowing a mut proxy is. | |
| let mut my_mut = my_proxied.as_mut(); | |
| accepts_as_view(my_mut.as_view()); | |
| accepts_as_mut(my_mut.as_mut()); | |
| // The `IntoView` / `IntoMut` bounds additionally accept a borrow directly, which is what | |
| // rustc suggests when an owned message is passed to them. | |
| accepts_into_view(&my_proxied); | |
| accepts_into_mut(&mut my_proxied); | |
| accepts_into_view(my_proxied.as_view()); | |
| accepts_into_mut(my_proxied.as_mut()); | |
| } | |
| } |