• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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