1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2023 Google LLC. All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file or at 6 // https://developers.google.com/open-source/licenses/bsd 7 8 //! Operating on borrowed data owned by a message is a central concept in 9 //! Protobuf (and Rust in general). The way this is normally accomplished in 10 //! Rust is to pass around references and operate on those. Unfortunately, 11 //! references come with two major drawbacks: 12 //! 13 //! * We must store the value somewhere in the memory to create a reference to 14 //! it. The value must be readable by a single load. However for Protobuf 15 //! fields it happens that the actual memory representation of a value differs 16 //! from what users expect and it is an implementation detail that can change 17 //! as more optimizations are implemented. For example, rarely accessed 18 //! `int64` fields can be represented in a packed format with 32 bits for the 19 //! value in the common case. Or, a single logical value can be spread across 20 //! multiple memory locations. For example, presence information for all the 21 //! fields in a protobuf message is centralized in a bitset. 22 //! * We cannot store extra data on the reference that might be necessary for 23 //! correctly manipulating it (and custom-metadata DSTs do not exist yet in 24 //! Rust). Concretely, messages, string, bytes, and repeated fields in UPB 25 //! need to carry around an arena parameter separate from the data pointer to 26 //! enable mutation (for example adding an element to a repeated field) or 27 //! potentially to enable optimizations (for example referencing a string 28 //! value using a Cord-like type instead of copying it if the source and 29 //! target messages are on the same arena already). Mutable references to 30 //! messages have one additional drawback: Rust allows users to 31 //! indiscriminately run a bytewise swap() on mutable references, which could 32 //! result in pointers to the wrong arena winding up on a message. For 33 //! example, imagine swapping a submessage across two root messages allocated 34 //! on distinct arenas A and B; after the swap, the message allocated in A may 35 //! contain pointers from B by way of the submessage, because the swap does 36 //! not know to fix up those pointers as needed. The C++ API uses 37 //! message-owned arenas, and this ends up resembling self-referential types, 38 //! which need `Pin` in order to be sound. However, `Pin` has much stronger 39 //! guarantees than we need to uphold. 40 //! 41 //! These drawbacks put the "idiomatic Rust" goal in conflict with the 42 //! "performance", "evolvability", and "safety" goals. Given the project design 43 //! priorities we decided to not use plain Rust references. Instead, we 44 //! implemented the concept of "proxy" types. Proxy types are a reference-like 45 //! indirection between the user and the internal memory representation. 46 47 use crate::__internal::{Private, SealedInternal}; 48 use std::fmt::Debug; 49 50 /// A type that can be accessed through a reference-like proxy. 51 /// 52 /// An instance of a `Proxied` can be accessed immutably via `Proxied::View`. 53 /// 54 /// All Protobuf field types implement `Proxied`. 55 pub trait Proxied: SealedInternal + AsView<Proxied = Self> + Sized { 56 /// The proxy type that provides shared access to a `T`, like a `&'msg T`. 57 /// 58 /// Most code should use the type alias [`View`]. 59 type View<'msg>: ViewProxy<'msg, Proxied = Self> 60 where 61 Self: 'msg; 62 } 63 64 /// A type that can be be accessed through a reference-like proxy. 65 /// 66 /// An instance of a `MutProxied` can be accessed mutably via `MutProxied::Mut` 67 /// and immutably via `MutProxied::View`. 68 /// 69 /// `MutProxied` is implemented by message, map and repeated field types. 70 pub trait MutProxied: SealedInternal + Proxied + AsMut<MutProxied = Self> { 71 /// The proxy type that provides exclusive mutable access to a `T`, like a 72 /// `&'msg mut T`. 73 /// 74 /// Most code should use the type alias [`Mut`]. 75 type Mut<'msg>: MutProxy<'msg, MutProxied = Self> 76 where 77 Self: 'msg; 78 } 79 80 /// A proxy type that provides shared access to a `T`, like a `&'msg T`. 81 /// 82 /// This is more concise than fully spelling the associated type. 83 #[allow(dead_code)] 84 pub type View<'msg, T> = <T as Proxied>::View<'msg>; 85 86 /// A proxy type that provides exclusive mutable access to a `T`, like a 87 /// `&'msg mut T`. 88 /// 89 /// This is more concise than fully spelling the associated type. 90 #[allow(dead_code)] 91 pub type Mut<'msg, T> = <T as MutProxied>::Mut<'msg>; 92 93 /// Used to semantically do a cheap "to-reference" conversion. This is 94 /// implemented on both owned `Proxied` types as well as ViewProxy and MutProxy 95 /// types. 96 /// 97 /// On ViewProxy this will behave as a reborrow into a shorter lifetime. 98 pub trait AsView: SealedInternal { 99 type Proxied: Proxied; 100 101 /// Converts a borrow into a `View` with the lifetime of that borrow. 102 /// 103 /// In non-generic code we don't need to use `as_view` because the proxy 104 /// types are covariant over `'msg`. However, generic code conservatively 105 /// treats `'msg` as [invariant], therefore we need to call 106 /// `as_view` to explicitly perform the operation that in concrete code 107 /// coercion would perform implicitly. 108 /// 109 /// For example, the call to `.as_view()` in the following snippet 110 /// wouldn't be necessary in concrete code: 111 /// ```ignore 112 /// fn reborrow<'a, 'b, T>(x: &'b View<'a, T>) -> View<'b, T> 113 /// where 'a: 'b, T: Proxied 114 /// { 115 /// x.as_view() 116 /// } 117 /// ``` 118 /// 119 /// [invariant]: https://doc.rust-lang.org/nomicon/subtyping.html#variance as_view(&self) -> View<'_, Self::Proxied>120 fn as_view(&self) -> View<'_, Self::Proxied>; 121 } 122 123 /// Used to turn another 'borrow' into a ViewProxy. 124 /// 125 /// On a MutProxy this borrows to a View (semantically matching turning a `&mut 126 /// T` into a `&T`). 127 /// 128 /// On a ViewProxy this will behave as a reborrow into a shorter lifetime 129 /// (semantically matching a `&'a T` into a `&'b T` where `'a: 'b`). 130 pub trait IntoView<'msg>: SealedInternal + AsView { 131 /// Converts into a `View` with a potentially shorter lifetime. 132 /// 133 /// In non-generic code we don't need to use `into_view` because the proxy 134 /// types are covariant over `'msg`. However, generic code conservatively 135 /// treats `'msg` as [invariant], therefore we need to call 136 /// `into_view` to explicitly perform the operation that in concrete 137 /// code coercion would perform implicitly. 138 /// 139 /// ```ignore 140 /// fn reborrow_generic_view_into_view<'a, 'b, T>( 141 /// x: View<'a, T>, 142 /// y: View<'b, T>, 143 /// ) -> [View<'b, T>; 2] 144 /// where 145 /// T: MutProxied, 146 /// 'a: 'b, 147 /// { 148 /// // `[x, y]` fails to compile because `'a` is not the same as `'b` and the `View` 149 /// // lifetime parameter is (conservatively) invariant. 150 /// // `[x.as_view(), y]` fails because that borrow cannot outlive `'b`. 151 /// [x.into_view(), y] 152 /// } 153 /// ``` 154 /// 155 /// [invariant]: https://doc.rust-lang.org/nomicon/subtyping.html#variance into_view<'shorter>(self) -> View<'shorter, Self::Proxied> where 'msg: 'shorter156 fn into_view<'shorter>(self) -> View<'shorter, Self::Proxied> 157 where 158 'msg: 'shorter; 159 } 160 161 /// Used to semantically do a cheap "to-mut-reference" conversion. This is 162 /// implemented on both owned `Proxied` types as well as MutProxy types. 163 /// 164 /// On MutProxy this will behave as a reborrow into a shorter lifetime. 165 pub trait AsMut: SealedInternal + AsView<Proxied = Self::MutProxied> { 166 type MutProxied: MutProxied; 167 168 /// Converts a borrow into a `Mut` with the lifetime of that borrow. as_mut(&mut self) -> Mut<'_, Self::MutProxied>169 fn as_mut(&mut self) -> Mut<'_, Self::MutProxied>; 170 } 171 172 /// Used to turn another 'borrow' into a MutProxy. 173 /// 174 /// On a MutProxy this will behave as a reborrow into a shorter lifetime 175 /// (semantically matching a `&mut 'a T` into a `&mut 'b T` where `'a: 'b`). 176 pub trait IntoMut<'msg>: SealedInternal + AsMut { 177 /// Converts into a `Mut` with a potentially shorter lifetime. 178 /// 179 /// In non-generic code we don't need to use `into_mut` because the proxy 180 /// types are covariant over `'msg`. However, generic code conservatively 181 /// treats `'msg` as [invariant], therefore we need to call 182 /// `into_mut` to explicitly perform the operation that in concrete code 183 /// coercion would perform implicitly. 184 /// 185 /// ```ignore 186 /// fn reborrow_generic_mut_into_mut<'a, 'b, T>(x: Mut<'a, T>, y: Mut<'b, T>) -> [Mut<'b, T>; 2] 187 /// where 188 /// T: Proxied, 189 /// 'a: 'b, 190 /// { 191 /// // `[x, y]` fails to compile because `'a` is not the same as `'b` and the `Mut` 192 /// // lifetime parameter is (conservatively) invariant. 193 /// // `[x.as_mut(), y]` fails because that borrow cannot outlive `'b`. 194 /// [x.into_mut(), y] 195 /// } 196 /// ``` 197 /// 198 /// [invariant]: https://doc.rust-lang.org/nomicon/subtyping.html#variance into_mut<'shorter>(self) -> Mut<'shorter, Self::MutProxied> where 'msg: 'shorter199 fn into_mut<'shorter>(self) -> Mut<'shorter, Self::MutProxied> 200 where 201 'msg: 'shorter; 202 } 203 204 /// Declares conversion operations common to all proxies (both views and mut 205 /// proxies). 206 /// 207 /// This trait is intentionally made non-object-safe to prevent a potential 208 /// future incompatible change. 209 pub trait Proxy<'msg>: 210 SealedInternal + 'msg + IntoView<'msg> + Sync + Unpin + Sized + Debug 211 { 212 } 213 214 /// Declares conversion operations common to view proxies. 215 pub trait ViewProxy<'msg>: SealedInternal + Proxy<'msg> + Send {} 216 217 /// Declares operations common to all mut proxies. 218 /// 219 /// This trait is intentionally made non-object-safe to prevent a potential 220 /// future incompatible change. 221 pub trait MutProxy<'msg>: SealedInternal + Proxy<'msg> + AsMut + IntoMut<'msg> { 222 /// Gets an immutable view of this field. This is shorthand for `as_view`. 223 /// 224 /// This provides a shorter lifetime than `into_view` but can also be called 225 /// multiple times - if the result of `get` is not living long enough 226 /// for your use, use that instead. get(&self) -> View<'_, Self::Proxied>227 fn get(&self) -> View<'_, Self::Proxied> { 228 self.as_view() 229 } 230 } 231 232 /// A value to `Proxied`-value conversion that consumes the input value. 233 /// 234 /// All setter functions accept types that implement `IntoProxied`. The purpose 235 /// of `IntoProxied` is to allow setting arbitrary values on Protobuf fields 236 /// with the minimal number of copies. 237 /// 238 /// This trait must not be implemented on types outside the Protobuf codegen and 239 /// runtime. We expect it to change in backwards incompatible ways in the 240 /// future. 241 pub trait IntoProxied<T: Proxied> { 242 #[doc(hidden)] into_proxied(self, _private: Private) -> T243 fn into_proxied(self, _private: Private) -> T; 244 } 245 246 impl<T: Proxied> IntoProxied<T> for T { into_proxied(self, _private: Private) -> T247 fn into_proxied(self, _private: Private) -> T { 248 self 249 } 250 } 251 252 #[cfg(test)] 253 mod tests { 254 use super::*; 255 use googletest::prelude::*; 256 257 #[derive(Debug, Default, PartialEq)] 258 struct MyProxied { 259 val: String, 260 } 261 262 impl MyProxied { as_view(&self) -> View<'_, Self>263 fn as_view(&self) -> View<'_, Self> { 264 MyProxiedView { my_proxied_ref: self } 265 } 266 as_mut(&mut self) -> Mut<'_, Self>267 fn as_mut(&mut self) -> Mut<'_, Self> { 268 MyProxiedMut { my_proxied_ref: self } 269 } 270 } 271 272 impl SealedInternal for MyProxied {} 273 274 impl Proxied for MyProxied { 275 type View<'msg> = MyProxiedView<'msg>; 276 } 277 278 impl AsView for MyProxied { 279 type Proxied = Self; as_view(&self) -> MyProxiedView<'_>280 fn as_view(&self) -> MyProxiedView<'_> { 281 self.as_view() 282 } 283 } 284 285 impl MutProxied for MyProxied { 286 type Mut<'msg> = MyProxiedMut<'msg>; 287 } 288 289 impl AsMut for MyProxied { 290 type MutProxied = Self; as_mut(&mut self) -> MyProxiedMut<'_>291 fn as_mut(&mut self) -> MyProxiedMut<'_> { 292 self.as_mut() 293 } 294 } 295 296 #[derive(Debug, Clone, Copy)] 297 struct MyProxiedView<'msg> { 298 my_proxied_ref: &'msg MyProxied, 299 } 300 301 impl<'msg> SealedInternal for MyProxiedView<'msg> {} 302 303 impl MyProxiedView<'_> { val(&self) -> &str304 fn val(&self) -> &str { 305 &self.my_proxied_ref.val 306 } 307 } 308 309 impl<'msg> Proxy<'msg> for MyProxiedView<'msg> {} 310 311 impl<'msg> ViewProxy<'msg> for MyProxiedView<'msg> {} 312 313 impl<'msg> AsView for MyProxiedView<'msg> { 314 type Proxied = MyProxied; 315 as_view(&self) -> MyProxiedView<'msg>316 fn as_view(&self) -> MyProxiedView<'msg> { 317 *self 318 } 319 } 320 321 impl<'msg> IntoView<'msg> for MyProxiedView<'msg> { into_view<'shorter>(self) -> MyProxiedView<'shorter> where 'msg: 'shorter,322 fn into_view<'shorter>(self) -> MyProxiedView<'shorter> 323 where 324 'msg: 'shorter, 325 { 326 self 327 } 328 } 329 330 #[derive(Debug)] 331 struct MyProxiedMut<'msg> { 332 my_proxied_ref: &'msg mut MyProxied, 333 } 334 335 impl<'msg> SealedInternal for MyProxiedMut<'msg> {} 336 337 impl<'msg> Proxy<'msg> for MyProxiedMut<'msg> {} 338 339 impl<'msg> AsView for MyProxiedMut<'msg> { 340 type Proxied = MyProxied; 341 as_view(&self) -> MyProxiedView<'_>342 fn as_view(&self) -> MyProxiedView<'_> { 343 MyProxiedView { my_proxied_ref: self.my_proxied_ref } 344 } 345 } 346 347 impl<'msg> IntoView<'msg> for MyProxiedMut<'msg> { into_view<'shorter>(self) -> View<'shorter, MyProxied> where 'msg: 'shorter,348 fn into_view<'shorter>(self) -> View<'shorter, MyProxied> 349 where 350 'msg: 'shorter, 351 { 352 MyProxiedView { my_proxied_ref: self.my_proxied_ref } 353 } 354 } 355 356 impl<'msg> AsMut for MyProxiedMut<'msg> { 357 type MutProxied = MyProxied; 358 as_mut(&mut self) -> MyProxiedMut<'_>359 fn as_mut(&mut self) -> MyProxiedMut<'_> { 360 MyProxiedMut { my_proxied_ref: self.my_proxied_ref } 361 } 362 } 363 364 impl<'msg> IntoMut<'msg> for MyProxiedMut<'msg> { into_mut<'shorter>(self) -> MyProxiedMut<'shorter> where 'msg: 'shorter,365 fn into_mut<'shorter>(self) -> MyProxiedMut<'shorter> 366 where 367 'msg: 'shorter, 368 { 369 self 370 } 371 } 372 373 impl<'msg> MutProxy<'msg> for MyProxiedMut<'msg> {} 374 375 #[gtest] test_as_view()376 fn test_as_view() { 377 let my_proxied = MyProxied { val: "Hello World".to_string() }; 378 379 let my_view = my_proxied.as_view(); 380 381 assert_that!(my_view.val(), eq(&my_proxied.val)); 382 } 383 reborrow_mut_into_view<'msg>(x: Mut<'msg, MyProxied>) -> View<'msg, MyProxied>384 fn reborrow_mut_into_view<'msg>(x: Mut<'msg, MyProxied>) -> View<'msg, MyProxied> { 385 // x.as_view() fails to compile with: 386 // `ERROR: attempt to return function-local borrowed content` 387 x.into_view() // OK: we return the same lifetime as we got in. 388 } 389 390 #[gtest] test_mut_into_view()391 fn test_mut_into_view() { 392 let mut my_proxied = MyProxied { val: "Hello World".to_string() }; 393 reborrow_mut_into_view(my_proxied.as_mut()); 394 } 395 require_unified_lifetimes<'msg>(_x: Mut<'msg, MyProxied>, _y: View<'msg, MyProxied>)396 fn require_unified_lifetimes<'msg>(_x: Mut<'msg, MyProxied>, _y: View<'msg, MyProxied>) {} 397 398 #[gtest] test_require_unified_lifetimes()399 fn test_require_unified_lifetimes() { 400 let mut my_proxied = MyProxied { val: "Hello1".to_string() }; 401 let my_mut = my_proxied.as_mut(); 402 403 { 404 let other_proxied = MyProxied { val: "Hello2".to_string() }; 405 let other_view = other_proxied.as_view(); 406 require_unified_lifetimes(my_mut, other_view); 407 } 408 } 409 reborrow_generic_as_view<'a, 'b, T>( x: &'b mut Mut<'a, T>, y: &'b View<'a, T>, ) -> [View<'b, T>; 2] where T: MutProxied, 'a: 'b,410 fn reborrow_generic_as_view<'a, 'b, T>( 411 x: &'b mut Mut<'a, T>, 412 y: &'b View<'a, T>, 413 ) -> [View<'b, T>; 2] 414 where 415 T: MutProxied, 416 'a: 'b, 417 { 418 // `[x, y]` fails to compile because `'a` is not the same as `'b` and the `View` 419 // lifetime parameter is (conservatively) invariant. 420 [x.as_view(), y.as_view()] 421 } 422 423 #[gtest] test_reborrow_generic_as_view()424 fn test_reborrow_generic_as_view() { 425 let mut my_proxied = MyProxied { val: "Hello1".to_string() }; 426 let mut my_mut = my_proxied.as_mut(); 427 let my_ref = &mut my_mut; 428 429 { 430 let other_proxied = MyProxied { val: "Hello2".to_string() }; 431 let other_view = other_proxied.as_view(); 432 reborrow_generic_as_view::<MyProxied>(my_ref, &other_view); 433 } 434 } 435 reborrow_generic_view_into_view<'a, 'b, T>( x: View<'a, T>, y: View<'b, T>, ) -> [View<'b, T>; 2] where T: Proxied, 'a: 'b,436 fn reborrow_generic_view_into_view<'a, 'b, T>( 437 x: View<'a, T>, 438 y: View<'b, T>, 439 ) -> [View<'b, T>; 2] 440 where 441 T: Proxied, 442 'a: 'b, 443 { 444 // `[x, y]` fails to compile because `'a` is not the same as `'b` and the `View` 445 // lifetime parameter is (conservatively) invariant. 446 // `[x.as_view(), y]` fails because that borrow cannot outlive `'b`. 447 [x.into_view(), y] 448 } 449 450 #[gtest] test_reborrow_generic_into_view()451 fn test_reborrow_generic_into_view() { 452 let my_proxied = MyProxied { val: "Hello1".to_string() }; 453 let my_view = my_proxied.as_view(); 454 455 { 456 let other_proxied = MyProxied { val: "Hello2".to_string() }; 457 let other_view = other_proxied.as_view(); 458 reborrow_generic_view_into_view::<MyProxied>(my_view, other_view); 459 } 460 } 461 reborrow_generic_mut_into_view<'a, 'b, T>(x: Mut<'a, T>, y: View<'b, T>) -> [View<'b, T>; 2] where T: MutProxied, 'a: 'b,462 fn reborrow_generic_mut_into_view<'a, 'b, T>(x: Mut<'a, T>, y: View<'b, T>) -> [View<'b, T>; 2] 463 where 464 T: MutProxied, 465 'a: 'b, 466 { 467 [x.into_view(), y] 468 } 469 470 #[gtest] test_reborrow_generic_mut_into_view()471 fn test_reborrow_generic_mut_into_view() { 472 let mut my_proxied = MyProxied { val: "Hello1".to_string() }; 473 let my_mut = my_proxied.as_mut(); 474 475 { 476 let other_proxied = MyProxied { val: "Hello2".to_string() }; 477 let other_view = other_proxied.as_view(); 478 reborrow_generic_mut_into_view::<MyProxied>(my_mut, other_view); 479 } 480 } 481 reborrow_generic_mut_into_mut<'a, 'b, T>(x: Mut<'a, T>, y: Mut<'b, T>) -> [Mut<'b, T>; 2] where T: MutProxied, 'a: 'b,482 fn reborrow_generic_mut_into_mut<'a, 'b, T>(x: Mut<'a, T>, y: Mut<'b, T>) -> [Mut<'b, T>; 2] 483 where 484 T: MutProxied, 485 'a: 'b, 486 { 487 // `[x, y]` fails to compile because `'a` is not the same as `'b` and the `Mut` 488 // lifetime parameter is (conservatively) invariant. 489 // `[x.as_mut(), y]` fails because that borrow cannot outlive `'b`. 490 let tmp: Mut<'b, T> = x.into_mut(); 491 [tmp, y] 492 } 493 494 #[gtest] test_reborrow_generic_mut_into_mut()495 fn test_reborrow_generic_mut_into_mut() { 496 let mut my_proxied = MyProxied { val: "Hello1".to_string() }; 497 let my_mut = my_proxied.as_mut(); 498 499 { 500 let mut other_proxied = MyProxied { val: "Hello2".to_string() }; 501 let other_mut = other_proxied.as_mut(); 502 // No need to reborrow, even though lifetime of &other_view is different 503 // than the lifetiem of my_ref. Rust references are covariant over their 504 // lifetime. 505 reborrow_generic_mut_into_mut::<MyProxied>(my_mut, other_mut); 506 } 507 } 508 } 509