protobuf_native/lib.rs
1// Copyright Materialize, Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License in the LICENSE file at the
6// root of this repository, or online at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! [<img src="https://materialize.com/wp-content/uploads/2020/01/materialize_logo_primary.png" width=180 align=right>](https://materialize.com)
17//! High-level, safe bindings to `libprotobuf`, the C++ implementation of
18//! [Protocol Buffers], Google's data interchange format.
19//!
20//! # Maintainership
21//!
22//! This crate is maintained by [Materialize]. Contributions are encouraged:
23//!
24//! * [View source code](https://github.com/MaterializeInc/rust-protobuf-native/tree/master/src/protobuf-native)
25//! * [Report an issue](https://github.com/MaterializeInc/rust-protobuf-native/issues/new/choose)
26//! * [Submit a pull request](https://github.com/MaterializeInc/rust-protobuf-native/compare)
27//!
28//! # Overview
29//!
30//! This crate contains handwritten bindings to libprotobuf facilitated by
31//! [cxx]. The API that is exposed is extremely specific to the few users of
32//! this library and is subject to frequent change.
33//!
34//! Depending on your use case, the auto-generated bindings in [protobuf-sys]
35//! may be more suitable.
36//!
37//! # API details
38//!
39//! This section, as well as the documentation on individual types, is
40//! copied directly from the official [C++ API reference][cxx-api], with a few
41//! modifications made as necessary.
42//!
43//! [cxx]: https://github.com/dtolnay/cxx
44//! [cxx-api]: https://developers.google.com/protocol-buffers/docs/reference/cpp
45//! [protobuf-sys]: https://docs.rs/protobuf-sys
46//! [Materialize]: https://materialize.com
47//! [Protocol Buffers]: https://github.com/google/protobuf
48
49use std::error::Error;
50use std::fmt;
51use std::io::Write;
52use std::marker::PhantomPinned;
53use std::mem;
54use std::path::Path;
55use std::pin::Pin;
56
57use crate::internal::{unsafe_ffi_conversions, BoolExt, CInt};
58use crate::io::{CodedInputStream, CodedOutputStream, WriterStream, ZeroCopyOutputStream};
59
60pub mod compiler;
61pub mod io;
62
63mod internal;
64
65#[cxx::bridge(namespace = "protobuf_native")]
66pub(crate) mod ffi {
67 unsafe extern "C++" {
68 include!("protobuf-native/src/internal.h");
69 include!("protobuf-native/src/lib.h");
70
71 #[namespace = "protobuf_native::internal"]
72 type CInt = crate::internal::CInt;
73
74 #[namespace = "google::protobuf::io"]
75 type ZeroCopyOutputStream = crate::io::ffi::ZeroCopyOutputStream;
76
77 #[namespace = "google::protobuf::io"]
78 type CodedInputStream = crate::io::ffi::CodedInputStream;
79
80 #[namespace = "google::protobuf::io"]
81 type CodedOutputStream = crate::io::ffi::CodedOutputStream;
82
83 #[namespace = "google::protobuf"]
84 type MessageLite;
85
86 fn NewMessageLite(message: &MessageLite) -> *mut MessageLite;
87 unsafe fn DeleteMessageLite(message: *mut MessageLite);
88 fn Clear(self: Pin<&mut MessageLite>);
89 fn IsInitialized(self: &MessageLite) -> bool;
90 unsafe fn MergeFromCodedStream(
91 self: Pin<&mut MessageLite>,
92 input: *mut CodedInputStream,
93 ) -> bool;
94 unsafe fn SerializeToCodedStream(
95 self: &MessageLite,
96 output: *mut CodedOutputStream,
97 ) -> bool;
98 unsafe fn SerializeToZeroCopyStream(
99 self: &MessageLite,
100 output: *mut ZeroCopyOutputStream,
101 ) -> bool;
102 fn ByteSizeLong(self: &MessageLite) -> usize;
103
104 #[namespace = "google::protobuf"]
105 type Message;
106
107 #[namespace = "google::protobuf"]
108 type FileDescriptor;
109
110 unsafe fn DeleteFileDescriptor(proto: *mut FileDescriptor);
111
112 #[namespace = "google::protobuf"]
113 type DescriptorPool;
114
115 fn NewDescriptorPool() -> *mut DescriptorPool;
116 unsafe fn DeleteDescriptorPool(proto: *mut DescriptorPool);
117 fn BuildFile(
118 self: Pin<&mut DescriptorPool>,
119 proto: &FileDescriptorProto,
120 ) -> *const FileDescriptor;
121
122 #[namespace = "google::protobuf"]
123 type FileDescriptorSet;
124
125 fn NewFileDescriptorSet() -> *mut FileDescriptorSet;
126 unsafe fn DeleteFileDescriptorSet(set: *mut FileDescriptorSet);
127 fn file_size(self: &FileDescriptorSet) -> CInt;
128 fn clear_file(self: Pin<&mut FileDescriptorSet>);
129 fn file(self: &FileDescriptorSet, i: CInt) -> &FileDescriptorProto;
130 fn mutable_file(self: Pin<&mut FileDescriptorSet>, i: CInt) -> *mut FileDescriptorProto;
131 fn add_file(self: Pin<&mut FileDescriptorSet>) -> *mut FileDescriptorProto;
132
133 #[namespace = "google::protobuf"]
134 type FileDescriptorProto;
135
136 fn NewFileDescriptorProto() -> *mut FileDescriptorProto;
137 unsafe fn DeleteFileDescriptorProto(proto: *mut FileDescriptorProto);
138 fn CopyFrom(self: Pin<&mut FileDescriptorProto>, from: &FileDescriptorProto);
139 fn MergeFrom(self: Pin<&mut FileDescriptorProto>, from: &FileDescriptorProto);
140 fn dependency_size(self: &FileDescriptorProto) -> CInt;
141 fn dependency(self: &FileDescriptorProto, i: CInt) -> &CxxString;
142 fn message_type_size(self: &FileDescriptorProto) -> CInt;
143 fn message_type(self: &FileDescriptorProto, i: CInt) -> &DescriptorProto;
144
145 #[namespace = "google::protobuf"]
146 type DescriptorProto;
147 unsafe fn DeleteDescriptorProto(proto: *mut DescriptorProto);
148 fn name(self: &DescriptorProto) -> &CxxString;
149 }
150
151 impl UniquePtr<MessageLite> {}
152 impl UniquePtr<Message> {}
153}
154
155mod private {
156 use std::pin::Pin;
157
158 use super::ffi;
159
160 pub trait MessageLite {
161 fn upcast(&self) -> &ffi::MessageLite;
162 fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::MessageLite>;
163 }
164
165 pub trait Message {}
166}
167
168/// Abstract interface for a database of descriptors.
169///
170/// This is useful if you want to create a [`DescriptorPool`] which loads
171/// descriptors on-demand from some sort of large database. If the database is
172/// large, it may be inefficient to enumerate every .proto file inside it
173/// calling [`DescriptorPool::build_file`] for each one. Instead, a
174/// `DescriptorPool` can be created which wraps a `DescriptorDatabase` and only
175/// builds particular descriptors when they are needed.
176pub trait DescriptorDatabase {
177 /// Finds a file by file name.
178 fn find_file_by_name(
179 self: Pin<&mut Self>,
180 filename: &Path,
181 ) -> Result<Pin<Box<FileDescriptorProto>>, OperationFailedError>;
182}
183
184/// Describes a whole .proto file.
185///
186/// To get the `FileDescriptor` for a compiled-in file, get the descriptor for
187/// something defined in that file and call `descriptor.file()`. Use
188/// `DescriptorPool` to construct your own descriptors.
189pub struct FileDescriptor {
190 _opaque: PhantomPinned,
191}
192
193impl FileDescriptor {
194 unsafe_ffi_conversions!(ffi::FileDescriptor);
195}
196
197impl Drop for FileDescriptor {
198 fn drop(&mut self) {
199 unsafe { ffi::DeleteFileDescriptor(self.as_ffi_mut_ptr_unpinned()) }
200 }
201}
202
203/// Used to construct descriptors.
204///
205/// Normally you won't want to build your own descriptors. Message classes
206/// constructed by the protocol compiler will provide them for you. However, if
207/// you are implementing [`Message`] on your own, or if you are writing a
208/// program which can operate on totally arbitrary types and needs to load them
209/// from some sort of database, you might need to.
210///
211/// Since [`Descriptor`]s are composed of a whole lot of cross-linked bits of
212/// data that would be a pain to put together manually, the [`DescriptorPool`]
213/// class is provided to make the process easier. It can take a
214/// [`FileDescriptorProto`] (defined in descriptor.proto), validate it, and
215/// convert it to a set of nicely cross-linked `Descriptor`s.
216///
217/// [`DescriptorPool`] also helps with memory management. Descriptors are
218/// composed of many objects containing static data and pointers to each other.
219/// In all likelihood, when it comes time to delete this data, you'll want to
220/// delete it all at once. In fact, it is not uncommon to have a whole pool of
221/// descriptors all cross-linked with each other which you wish to delete all at
222/// once. This class represents such a pool, and handles the memory management
223/// for you.
224///
225/// You can also search for descriptors within a `DescriptorPool` by name, and
226/// extensions by number.
227pub struct DescriptorPool {
228 _opaque: PhantomPinned,
229}
230
231impl Drop for DescriptorPool {
232 fn drop(&mut self) {
233 unsafe { ffi::DeleteDescriptorPool(self.as_ffi_mut_ptr_unpinned()) }
234 }
235}
236
237impl DescriptorPool {
238 pub fn new() -> Pin<Box<DescriptorPool>> {
239 let pool = ffi::NewDescriptorPool();
240 unsafe { Self::from_ffi_owned(pool) }
241 }
242
243 /// Converts the `FileDescriptorProto` to real descriptors and places them
244 /// in this descriptor pool.
245 ///
246 /// All dependencies of the file must already be in the pool. Returns the
247 /// resulting [`FileDescriptor`], or `None` if there were problems with the
248 /// input (e.g. the message was invalid, or dependencies were missing).
249 /// Details about the errors are written to the error log.
250 pub fn build_file(self: Pin<&mut Self>, proto: &FileDescriptorProto) -> &FileDescriptor {
251 let file = self.as_ffi_mut().BuildFile(proto.as_ffi());
252 unsafe { FileDescriptor::from_ffi_ptr(file) }
253 }
254
255 unsafe_ffi_conversions!(ffi::DescriptorPool);
256}
257
258/// Describes a type of protocol message, or a particular group within a
259/// message.
260///
261/// To obtain the `Descriptor` for a given message object, call
262/// [`Message::get_descriptor`]. Generated message classes also have a static
263/// method called `descriptor` which returns the type's descriptor. Use
264/// [`DescriptorPool`] to construct your own descriptors.
265pub struct Descriptor {}
266
267/// Interface to light weight protocol messages.
268///
269/// This interface is implemented by all protocol message objects. Non-lite
270/// messages additionally implement the [`Message`] interface, which is a
271/// subclass of `MessageLite`. Use `MessageLite` instead when you only need the
272/// subset of features which it supports -- namely, nothing that uses
273/// descriptors or reflection. You can instruct the protocol compiler to
274/// generate classes which implement only `MessageLite`, not the full `Message`
275/// interface, by adding the following line to the .proto file:
276///
277/// ```proto
278/// option optimize_for = LITE_RUNTIME;
279/// ```
280///
281/// This is particularly useful on resource-constrained systems where the full
282/// protocol buffers runtime library is too big.
283///
284/// Note that on non-constrained systems (e.g. servers) when you need to link in
285/// lots of protocol definitions, a better way to reduce total code footprint is
286/// to use `optimize_for = CODE_SIZE`. This will make the generated code smaller
287/// while still supporting all the same features (at the expense of speed).
288/// `optimize_for = LITE_RUNTIME` is best when you only have a small number of
289/// message types linked into your binary, in which case the size of the
290/// protocol buffers runtime itself is the biggest problem.
291///
292/// Users must not derive from this class. Only the protocol compiler and the
293/// internal library are allowed to create subclasses.
294pub trait MessageLite: private::MessageLite {
295 /// Constructs a new instance of the same type.
296 fn new(&self) -> Pin<Box<dyn MessageLite>> {
297 unsafe { DynMessageLite::from_ffi_owned(ffi::NewMessageLite(self.upcast())) }
298 }
299
300 /// Clears all fields of the message and set them to their default values.
301 ///
302 /// This method avoids freeing memory, assuming that any memory allocated to
303 /// hold parts of the message will be needed again to hold the next message.
304 /// If you actually want to free the memory used by a `MessageLite`, you
305 /// must drop it.
306 fn clear(self: Pin<&mut Self>) {
307 self.upcast_mut().Clear()
308 }
309
310 /// Quickly checks if all required fields have been set.
311 fn is_initialized(&self) -> bool {
312 self.upcast().IsInitialized()
313 }
314
315 /// Reads a protocol buffer from the stream and merges it into this message.
316 ///
317 /// Singular fields read from the what is already in the message and
318 /// repeated fields are appended to those already present.
319 ///
320 /// It is the responsibility of the caller to call input->LastTagWas() (for
321 /// groups) or input->ConsumedEntireMessage() (for non-groups) after this
322 /// returns to verify that the message's end was delimited correctly.
323 fn merge_from_coded_stream(
324 self: Pin<&mut Self>,
325 input: Pin<&mut CodedInputStream>,
326 ) -> Result<(), OperationFailedError> {
327 unsafe {
328 self.upcast_mut()
329 .MergeFromCodedStream(input.as_ffi_mut_ptr())
330 .as_result()
331 }
332 }
333
334 /// Writes a protocol buffer of this message to the given output.
335 ///
336 /// All required fields must be set.
337 fn serialize_to_coded_stream(
338 &self,
339 output: Pin<&mut CodedOutputStream>,
340 ) -> Result<(), OperationFailedError> {
341 unsafe {
342 self.upcast()
343 .SerializeToCodedStream(output.as_ffi_mut_ptr())
344 .as_result()
345 }
346 }
347
348 /// Writes the message to the given zero-copy output stream.
349 ///
350 /// All required fields must be set.
351 fn serialize_to_zero_copy_stream(
352 &self,
353 output: Pin<&mut dyn ZeroCopyOutputStream>,
354 ) -> Result<(), OperationFailedError> {
355 unsafe {
356 self.upcast()
357 .SerializeToZeroCopyStream(output.upcast_mut_ptr())
358 .as_result()
359 }
360 }
361
362 /// Writes the message to the given [`Write`] implementor.
363 ///
364 /// All required fields must be set.
365 fn serialize_to_writer(&self, output: &mut dyn Write) -> Result<(), OperationFailedError> {
366 self.serialize_to_zero_copy_stream(WriterStream::new(output).as_mut())
367 }
368
369 /// Serializes the message to a byte vector.
370 ///
371 /// All required fields must be set.
372 fn serialize(&self) -> Result<Vec<u8>, OperationFailedError> {
373 let mut output = vec![];
374 self.serialize_to_writer(&mut output)?;
375 Ok(output)
376 }
377
378 /// Computes the serialized size of the message.
379 ///
380 /// This recursively calls `byte_size` on all embedded messages. The
381 /// computation is generally linear in the number of the fields defined for
382 /// the proto.
383 fn byte_size(&self) -> usize {
384 self.upcast().ByteSizeLong()
385 }
386}
387
388struct DynMessageLite {
389 _opaque: PhantomPinned,
390}
391
392impl Drop for DynMessageLite {
393 fn drop(&mut self) {
394 unsafe { ffi::DeleteMessageLite(self.as_ffi_mut_ptr_unpinned()) }
395 }
396}
397
398impl DynMessageLite {
399 unsafe_ffi_conversions!(ffi::MessageLite);
400}
401
402impl MessageLite for DynMessageLite {}
403
404impl private::MessageLite for DynMessageLite {
405 fn upcast(&self) -> &ffi::MessageLite {
406 unsafe { mem::transmute(self) }
407 }
408
409 fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::MessageLite> {
410 unsafe { mem::transmute(self) }
411 }
412}
413
414/// Abstract interface for protocol messages.
415///
416/// See also `MessageLite`, which contains most every-day operations. `Message`
417/// adds descriptors and reflection on top of that.
418///
419/// The methods of this class that have default implementations have default
420/// implementations based on reflection. Message classes which are optimized for
421/// speed will want to override these with faster implementations, but classes
422/// optimized for code size may be happy with keeping them. See the
423/// optimize_for option in descriptor.proto.
424///
425/// Users must not derive from this class. Only the protocol compiler and the
426/// internal library are allowed to create subclasses.
427pub trait Message: private::Message + MessageLite {}
428
429/// The protocol compiler can output a file descriptor set containing the .proto
430/// files it parses.
431pub struct FileDescriptorSet {
432 _opaque: PhantomPinned,
433}
434
435impl Drop for FileDescriptorSet {
436 fn drop(&mut self) {
437 unsafe { ffi::DeleteFileDescriptorSet(self.as_ffi_mut_ptr_unpinned()) }
438 }
439}
440
441impl FileDescriptorSet {
442 /// Creates a a new file descriptor set.
443 fn new() -> Pin<Box<FileDescriptorSet>> {
444 let set = ffi::NewFileDescriptorSet();
445 unsafe { Self::from_ffi_owned(set) }
446 }
447
448 /// Returns the number of file descriptors in the file descriptor set.
449 pub fn file_size(&self) -> usize {
450 self.as_ffi().file_size().expect_usize()
451 }
452
453 /// Clears the file descriptors.
454 pub fn clear_file(self: Pin<&mut Self>) {
455 self.as_ffi_mut().clear_file()
456 }
457
458 /// Returns a reference the `i`th file descriptor.
459 pub fn file(&self, i: usize) -> &FileDescriptorProto {
460 let file = self.as_ffi().file(CInt::expect_from(i));
461 FileDescriptorProto::from_ffi_ref(file)
462 }
463
464 /// Returns a mutable reference to the `i`th file descriptor.
465 pub fn file_mut(self: Pin<&mut Self>, i: usize) -> Pin<&mut FileDescriptorProto> {
466 let file = self.as_ffi_mut().mutable_file(CInt::expect_from(i));
467 unsafe { FileDescriptorProto::from_ffi_mut(file) }
468 }
469
470 /// Adds a new empty file descriptor and returns a mutable reference to it.
471 pub fn add_file(self: Pin<&mut Self>) -> Pin<&mut FileDescriptorProto> {
472 let file = self.as_ffi_mut().add_file();
473 unsafe { FileDescriptorProto::from_ffi_mut(file) }
474 }
475
476 unsafe_ffi_conversions!(ffi::FileDescriptorSet);
477}
478
479impl MessageLite for FileDescriptorSet {}
480
481impl private::MessageLite for FileDescriptorSet {
482 fn upcast(&self) -> &ffi::MessageLite {
483 unsafe { mem::transmute(self) }
484 }
485
486 fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::MessageLite> {
487 unsafe { mem::transmute(self) }
488 }
489}
490
491impl Message for FileDescriptorSet {}
492impl private::Message for FileDescriptorSet {}
493
494/// Describes a complete .proto file.
495pub struct FileDescriptorProto {
496 _opaque: PhantomPinned,
497}
498
499impl FileDescriptorProto {
500 /// Creates a a new file descriptor proto.
501 fn new() -> Pin<Box<FileDescriptorProto>> {
502 let proto = ffi::NewFileDescriptorProto();
503 unsafe { Self::from_ffi_owned(proto) }
504 }
505
506 /// Make this file descriptor proto into a copy of the given file descriptor
507 /// proto.
508 pub fn copy_from(self: Pin<&mut Self>, from: &FileDescriptorProto) {
509 self.as_ffi_mut().CopyFrom(from.as_ffi())
510 }
511
512 /// Merge the fields of the file descriptor proto into this file descriptor
513 /// proto.
514 pub fn merge_from(self: Pin<&mut Self>, from: &FileDescriptorProto) {
515 self.as_ffi_mut().MergeFrom(from.as_ffi())
516 }
517
518 /// Returns the number of entries in the `dependency` field.
519 pub fn dependency_size(&self) -> usize {
520 self.as_ffi().dependency_size().expect_usize()
521 }
522
523 /// Returns the `i`th entry in the `dependency` field.
524 pub fn dependency(&self, i: usize) -> &[u8] {
525 if i >= self.dependency_size() {
526 panic!(
527 "index out of bounds: the length is {} but the index is {}",
528 self.dependency_size(),
529 i
530 );
531 }
532 self.as_ffi().dependency(CInt::expect_from(i)).as_bytes()
533 }
534
535 /// Returns the number of entries in the `message_type` field.
536 pub fn message_type_size(&self) -> usize {
537 self.as_ffi().message_type_size().expect_usize()
538 }
539
540 /// Returns the `i`th entry in the `message_type` field.
541 pub fn message_type(&self, i: usize) -> &DescriptorProto {
542 if i >= self.message_type_size() {
543 panic!(
544 "index out of bounds: the length is {} but the index is {}",
545 self.message_type_size(),
546 i
547 );
548 }
549 DescriptorProto::from_ffi_ref(self.as_ffi().message_type(CInt::expect_from(i)))
550 }
551
552 unsafe_ffi_conversions!(ffi::FileDescriptorProto);
553}
554
555impl Drop for FileDescriptorProto {
556 fn drop(&mut self) {
557 unsafe { ffi::DeleteFileDescriptorProto(self.as_ffi_mut_ptr_unpinned()) }
558 }
559}
560
561impl MessageLite for FileDescriptorProto {}
562
563impl private::MessageLite for FileDescriptorProto {
564 fn upcast(&self) -> &ffi::MessageLite {
565 unsafe { mem::transmute(self) }
566 }
567
568 fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::MessageLite> {
569 unsafe { mem::transmute(self) }
570 }
571}
572
573impl Message for FileDescriptorProto {}
574impl private::Message for FileDescriptorProto {}
575
576/// Describes a message type.
577pub struct DescriptorProto {
578 _opaque: PhantomPinned,
579}
580
581impl Drop for DescriptorProto {
582 fn drop(&mut self) {
583 unsafe { ffi::DeleteDescriptorProto(self.as_ffi_mut_ptr_unpinned()) }
584 }
585}
586
587impl DescriptorProto {
588 /// Returns the name of tis message.
589 pub fn name(&self) -> &[u8] {
590 self.as_ffi().name().as_bytes()
591 }
592
593 unsafe_ffi_conversions!(ffi::DescriptorProto);
594}
595
596impl MessageLite for DescriptorProto {}
597
598impl private::MessageLite for DescriptorProto {
599 fn upcast(&self) -> &ffi::MessageLite {
600 unsafe { mem::transmute(self) }
601 }
602
603 fn upcast_mut(self: Pin<&mut Self>) -> Pin<&mut ffi::MessageLite> {
604 unsafe { mem::transmute(self) }
605 }
606}
607
608impl Message for DescriptorProto {}
609impl private::Message for DescriptorProto {}
610
611/// An operation failed.
612///
613/// This error does not contain details about why the operation failed or what
614/// the operation was. Unfortunately this is a limitation of the underlying
615/// `libprotobuf` APIs.
616///
617/// In some cases, you may be able to find an alternative API that returns a
618/// more descriptive error type (e.g., the APIs that return
619/// [`compiler::FileLoadError`]), but in most cases the underlying library
620/// simply provides no additional details about what went wrong.
621#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
622pub struct OperationFailedError;
623
624impl fmt::Display for OperationFailedError {
625 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
626 f.write_str("operation failed")
627 }
628}
629
630impl Error for OperationFailedError {}