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 // Rust Protobuf runtime using the C++ kernel.
9
10 use crate::__internal::{Enum, Private};
11 use crate::{
12 IntoProxied, Map, MapIter, MapMut, MapView, Mut, ProtoBytes, ProtoStr, ProtoString, Proxied,
13 ProxiedInMapValue, ProxiedInRepeated, Repeated, RepeatedMut, RepeatedView, View,
14 };
15 use core::fmt::Debug;
16 use paste::paste;
17 use std::convert::identity;
18 use std::ffi::{c_int, c_void};
19 use std::fmt;
20 use std::marker::PhantomData;
21 use std::mem::{ManuallyDrop, MaybeUninit};
22 use std::ops::Deref;
23 use std::ptr::{self, NonNull};
24 use std::slice;
25
26 /// Defines a set of opaque, unique, non-accessible pointees.
27 ///
28 /// The [Rustonomicon][nomicon] currently recommends a zero-sized struct,
29 /// though this should use [`extern type`] when that is stabilized.
30 /// [nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
31 /// [`extern type`]: https://github.com/rust-lang/rust/issues/43467
32 #[doc(hidden)]
33 mod _opaque_pointees {
34 /// Opaque pointee for [`RawMessage`]
35 ///
36 /// This type is not meant to be dereferenced in Rust code.
37 /// It is only meant to provide type safety for raw pointers
38 /// which are manipulated behind FFI.
39 ///
40 /// [`RawMessage`]: super::RawMessage
41 #[repr(C)]
42 pub struct RawMessageData {
43 _data: [u8; 0],
44 _marker: std::marker::PhantomData<(*mut u8, ::std::marker::PhantomPinned)>,
45 }
46
47 /// Opaque pointee for [`RawRepeatedField`]
48 ///
49 /// This type is not meant to be dereferenced in Rust code.
50 /// It is only meant to provide type safety for raw pointers
51 /// which are manipulated behind FFI.
52 #[repr(C)]
53 pub struct RawRepeatedFieldData {
54 _data: [u8; 0],
55 _marker: std::marker::PhantomData<(*mut u8, ::std::marker::PhantomPinned)>,
56 }
57
58 /// Opaque pointee for [`RawMap`]
59 ///
60 /// This type is not meant to be dereferenced in Rust code.
61 /// It is only meant to provide type safety for raw pointers
62 /// which are manipulated behind FFI.
63 #[repr(C)]
64 pub struct RawMapData {
65 _data: [u8; 0],
66 _marker: std::marker::PhantomData<(*mut u8, ::std::marker::PhantomPinned)>,
67 }
68
69 /// Opaque pointee for [`CppStdString`]
70 ///
71 /// This type is not meant to be dereferenced in Rust code.
72 /// It is only meant to provide type safety for raw pointers
73 /// which are manipulated behind FFI.
74 #[repr(C)]
75 pub struct CppStdStringData {
76 _data: [u8; 0],
77 _marker: std::marker::PhantomData<(*mut u8, ::std::marker::PhantomPinned)>,
78 }
79 }
80
81 /// A raw pointer to the underlying message for this runtime.
82 #[doc(hidden)]
83 pub type RawMessage = NonNull<_opaque_pointees::RawMessageData>;
84
85 /// A raw pointer to the underlying repeated field container for this runtime.
86 #[doc(hidden)]
87 pub type RawRepeatedField = NonNull<_opaque_pointees::RawRepeatedFieldData>;
88
89 /// A raw pointer to the underlying arena for this runtime.
90 #[doc(hidden)]
91 pub type RawMap = NonNull<_opaque_pointees::RawMapData>;
92
93 /// A raw pointer to a std::string.
94 #[doc(hidden)]
95 pub type CppStdString = NonNull<_opaque_pointees::CppStdStringData>;
96
97 /// Kernel-specific owned `string` and `bytes` field type.
98 #[derive(Debug)]
99 #[doc(hidden)]
100 pub struct InnerProtoString {
101 owned_ptr: CppStdString,
102 }
103
104 extern "C" {
proto2_rust_Message_delete(m: RawMessage)105 pub fn proto2_rust_Message_delete(m: RawMessage);
proto2_rust_Message_clear(m: RawMessage)106 pub fn proto2_rust_Message_clear(m: RawMessage);
proto2_rust_Message_parse(m: RawMessage, input: SerializedData) -> bool107 pub fn proto2_rust_Message_parse(m: RawMessage, input: SerializedData) -> bool;
proto2_rust_Message_serialize(m: RawMessage, output: &mut SerializedData) -> bool108 pub fn proto2_rust_Message_serialize(m: RawMessage, output: &mut SerializedData) -> bool;
proto2_rust_Message_copy_from(dst: RawMessage, src: RawMessage) -> bool109 pub fn proto2_rust_Message_copy_from(dst: RawMessage, src: RawMessage) -> bool;
proto2_rust_Message_merge_from(dst: RawMessage, src: RawMessage) -> bool110 pub fn proto2_rust_Message_merge_from(dst: RawMessage, src: RawMessage) -> bool;
111 }
112
113 /// An opaque type matching MapNodeSizeInfoT from C++.
114 #[doc(hidden)]
115 #[repr(transparent)]
116 pub struct MapNodeSizeInfo(pub i32);
117
118 impl Drop for InnerProtoString {
drop(&mut self)119 fn drop(&mut self) {
120 // SAFETY: `self.owned_ptr` points to a valid std::string object.
121 unsafe {
122 proto2_rust_cpp_delete_string(self.owned_ptr);
123 }
124 }
125 }
126
127 impl InnerProtoString {
as_bytes(&self) -> &[u8]128 pub(crate) fn as_bytes(&self) -> &[u8] {
129 // SAFETY: `self.owned_ptr` points to a valid std::string object.
130 unsafe { proto2_rust_cpp_string_to_view(self.owned_ptr).as_ref() }
131 }
132
into_raw(self) -> CppStdString133 pub fn into_raw(self) -> CppStdString {
134 let s = ManuallyDrop::new(self);
135 s.owned_ptr
136 }
137
138 /// # Safety
139 /// - `src` points to a valid CppStdString.
from_raw(src: CppStdString) -> InnerProtoString140 pub unsafe fn from_raw(src: CppStdString) -> InnerProtoString {
141 InnerProtoString { owned_ptr: src }
142 }
143 }
144
145 impl From<&[u8]> for InnerProtoString {
from(val: &[u8]) -> Self146 fn from(val: &[u8]) -> Self {
147 // SAFETY: `val` is valid byte slice.
148 let owned_ptr: CppStdString = unsafe { proto2_rust_cpp_new_string(val.into()) };
149 InnerProtoString { owned_ptr }
150 }
151 }
152
153 extern "C" {
proto2_rust_cpp_new_string(src: PtrAndLen) -> CppStdString154 fn proto2_rust_cpp_new_string(src: PtrAndLen) -> CppStdString;
proto2_rust_cpp_delete_string(src: CppStdString)155 fn proto2_rust_cpp_delete_string(src: CppStdString);
proto2_rust_cpp_string_to_view(src: CppStdString) -> PtrAndLen156 fn proto2_rust_cpp_string_to_view(src: CppStdString) -> PtrAndLen;
157 }
158
159 /// Represents an ABI-stable version of `NonNull<[u8]>`/`string_view` (a
160 /// borrowed slice of bytes) for FFI use only.
161 ///
162 /// Has semantics similar to `std::string_view` in C++ and `&[u8]` in Rust,
163 /// but is not ABI-compatible with either.
164 ///
165 /// If `len` is 0, then `ptr` can be null or dangling. C++ considers a dangling
166 /// 0-len `std::string_view` to be invalid, and Rust considers a `&[u8]` with a
167 /// null data pointer to be invalid.
168 #[repr(C)]
169 #[derive(Copy, Clone)]
170 #[doc(hidden)]
171 pub struct PtrAndLen {
172 /// Pointer to the first byte.
173 /// Borrows the memory.
174 pub ptr: *const u8,
175
176 /// Length of the `[u8]` pointed to by `ptr`.
177 pub len: usize,
178 }
179
180 impl PtrAndLen {
181 /// Unsafely dereference this slice.
182 ///
183 /// # Safety
184 /// - `self.ptr` must be dereferencable and immutable for `self.len` bytes
185 /// for the lifetime `'a`. It can be null or dangling if `self.len == 0`.
as_ref<'a>(self) -> &'a [u8]186 pub unsafe fn as_ref<'a>(self) -> &'a [u8] {
187 if self.ptr.is_null() {
188 assert_eq!(self.len, 0, "Non-empty slice with null data pointer");
189 &[]
190 } else {
191 // SAFETY:
192 // - `ptr` is non-null
193 // - `ptr` is valid for `len` bytes as promised by the caller.
194 unsafe { slice::from_raw_parts(self.ptr, self.len) }
195 }
196 }
197 }
198
199 impl From<&[u8]> for PtrAndLen {
from(slice: &[u8]) -> Self200 fn from(slice: &[u8]) -> Self {
201 Self { ptr: slice.as_ptr(), len: slice.len() }
202 }
203 }
204
205 impl From<&ProtoStr> for PtrAndLen {
from(s: &ProtoStr) -> Self206 fn from(s: &ProtoStr) -> Self {
207 let bytes = s.as_bytes();
208 Self { ptr: bytes.as_ptr(), len: bytes.len() }
209 }
210 }
211
212 /// Serialized Protobuf wire format data. It's typically produced by
213 /// `<Message>.serialize()`.
214 ///
215 /// This struct is ABI-compatible with the equivalent struct on the C++ side. It
216 /// owns (and drops) its data.
217 #[repr(C)]
218 #[doc(hidden)]
219 pub struct SerializedData {
220 /// Owns the memory.
221 data: NonNull<u8>,
222 len: usize,
223 }
224
225 impl SerializedData {
new() -> Self226 pub fn new() -> Self {
227 Self { data: NonNull::dangling(), len: 0 }
228 }
229
230 /// Constructs owned serialized data from raw components.
231 ///
232 /// # Safety
233 /// - `data` must be readable for `len` bytes.
234 /// - `data` must be an owned pointer and valid until deallocated.
235 /// - `data` must have been allocated by the Rust global allocator with a
236 /// size of `len` and align of 1.
from_raw_parts(data: NonNull<u8>, len: usize) -> Self237 pub unsafe fn from_raw_parts(data: NonNull<u8>, len: usize) -> Self {
238 Self { data, len }
239 }
240
241 /// Gets a raw slice pointer.
as_ptr(&self) -> *const [u8]242 pub fn as_ptr(&self) -> *const [u8] {
243 ptr::slice_from_raw_parts(self.data.as_ptr(), self.len)
244 }
245
246 /// Gets a mutable raw slice pointer.
as_mut_ptr(&mut self) -> *mut [u8]247 fn as_mut_ptr(&mut self) -> *mut [u8] {
248 ptr::slice_from_raw_parts_mut(self.data.as_ptr(), self.len)
249 }
250
251 /// Converts into a Vec<u8>.
into_vec(self) -> Vec<u8>252 pub fn into_vec(self) -> Vec<u8> {
253 // We need to prevent self from being dropped, because we are going to transfer
254 // ownership of self.data to the Vec<u8>.
255 let s = ManuallyDrop::new(self);
256
257 unsafe {
258 // SAFETY:
259 // - `data` was allocated by the Rust global allocator.
260 // - `data` was allocated with an alignment of 1 for u8.
261 // - The allocated size was `len`.
262 // - The length and capacity are equal.
263 // - All `len` bytes are initialized.
264 // - The capacity (`len` in this case) is the size the pointer was allocated
265 // with.
266 // - The allocated size is no more than isize::MAX, because the protobuf
267 // serializer will refuse to serialize a message if the output would exceed
268 // 2^31 - 1 bytes.
269 Vec::<u8>::from_raw_parts(s.data.as_ptr(), s.len, s.len)
270 }
271 }
272 }
273
274 impl Deref for SerializedData {
275 type Target = [u8];
deref(&self) -> &Self::Target276 fn deref(&self) -> &Self::Target {
277 // SAFETY: `data` is valid for `len` bytes until deallocated as promised by
278 // `from_raw_parts`.
279 unsafe { &*self.as_ptr() }
280 }
281 }
282
283 impl Drop for SerializedData {
drop(&mut self)284 fn drop(&mut self) {
285 // SAFETY: `data` was allocated by the Rust global allocator with a
286 // size of `len` and align of 1 as promised by `from_raw_parts`.
287 unsafe { drop(Box::from_raw(self.as_mut_ptr())) }
288 }
289 }
290
291 impl fmt::Debug for SerializedData {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result292 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
293 fmt::Debug::fmt(self.deref(), f)
294 }
295 }
296
297 /// A type to transfer an owned Rust string across the FFI boundary:
298 /// * This struct is ABI-compatible with the equivalent C struct.
299 /// * It owns its data but does not drop it. Immediately turn it into a
300 /// `String` by calling `.into()` on it.
301 /// * `.data` points to a valid UTF-8 string that has been allocated with the
302 /// Rust allocator and is 1-byte aligned.
303 /// * `.data` contains exactly `.len` bytes.
304 /// * The empty string is represented as `.data.is_null() == true`.
305 #[repr(C)]
306 #[doc(hidden)]
307 pub struct RustStringRawParts {
308 data: *const u8,
309 len: usize,
310 }
311
312 impl From<RustStringRawParts> for String {
from(value: RustStringRawParts) -> Self313 fn from(value: RustStringRawParts) -> Self {
314 if value.data.is_null() {
315 // Handle the case where the string is empty.
316 return String::new();
317 }
318 // SAFETY:
319 // - `value.data` contains valid UTF-8 bytes as promised by
320 // `RustStringRawParts`.
321 // - `value.data` has been allocated with the Rust allocator and is 1-byte
322 // aligned as promised by `RustStringRawParts`.
323 // - `value.data` contains and is allocated for exactly `value.len` bytes.
324 unsafe { String::from_raw_parts(value.data as *mut u8, value.len, value.len) }
325 }
326 }
327
328 extern "C" {
proto2_rust_utf8_debug_string(msg: RawMessage) -> RustStringRawParts329 fn proto2_rust_utf8_debug_string(msg: RawMessage) -> RustStringRawParts;
330 }
331
debug_string(msg: RawMessage, f: &mut fmt::Formatter<'_>) -> fmt::Result332 pub fn debug_string(msg: RawMessage, f: &mut fmt::Formatter<'_>) -> fmt::Result {
333 // SAFETY:
334 // - `msg` is a valid protobuf message.
335 let dbg_str: String = unsafe { proto2_rust_utf8_debug_string(msg) }.into();
336 write!(f, "{dbg_str}")
337 }
338
339 extern "C" {
340 /// # Safety
341 /// - `msg1` and `msg2` legally dereferencable MessageLite* pointers.
342 #[link_name = "proto2_rust_messagelite_equals"]
raw_message_equals(msg1: RawMessage, msg2: RawMessage) -> bool343 pub fn raw_message_equals(msg1: RawMessage, msg2: RawMessage) -> bool;
344 }
345
346 pub type RawMapIter = UntypedMapIterator;
347
348 /// The raw contents of every generated message.
349 #[derive(Debug)]
350 #[doc(hidden)]
351 pub struct MessageInner {
352 pub msg: RawMessage,
353 }
354
355 /// Mutators that point to their original message use this to do so.
356 ///
357 /// Since C++ messages manage their own memory, this can just copy the
358 /// `RawMessage` instead of referencing an arena like UPB must.
359 ///
360 /// Note: even though this type is `Copy`, it should only be copied by
361 /// protobuf internals that can maintain mutation invariants:
362 ///
363 /// - No concurrent mutation for any two fields in a message: this means
364 /// mutators cannot be `Send` but are `Sync`.
365 /// - If there are multiple accessible `Mut` to a single message at a time, they
366 /// must be different fields, and not be in the same oneof. As such, a `Mut`
367 /// cannot be `Clone` but *can* reborrow itself with `.as_mut()`, which
368 /// converts `&'b mut Mut<'a, T>` to `Mut<'b, T>`.
369 #[derive(Clone, Copy, Debug)]
370 #[doc(hidden)]
371 pub struct MutatorMessageRef<'msg> {
372 msg: RawMessage,
373 _phantom: PhantomData<&'msg mut ()>,
374 }
375 impl<'msg> MutatorMessageRef<'msg> {
376 #[allow(clippy::needless_pass_by_ref_mut)] // Sound construction requires mutable access.
new(msg: &'msg mut MessageInner) -> Self377 pub fn new(msg: &'msg mut MessageInner) -> Self {
378 MutatorMessageRef { msg: msg.msg, _phantom: PhantomData }
379 }
380
381 /// # Safety
382 /// - The underlying pointer must be sound and live for the lifetime 'msg.
wrap_raw(raw: RawMessage) -> Self383 pub unsafe fn wrap_raw(raw: RawMessage) -> Self {
384 MutatorMessageRef { msg: raw, _phantom: PhantomData }
385 }
386
from_parent( _parent_msg: MutatorMessageRef<'msg>, message_field_ptr: RawMessage, ) -> Self387 pub fn from_parent(
388 _parent_msg: MutatorMessageRef<'msg>,
389 message_field_ptr: RawMessage,
390 ) -> Self {
391 Self { msg: message_field_ptr, _phantom: PhantomData }
392 }
393
msg(&self) -> RawMessage394 pub fn msg(&self) -> RawMessage {
395 self.msg
396 }
397
from_raw_msg(msg: &RawMessage) -> Self398 pub fn from_raw_msg(msg: &RawMessage) -> Self {
399 Self { msg: *msg, _phantom: PhantomData }
400 }
401 }
402
403 /// The raw type-erased version of an owned `Repeated`.
404 #[derive(Debug)]
405 #[doc(hidden)]
406 pub struct InnerRepeated {
407 raw: RawRepeatedField,
408 }
409
410 impl InnerRepeated {
as_mut(&mut self) -> InnerRepeatedMut<'_>411 pub fn as_mut(&mut self) -> InnerRepeatedMut<'_> {
412 InnerRepeatedMut::new(self.raw)
413 }
414
raw(&self) -> RawRepeatedField415 pub fn raw(&self) -> RawRepeatedField {
416 self.raw
417 }
418
419 /// # Safety
420 /// - `raw` must be a valid `proto2::RepeatedField*` or
421 /// `proto2::RepeatedPtrField*`.
from_raw(raw: RawRepeatedField) -> Self422 pub unsafe fn from_raw(raw: RawRepeatedField) -> Self {
423 Self { raw }
424 }
425 }
426
427 /// The raw type-erased pointer version of `RepeatedMut`.
428 ///
429 /// Contains a `proto2::RepeatedField*` or `proto2::RepeatedPtrField*`.
430 #[derive(Clone, Copy, Debug)]
431 #[doc(hidden)]
432 pub struct InnerRepeatedMut<'msg> {
433 pub(crate) raw: RawRepeatedField,
434 _phantom: PhantomData<&'msg ()>,
435 }
436
437 impl<'msg> InnerRepeatedMut<'msg> {
438 #[doc(hidden)]
new(raw: RawRepeatedField) -> Self439 pub fn new(raw: RawRepeatedField) -> Self {
440 InnerRepeatedMut { raw, _phantom: PhantomData }
441 }
442 }
443
444 trait CppTypeConversions: Proxied {
445 type InsertElemType;
446 type ElemType;
447
elem_to_view<'msg>(v: Self::ElemType) -> View<'msg, Self>448 fn elem_to_view<'msg>(v: Self::ElemType) -> View<'msg, Self>;
into_insertelem(v: Self) -> Self::InsertElemType449 fn into_insertelem(v: Self) -> Self::InsertElemType;
450 }
451
452 macro_rules! impl_cpp_type_conversions_for_scalars {
453 ($($t:ty),* $(,)?) => {
454 $(
455 impl CppTypeConversions for $t {
456 type InsertElemType = Self;
457 type ElemType = Self;
458
459 fn elem_to_view<'msg>(v: Self) -> View<'msg, Self> {
460 v
461 }
462
463 fn into_insertelem(v: Self) -> Self {
464 v
465 }
466 }
467 )*
468 }
469 }
470
471 impl_cpp_type_conversions_for_scalars!(i32, u32, i64, u64, f32, f64, bool);
472
473 impl CppTypeConversions for ProtoString {
474 type InsertElemType = CppStdString;
475 type ElemType = PtrAndLen;
476
elem_to_view<'msg>(v: PtrAndLen) -> View<'msg, ProtoString>477 fn elem_to_view<'msg>(v: PtrAndLen) -> View<'msg, ProtoString> {
478 ptrlen_to_str(v)
479 }
480
into_insertelem(v: Self) -> CppStdString481 fn into_insertelem(v: Self) -> CppStdString {
482 v.into_inner(Private).into_raw()
483 }
484 }
485
486 impl CppTypeConversions for ProtoBytes {
487 type InsertElemType = CppStdString;
488 type ElemType = PtrAndLen;
489
elem_to_view<'msg>(v: Self::ElemType) -> View<'msg, Self>490 fn elem_to_view<'msg>(v: Self::ElemType) -> View<'msg, Self> {
491 ptrlen_to_bytes(v)
492 }
493
into_insertelem(v: Self) -> CppStdString494 fn into_insertelem(v: Self) -> CppStdString {
495 v.into_inner(Private).into_raw()
496 }
497 }
498
499 macro_rules! impl_repeated_primitives {
500 (@impl $($t:ty => [
501 $new_thunk:ident,
502 $free_thunk:ident,
503 $add_thunk:ident,
504 $size_thunk:ident,
505 $get_thunk:ident,
506 $set_thunk:ident,
507 $clear_thunk:ident,
508 $copy_from_thunk:ident,
509 $reserve_thunk:ident $(,)?
510 ]),* $(,)?) => {
511 $(
512 extern "C" {
513 fn $new_thunk() -> RawRepeatedField;
514 fn $free_thunk(f: RawRepeatedField);
515 fn $add_thunk(f: RawRepeatedField, v: <$t as CppTypeConversions>::InsertElemType);
516 fn $size_thunk(f: RawRepeatedField) -> usize;
517 fn $get_thunk(
518 f: RawRepeatedField,
519 i: usize) -> <$t as CppTypeConversions>::ElemType;
520 fn $set_thunk(
521 f: RawRepeatedField,
522 i: usize,
523 v: <$t as CppTypeConversions>::InsertElemType);
524 fn $clear_thunk(f: RawRepeatedField);
525 fn $copy_from_thunk(src: RawRepeatedField, dst: RawRepeatedField);
526 fn $reserve_thunk(
527 f: RawRepeatedField,
528 additional: usize);
529 }
530
531 unsafe impl ProxiedInRepeated for $t {
532 #[allow(dead_code)]
533 #[inline]
534 fn repeated_new(_: Private) -> Repeated<$t> {
535 Repeated::from_inner(Private, InnerRepeated {
536 raw: unsafe { $new_thunk() }
537 })
538 }
539 #[allow(dead_code)]
540 #[inline]
541 unsafe fn repeated_free(_: Private, f: &mut Repeated<$t>) {
542 unsafe { $free_thunk(f.as_mut().as_raw(Private)) }
543 }
544 #[inline]
545 fn repeated_len(f: View<Repeated<$t>>) -> usize {
546 unsafe { $size_thunk(f.as_raw(Private)) }
547 }
548 #[inline]
549 fn repeated_push(mut f: Mut<Repeated<$t>>, v: impl IntoProxied<$t>) {
550 unsafe { $add_thunk(f.as_raw(Private), <$t as CppTypeConversions>::into_insertelem(v.into_proxied(Private))) }
551 }
552 #[inline]
553 fn repeated_clear(mut f: Mut<Repeated<$t>>) {
554 unsafe { $clear_thunk(f.as_raw(Private)) }
555 }
556 #[inline]
557 unsafe fn repeated_get_unchecked(f: View<Repeated<$t>>, i: usize) -> View<$t> {
558 <$t as CppTypeConversions>::elem_to_view(
559 unsafe { $get_thunk(f.as_raw(Private), i) })
560 }
561 #[inline]
562 unsafe fn repeated_set_unchecked(mut f: Mut<Repeated<$t>>, i: usize, v: impl IntoProxied<$t>) {
563 unsafe { $set_thunk(f.as_raw(Private), i, <$t as CppTypeConversions>::into_insertelem(v.into_proxied(Private))) }
564 }
565 #[inline]
566 fn repeated_copy_from(src: View<Repeated<$t>>, mut dest: Mut<Repeated<$t>>) {
567 unsafe { $copy_from_thunk(src.as_raw(Private), dest.as_raw(Private)) }
568 }
569 #[inline]
570 fn repeated_reserve(mut f: Mut<Repeated<$t>>, additional: usize) {
571 unsafe { $reserve_thunk(f.as_raw(Private), additional) }
572 }
573 }
574 )*
575 };
576 ($($t:ty),* $(,)?) => {
577 paste!{
578 impl_repeated_primitives!(@impl $(
579 $t => [
580 [< proto2_rust_RepeatedField_ $t _new >],
581 [< proto2_rust_RepeatedField_ $t _free >],
582 [< proto2_rust_RepeatedField_ $t _add >],
583 [< proto2_rust_RepeatedField_ $t _size >],
584 [< proto2_rust_RepeatedField_ $t _get >],
585 [< proto2_rust_RepeatedField_ $t _set >],
586 [< proto2_rust_RepeatedField_ $t _clear >],
587 [< proto2_rust_RepeatedField_ $t _copy_from >],
588 [< proto2_rust_RepeatedField_ $t _reserve >],
589 ],
590 )*);
591 }
592 };
593 }
594
595 impl_repeated_primitives!(i32, u32, i64, u64, f32, f64, bool, ProtoString, ProtoBytes);
596
597 /// Cast a `RepeatedView<SomeEnum>` to `RepeatedView<c_int>`.
cast_enum_repeated_view<E: Enum + ProxiedInRepeated>( repeated: RepeatedView<E>, ) -> RepeatedView<c_int>598 pub fn cast_enum_repeated_view<E: Enum + ProxiedInRepeated>(
599 repeated: RepeatedView<E>,
600 ) -> RepeatedView<c_int> {
601 // SAFETY: the implementer of `Enum` has promised that this
602 // raw repeated is a type-erased `proto2::RepeatedField<int>*`.
603 unsafe { RepeatedView::from_raw(Private, repeated.as_raw(Private)) }
604 }
605
606 /// Cast a `RepeatedMut<SomeEnum>` to `RepeatedMut<c_int>`.
607 ///
608 /// Writing an unknown value is sound because all enums
609 /// are representationally open.
cast_enum_repeated_mut<E: Enum + ProxiedInRepeated>( mut repeated: RepeatedMut<E>, ) -> RepeatedMut<c_int>610 pub fn cast_enum_repeated_mut<E: Enum + ProxiedInRepeated>(
611 mut repeated: RepeatedMut<E>,
612 ) -> RepeatedMut<c_int> {
613 // SAFETY: the implementer of `Enum` has promised that this
614 // raw repeated is a type-erased `proto2::RepeatedField<int>*`.
615 unsafe {
616 RepeatedMut::from_inner(
617 Private,
618 InnerRepeatedMut { raw: repeated.as_raw(Private), _phantom: PhantomData },
619 )
620 }
621 }
622
623 /// Cast a `RepeatedMut<SomeEnum>` to `RepeatedMut<c_int>` and call
624 /// repeated_reserve.
reserve_enum_repeated_mut<E: Enum + ProxiedInRepeated>( repeated: RepeatedMut<E>, additional: usize, )625 pub fn reserve_enum_repeated_mut<E: Enum + ProxiedInRepeated>(
626 repeated: RepeatedMut<E>,
627 additional: usize,
628 ) {
629 let int_repeated = cast_enum_repeated_mut(repeated);
630 ProxiedInRepeated::repeated_reserve(int_repeated, additional);
631 }
632
new_enum_repeated<E: Enum + ProxiedInRepeated>() -> Repeated<E>633 pub fn new_enum_repeated<E: Enum + ProxiedInRepeated>() -> Repeated<E> {
634 let int_repeated = Repeated::<c_int>::new();
635 let raw = int_repeated.inner.raw();
636 std::mem::forget(int_repeated);
637 unsafe { Repeated::from_inner(Private, InnerRepeated::from_raw(raw)) }
638 }
639
640 /// Cast a `RepeatedMut<SomeEnum>` to `RepeatedMut<c_int>` and call
641 /// repeated_free.
642 /// # Safety
643 /// - The passed in `&mut Repeated<E>` must not be used after this function is
644 /// called.
free_enum_repeated<E: Enum + ProxiedInRepeated>(repeated: &mut Repeated<E>)645 pub unsafe fn free_enum_repeated<E: Enum + ProxiedInRepeated>(repeated: &mut Repeated<E>) {
646 unsafe {
647 let mut int_r: Repeated<c_int> =
648 Repeated::from_inner(Private, InnerRepeated::from_raw(repeated.inner.raw()));
649 ProxiedInRepeated::repeated_free(Private, &mut int_r);
650 std::mem::forget(int_r);
651 }
652 }
653
654 #[derive(Debug)]
655 #[doc(hidden)]
656 pub struct InnerMap {
657 pub(crate) raw: RawMap,
658 }
659
660 impl InnerMap {
new(raw: RawMap) -> Self661 pub fn new(raw: RawMap) -> Self {
662 Self { raw }
663 }
664
as_mut(&mut self) -> InnerMapMut<'_>665 pub fn as_mut(&mut self) -> InnerMapMut<'_> {
666 InnerMapMut { raw: self.raw, _phantom: PhantomData }
667 }
668 }
669
670 #[derive(Clone, Copy, Debug)]
671 #[doc(hidden)]
672 pub struct InnerMapMut<'msg> {
673 pub(crate) raw: RawMap,
674 _phantom: PhantomData<&'msg ()>,
675 }
676
677 #[doc(hidden)]
678 impl<'msg> InnerMapMut<'msg> {
new(raw: RawMap) -> Self679 pub fn new(raw: RawMap) -> Self {
680 InnerMapMut { raw, _phantom: PhantomData }
681 }
682
as_raw(&self) -> RawMap683 pub fn as_raw(&self) -> RawMap {
684 self.raw
685 }
686 }
687
688 /// An untyped iterator in a map, produced via `.cbegin()` on a typed map.
689 ///
690 /// This struct is ABI-compatible with `proto2::internal::UntypedMapIterator`.
691 /// It is trivially constructible and destructible.
692 #[repr(C)]
693 #[doc(hidden)]
694 pub struct UntypedMapIterator {
695 node: *mut c_void,
696 map: *const c_void,
697 bucket_index: u32,
698 }
699
700 impl UntypedMapIterator {
701 /// Returns `true` if this iterator is at the end of the map.
at_end(&self) -> bool702 fn at_end(&self) -> bool {
703 // This behavior is verified via test `IteratorNodeFieldIsNullPtrAtEnd`.
704 self.node.is_null()
705 }
706
707 /// Assumes that the map iterator is for the input types, gets the current
708 /// entry, and moves the iterator forward to the next entry.
709 ///
710 /// Conversion to and from FFI types is provided by the user.
711 /// This is a helper function for implementing
712 /// `ProxiedInMapValue::iter_next`.
713 ///
714 /// # Safety
715 /// - The backing map must be valid and not be mutated for `'a`.
716 /// - The thunk must be safe to call if the iterator is not at the end of
717 /// the map.
718 /// - The thunk must always write to the `key` and `value` fields, but not
719 /// read from them.
720 /// - The get thunk must not move the iterator forward or backward.
721 #[inline(always)]
next_unchecked<'a, K, V, FfiKey, FfiValue>( &mut self, iter_get_thunk: unsafe fn( iter: &mut UntypedMapIterator, key: *mut FfiKey, value: *mut FfiValue, ), from_ffi_key: impl FnOnce(FfiKey) -> View<'a, K>, from_ffi_value: impl FnOnce(FfiValue) -> View<'a, V>, ) -> Option<(View<'a, K>, View<'a, V>)> where K: Proxied + 'a, V: ProxiedInMapValue<K> + 'a,722 pub unsafe fn next_unchecked<'a, K, V, FfiKey, FfiValue>(
723 &mut self,
724
725 iter_get_thunk: unsafe fn(
726 iter: &mut UntypedMapIterator,
727 key: *mut FfiKey,
728 value: *mut FfiValue,
729 ),
730 from_ffi_key: impl FnOnce(FfiKey) -> View<'a, K>,
731 from_ffi_value: impl FnOnce(FfiValue) -> View<'a, V>,
732 ) -> Option<(View<'a, K>, View<'a, V>)>
733 where
734 K: Proxied + 'a,
735 V: ProxiedInMapValue<K> + 'a,
736 {
737 if self.at_end() {
738 return None;
739 }
740 let mut ffi_key = MaybeUninit::uninit();
741 let mut ffi_value = MaybeUninit::uninit();
742 // SAFETY:
743 // - The backing map outlives `'a`.
744 // - The iterator is not at the end (node is non-null).
745 // - `ffi_key` and `ffi_value` are not read (as uninit) as promised by the
746 // caller.
747 unsafe { (iter_get_thunk)(self, ffi_key.as_mut_ptr(), ffi_value.as_mut_ptr()) }
748
749 // SAFETY:
750 // - The backing map is alive as promised by the caller.
751 // - `self.at_end()` is false and the `get` does not change that.
752 // - `UntypedMapIterator` has the same ABI as
753 // `proto2::internal::UntypedMapIterator`. It is statically checked to be:
754 // - Trivially copyable.
755 // - Trivially destructible.
756 // - Standard layout.
757 // - The size and alignment of the Rust type above.
758 // - With the `node_` field first.
759 unsafe { proto2_rust_thunk_UntypedMapIterator_increment(self) }
760
761 // SAFETY:
762 // - The `get` function always writes valid values to `ffi_key` and `ffi_value`
763 // as promised by the caller.
764 unsafe {
765 Some((from_ffi_key(ffi_key.assume_init()), from_ffi_value(ffi_value.assume_init())))
766 }
767 }
768 }
769
770 #[doc(hidden)]
771 #[repr(transparent)]
772 pub struct MapNodeSizeInfoIndex(i32);
773
774 #[doc(hidden)]
775 pub trait MapNodeSizeInfoIndexForType {
776 const SIZE_INFO_INDEX: MapNodeSizeInfoIndex;
777 }
778
779 macro_rules! generate_map_node_size_info_mapping {
780 ( $($key:ty, $index:expr;)* ) => {
781 $(
782 impl MapNodeSizeInfoIndexForType for $key {
783 const SIZE_INFO_INDEX: MapNodeSizeInfoIndex = MapNodeSizeInfoIndex($index);
784 }
785 )*
786 }
787 }
788
789 // LINT.IfChange(size_info_mapping)
790 generate_map_node_size_info_mapping!(
791 i32, 0;
792 u32, 0;
793 i64, 1;
794 u64, 1;
795 bool, 2;
796 ProtoString, 3;
797 );
798 // LINT.ThenChange(//depot/google3/third_party/protobuf/compiler/rust/message.
799 // cc:size_info_mapping)
800
801 macro_rules! impl_map_primitives {
802 (@impl $(($rust_type:ty, $cpp_type:ty) => [
803 $insert_thunk:ident,
804 $get_thunk:ident,
805 $iter_get_thunk:ident,
806 $remove_thunk:ident,
807 ]),* $(,)?) => {
808 $(
809 extern "C" {
810 pub fn $insert_thunk(
811 m: RawMap,
812 size_info: MapNodeSizeInfo,
813 key: $cpp_type,
814 value: RawMessage,
815 ) -> bool;
816 pub fn $get_thunk(
817 m: RawMap,
818 size_info: MapNodeSizeInfo,
819 key: $cpp_type,
820 value: *mut RawMessage,
821 ) -> bool;
822 pub fn $iter_get_thunk(
823 iter: &mut UntypedMapIterator,
824 size_info: MapNodeSizeInfo,
825 key: *mut $cpp_type,
826 value: *mut RawMessage,
827 );
828 pub fn $remove_thunk(m: RawMap, size_info: MapNodeSizeInfo, key: $cpp_type) -> bool;
829 }
830 )*
831 };
832 ($($rust_type:ty, $cpp_type:ty;)* $(,)?) => {
833 paste!{
834 impl_map_primitives!(@impl $(
835 ($rust_type, $cpp_type) => [
836 [< proto2_rust_map_insert_ $rust_type >],
837 [< proto2_rust_map_get_ $rust_type >],
838 [< proto2_rust_map_iter_get_ $rust_type >],
839 [< proto2_rust_map_remove_ $rust_type >],
840 ],
841 )*);
842 }
843 };
844 }
845
846 impl_map_primitives!(
847 i32, i32;
848 u32, u32;
849 i64, i64;
850 u64, u64;
851 bool, bool;
852 ProtoString, PtrAndLen;
853 );
854
855 extern "C" {
proto2_rust_thunk_UntypedMapIterator_increment(iter: &mut UntypedMapIterator)856 fn proto2_rust_thunk_UntypedMapIterator_increment(iter: &mut UntypedMapIterator);
857
proto2_rust_map_new() -> RawMap858 pub fn proto2_rust_map_new() -> RawMap;
proto2_rust_map_free(m: RawMap, key_is_string: bool, size_info: MapNodeSizeInfo)859 pub fn proto2_rust_map_free(m: RawMap, key_is_string: bool, size_info: MapNodeSizeInfo);
proto2_rust_map_clear(m: RawMap, key_is_string: bool, size_info: MapNodeSizeInfo)860 pub fn proto2_rust_map_clear(m: RawMap, key_is_string: bool, size_info: MapNodeSizeInfo);
proto2_rust_map_size(m: RawMap) -> usize861 pub fn proto2_rust_map_size(m: RawMap) -> usize;
proto2_rust_map_iter(m: RawMap) -> UntypedMapIterator862 pub fn proto2_rust_map_iter(m: RawMap) -> UntypedMapIterator;
863 }
864
865 macro_rules! impl_ProxiedInMapValue_for_non_generated_value_types {
866 ($key_t:ty, $ffi_key_t:ty, $to_ffi_key:expr, $from_ffi_key:expr, for $($t:ty, $ffi_view_t:ty, $ffi_value_t:ty, $to_ffi_value:expr, $from_ffi_value:expr;)*) => {
867 paste! { $(
868 extern "C" {
869 pub fn [< proto2_rust_thunk_Map_ $key_t _ $t _new >]() -> RawMap;
870 pub fn [< proto2_rust_thunk_Map_ $key_t _ $t _free >](m: RawMap);
871 pub fn [< proto2_rust_thunk_Map_ $key_t _ $t _clear >](m: RawMap);
872 pub fn [< proto2_rust_thunk_Map_ $key_t _ $t _size >](m: RawMap) -> usize;
873 pub fn [< proto2_rust_thunk_Map_ $key_t _ $t _insert >](m: RawMap, key: $ffi_key_t, value: $ffi_value_t) -> bool;
874 pub fn [< proto2_rust_thunk_Map_ $key_t _ $t _get >](m: RawMap, key: $ffi_key_t, value: *mut $ffi_view_t) -> bool;
875 pub fn [< proto2_rust_thunk_Map_ $key_t _ $t _iter >](m: RawMap) -> UntypedMapIterator;
876 pub fn [< proto2_rust_thunk_Map_ $key_t _ $t _iter_get >](iter: &mut UntypedMapIterator, key: *mut $ffi_key_t, value: *mut $ffi_view_t);
877 pub fn [< proto2_rust_thunk_Map_ $key_t _ $t _remove >](m: RawMap, key: $ffi_key_t, value: *mut $ffi_view_t) -> bool;
878 }
879
880 impl ProxiedInMapValue<$key_t> for $t {
881 fn map_new(_private: Private) -> Map<$key_t, Self> {
882 unsafe {
883 Map::from_inner(
884 Private,
885 InnerMap {
886 raw: [< proto2_rust_thunk_Map_ $key_t _ $t _new >](),
887 }
888 )
889 }
890 }
891
892 unsafe fn map_free(_private: Private, map: &mut Map<$key_t, Self>) {
893 // SAFETY:
894 // - `map.inner.raw` is a live `RawMap`
895 // - This function is only called once for `map` in `Drop`.
896 unsafe { [< proto2_rust_thunk_Map_ $key_t _ $t _free >](map.as_mut().as_raw(Private)); }
897 }
898
899
900 fn map_clear(mut map: MapMut<$key_t, Self>) {
901 unsafe { [< proto2_rust_thunk_Map_ $key_t _ $t _clear >](map.as_raw(Private)); }
902 }
903
904 fn map_len(map: MapView<$key_t, Self>) -> usize {
905 unsafe { [< proto2_rust_thunk_Map_ $key_t _ $t _size >](map.as_raw(Private)) }
906 }
907
908 fn map_insert(mut map: MapMut<$key_t, Self>, key: View<'_, $key_t>, value: impl IntoProxied<Self>) -> bool {
909 let ffi_key = $to_ffi_key(key);
910 let ffi_value = $to_ffi_value(value.into_proxied(Private));
911 unsafe { [< proto2_rust_thunk_Map_ $key_t _ $t _insert >](map.as_raw(Private), ffi_key, ffi_value) }
912 }
913
914 fn map_get<'a>(map: MapView<'a, $key_t, Self>, key: View<'_, $key_t>) -> Option<View<'a, Self>> {
915 let ffi_key = $to_ffi_key(key);
916 let mut ffi_value = MaybeUninit::uninit();
917 let found = unsafe { [< proto2_rust_thunk_Map_ $key_t _ $t _get >](map.as_raw(Private), ffi_key, ffi_value.as_mut_ptr()) };
918
919 if !found {
920 return None;
921 }
922 // SAFETY: if `found` is true, then the `ffi_value` was written to by `get`.
923 Some($from_ffi_value(unsafe { ffi_value.assume_init() }))
924 }
925
926 fn map_remove(mut map: MapMut<$key_t, Self>, key: View<'_, $key_t>) -> bool {
927 let ffi_key = $to_ffi_key(key);
928 let mut ffi_value = MaybeUninit::uninit();
929 unsafe { [< proto2_rust_thunk_Map_ $key_t _ $t _remove >](map.as_raw(Private), ffi_key, ffi_value.as_mut_ptr()) }
930 }
931
932 fn map_iter(map: MapView<$key_t, Self>) -> MapIter<$key_t, Self> {
933 // SAFETY:
934 // - The backing map for `map.as_raw` is valid for at least '_.
935 // - A View that is live for '_ guarantees the backing map is unmodified for '_.
936 // - The `iter` function produces an iterator that is valid for the key
937 // and value types, and live for at least '_.
938 unsafe {
939 MapIter::from_raw(
940 Private,
941 [< proto2_rust_thunk_Map_ $key_t _ $t _iter >](map.as_raw(Private))
942 )
943 }
944 }
945
946 fn map_iter_next<'a>(iter: &mut MapIter<'a, $key_t, Self>) -> Option<(View<'a, $key_t>, View<'a, Self>)> {
947 // SAFETY:
948 // - The `MapIter` API forbids the backing map from being mutated for 'a,
949 // and guarantees that it's the correct key and value types.
950 // - The thunk is safe to call as long as the iterator isn't at the end.
951 // - The thunk always writes to key and value fields and does not read.
952 // - The thunk does not increment the iterator.
953 unsafe {
954 iter.as_raw_mut(Private).next_unchecked::<$key_t, Self, _, _>(
955 |iter, key, value| { [< proto2_rust_thunk_Map_ $key_t _ $t _iter_get >](iter, key, value) },
956 $from_ffi_key,
957 $from_ffi_value,
958 )
959 }
960 }
961 }
962 )* }
963 }
964 }
965
str_to_ptrlen<'msg>(val: impl Into<&'msg ProtoStr>) -> PtrAndLen966 fn str_to_ptrlen<'msg>(val: impl Into<&'msg ProtoStr>) -> PtrAndLen {
967 val.into().as_bytes().into()
968 }
969
970 // Warning: this function is unsound on its own! `val.as_ref()` must be safe to
971 // call.
ptrlen_to_str<'msg>(val: PtrAndLen) -> &'msg ProtoStr972 fn ptrlen_to_str<'msg>(val: PtrAndLen) -> &'msg ProtoStr {
973 unsafe { ProtoStr::from_utf8_unchecked(val.as_ref()) }
974 }
975
protostr_into_cppstdstring(val: ProtoString) -> CppStdString976 fn protostr_into_cppstdstring(val: ProtoString) -> CppStdString {
977 val.into_inner(Private).into_raw()
978 }
979
protobytes_into_cppstdstring(val: ProtoBytes) -> CppStdString980 fn protobytes_into_cppstdstring(val: ProtoBytes) -> CppStdString {
981 val.into_inner(Private).into_raw()
982 }
983
984 // Warning: this function is unsound on its own! `val.as_ref()` must be safe to
985 // call.
ptrlen_to_bytes<'msg>(val: PtrAndLen) -> &'msg [u8]986 fn ptrlen_to_bytes<'msg>(val: PtrAndLen) -> &'msg [u8] {
987 unsafe { val.as_ref() }
988 }
989
990 macro_rules! impl_ProxiedInMapValue_for_key_types {
991 ($($t:ty, $ffi_t:ty, $to_ffi_key:expr, $from_ffi_key:expr;)*) => {
992 paste! {
993 $(
994 impl_ProxiedInMapValue_for_non_generated_value_types!(
995 $t, $ffi_t, $to_ffi_key, $from_ffi_key, for
996 f32, f32, f32, identity, identity;
997 f64, f64, f64, identity, identity;
998 i32, i32, i32, identity, identity;
999 u32, u32, u32, identity, identity;
1000 i64, i64, i64, identity, identity;
1001 u64, u64, u64, identity, identity;
1002 bool, bool, bool, identity, identity;
1003 ProtoString, PtrAndLen, CppStdString, protostr_into_cppstdstring, ptrlen_to_str;
1004 ProtoBytes, PtrAndLen, CppStdString, protobytes_into_cppstdstring, ptrlen_to_bytes;
1005 );
1006 )*
1007 }
1008 }
1009 }
1010
1011 impl_ProxiedInMapValue_for_key_types!(
1012 i32, i32, identity, identity;
1013 u32, u32, identity, identity;
1014 i64, i64, identity, identity;
1015 u64, u64, identity, identity;
1016 bool, bool, identity, identity;
1017 ProtoString, PtrAndLen, str_to_ptrlen, ptrlen_to_str;
1018 );
1019
1020 #[cfg(test)]
1021 mod tests {
1022 use super::*;
1023 use googletest::prelude::*;
1024
1025 // We need to allocate the byte array so SerializedData can own it and
1026 // deallocate it in its drop. This function makes it easier to do so for our
1027 // tests.
allocate_byte_array(content: &'static [u8]) -> (*mut u8, usize)1028 fn allocate_byte_array(content: &'static [u8]) -> (*mut u8, usize) {
1029 let content: &mut [u8] = Box::leak(content.into());
1030 (content.as_mut_ptr(), content.len())
1031 }
1032
1033 #[gtest]
test_serialized_data_roundtrip()1034 fn test_serialized_data_roundtrip() {
1035 let (ptr, len) = allocate_byte_array(b"Hello world");
1036 let serialized_data = SerializedData { data: NonNull::new(ptr).unwrap(), len };
1037 assert_that!(&*serialized_data, eq(b"Hello world"));
1038 }
1039
1040 #[gtest]
test_empty_string()1041 fn test_empty_string() {
1042 let empty_str: String = RustStringRawParts { data: std::ptr::null(), len: 0 }.into();
1043 assert_that!(empty_str, eq(""));
1044 }
1045 }
1046