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 {}