The intent of this change is to take the best ideas from the C++ backend, such as having generator objects that can cache pre-computed state, while minimizing duplication. Where possible, we take the approach of making the C++ and UPB kernel-specific code as similar as possible, since this reduces the number of templates we need to keep in sync. PiperOrigin-RevId: 524903073pull/12484/head
parent
01aca3e606
commit
6678619d10
13 changed files with 931 additions and 326 deletions
@ -0,0 +1,67 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "google/protobuf/compiler/rust/accessors/accessors.h" |
||||
|
||||
#include <memory> |
||||
|
||||
#include "google/protobuf/compiler/rust/context.h" |
||||
#include "google/protobuf/descriptor.h" |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace rust { |
||||
std::unique_ptr<AccessorGenerator> AccessorGenerator::For( |
||||
Context<FieldDescriptor> field) { |
||||
// We do not support [ctype=FOO] (used to set the field type in C++ to
|
||||
// cord or string_piece) in V0 API.
|
||||
if (field.desc().options().has_ctype()) { |
||||
return nullptr; |
||||
} |
||||
|
||||
switch (field.desc().type()) { |
||||
case FieldDescriptor::TYPE_INT64: |
||||
case FieldDescriptor::TYPE_BOOL: |
||||
if (field.desc().is_repeated()) return nullptr; |
||||
return ForSingularScalar(field); |
||||
case FieldDescriptor::TYPE_BYTES: |
||||
if (field.desc().is_repeated() || field.is_upb()) return nullptr; |
||||
return ForSingularBytes(field); |
||||
|
||||
default: |
||||
return nullptr; |
||||
} |
||||
} |
||||
} // namespace rust
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,103 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_RUST_ACCESSORS_ACCESSORS_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_RUST_ACCESSORS_ACCESSORS_H__ |
||||
|
||||
#include <memory> |
||||
|
||||
#include "absl/log/absl_check.h" |
||||
#include "google/protobuf/compiler/rust/context.h" |
||||
#include "google/protobuf/descriptor.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace rust { |
||||
|
||||
class AccessorGenerator { |
||||
public: |
||||
AccessorGenerator() = default; |
||||
|
||||
AccessorGenerator(const AccessorGenerator &) = delete; |
||||
AccessorGenerator(AccessorGenerator &&) = delete; |
||||
AccessorGenerator &operator=(const AccessorGenerator &) = delete; |
||||
AccessorGenerator &operator=(AccessorGenerator &&) = delete; |
||||
|
||||
virtual ~AccessorGenerator(); |
||||
|
||||
// Constructs a generator for the given field.
|
||||
//
|
||||
// Returns `nullptr` if there is no known generator for this field.
|
||||
static std::unique_ptr<AccessorGenerator> For(Context<FieldDescriptor> field); |
||||
|
||||
void GenerateMsgImpl(Context<FieldDescriptor> field) const { |
||||
InMsgImpl(field); |
||||
} |
||||
void GenerateExternC(Context<FieldDescriptor> field) const { |
||||
InExternC(field); |
||||
} |
||||
void GenerateThunkCc(Context<FieldDescriptor> field) const { |
||||
ABSL_CHECK(field.is_cpp()); |
||||
InThunkCc(field); |
||||
} |
||||
|
||||
private: |
||||
// Note: the virtual functions are duplicated as non-virtual public functions,
|
||||
// so that we can customize prologue and epilogue behavior for these
|
||||
// functions. For example, consider calling `field.printer.WithVars()` as a
|
||||
// prologue to inject variables automatically.
|
||||
|
||||
// Called inside the main inherent `impl Msg {}` block.
|
||||
virtual void InMsgImpl(Context<FieldDescriptor> field) const {} |
||||
|
||||
// Called inside of a message's `extern "C" {}` block.
|
||||
virtual void InExternC(Context<FieldDescriptor> field) const {} |
||||
|
||||
// Called inside of an `extern "C" {}` block in the `.thunk.cc` file, if such
|
||||
// a file is being generated.
|
||||
virtual void InThunkCc(Context<FieldDescriptor> field) const {} |
||||
|
||||
// These static factories are defined in the corresponding implementation
|
||||
// files for each implementation of AccessorGenerator.
|
||||
static std::unique_ptr<AccessorGenerator> ForSingularScalar( |
||||
Context<FieldDescriptor> field); |
||||
static std::unique_ptr<AccessorGenerator> ForSingularBytes( |
||||
Context<FieldDescriptor> field); |
||||
}; |
||||
|
||||
inline AccessorGenerator::~AccessorGenerator() = default; |
||||
|
||||
} // namespace rust
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_RUST_ACCESSORS_ACCESSORS_H__
|
@ -0,0 +1,128 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <memory> |
||||
|
||||
#include "absl/strings/string_view.h" |
||||
#include "google/protobuf/compiler/cpp/helpers.h" |
||||
#include "google/protobuf/compiler/rust/accessors/accessors.h" |
||||
#include "google/protobuf/compiler/rust/context.h" |
||||
#include "google/protobuf/compiler/rust/naming.h" |
||||
#include "google/protobuf/descriptor.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace rust { |
||||
namespace { |
||||
class SingularBytes final : public AccessorGenerator { |
||||
public: |
||||
~SingularBytes() override = default; |
||||
|
||||
void InMsgImpl(Context<FieldDescriptor> field) const override { |
||||
field.Emit( |
||||
{ |
||||
{"field", field.desc().name()}, |
||||
{"hazzer_thunk", GetAccessorThunkName(field, "has")}, |
||||
{"getter_thunk", GetAccessorThunkName(field, "")}, |
||||
{"setter_thunk", GetAccessorThunkName(field, "set")}, |
||||
{"clearer_thunk", GetAccessorThunkName(field, "clear")}, |
||||
}, |
||||
R"rs( |
||||
pub fn $field$(&self) -> Option<&[u8]> { |
||||
if !unsafe { $hazzer_thunk$(self.msg) } { |
||||
return None; |
||||
} |
||||
unsafe { |
||||
let val = $getter_thunk$(self.msg); |
||||
Some($std$::slice::from_raw_parts(val.ptr, val.len)) |
||||
} |
||||
} |
||||
pub fn $field$_set(&mut self, val: Option<&[u8]>) { |
||||
match val { |
||||
Some(val) => unsafe { $setter_thunk$(self.msg, val.as_ptr(), val.len()) }, |
||||
None => unsafe { $clearer_thunk$(self.msg) }, |
||||
} |
||||
} |
||||
)rs"); |
||||
} |
||||
|
||||
void InExternC(Context<FieldDescriptor> field) const override { |
||||
field.Emit( |
||||
{ |
||||
{"hazzer_thunk", GetAccessorThunkName(field, "has")}, |
||||
{"getter_thunk", GetAccessorThunkName(field, "")}, |
||||
{"setter_thunk", GetAccessorThunkName(field, "set")}, |
||||
{"clearer_thunk", GetAccessorThunkName(field, "clear")}, |
||||
}, |
||||
R"rs( |
||||
fn $hazzer_thunk$(raw_msg: $NonNull$<u8>) -> bool; |
||||
fn $getter_thunk$(raw_msg: $NonNull$<u8>) -> $pb$::PtrAndLen; |
||||
fn $setter_thunk$(raw_msg: $NonNull$<u8>, val: *const u8, len: usize); |
||||
fn $clearer_thunk$(raw_msg: $NonNull$<u8>); |
||||
)rs"); |
||||
} |
||||
|
||||
void InThunkCc(Context<FieldDescriptor> field) const override { |
||||
field.Emit( |
||||
{ |
||||
{"field", field.desc().name()}, |
||||
{"namespace", cpp::Namespace(field.desc().containing_type())}, |
||||
{"hazzer_thunk", GetAccessorThunkName(field, "has")}, |
||||
{"getter_thunk", GetAccessorThunkName(field, "")}, |
||||
{"setter_thunk", GetAccessorThunkName(field, "set")}, |
||||
{"clearer_thunk", GetAccessorThunkName(field, "clear")}, |
||||
}, |
||||
R"cc( |
||||
bool $hazzer_thunk$($namespace$::$Msg$* msg) { |
||||
return msg->has_$field$(); |
||||
} |
||||
::google::protobuf::rust_internal::PtrAndLen $getter_thunk$($namespace$::$Msg$* msg) { |
||||
absl::string_view val = msg->$field$(); |
||||
return google::protobuf::rust_internal::PtrAndLen(val.data(), val.size()); |
||||
} |
||||
void $setter_thunk$($namespace$::$Msg$* msg, const char* ptr, |
||||
::std::size_t size) { |
||||
msg->set_$field$(absl::string_view(ptr, size)); |
||||
} |
||||
void $clearer_thunk$($namespace$::$Msg$* msg) { msg->clear_$field$(); } |
||||
)cc"); |
||||
} |
||||
}; |
||||
} // namespace
|
||||
|
||||
std::unique_ptr<AccessorGenerator> AccessorGenerator::ForSingularBytes( |
||||
Context<FieldDescriptor> field) { |
||||
return std::make_unique<SingularBytes>(); |
||||
} |
||||
} // namespace rust
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,124 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <memory> |
||||
|
||||
#include "absl/strings/string_view.h" |
||||
#include "google/protobuf/compiler/cpp/helpers.h" |
||||
#include "google/protobuf/compiler/rust/accessors/accessors.h" |
||||
#include "google/protobuf/compiler/rust/context.h" |
||||
#include "google/protobuf/compiler/rust/naming.h" |
||||
#include "google/protobuf/descriptor.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace rust { |
||||
namespace { |
||||
class SingularScalar final : public AccessorGenerator { |
||||
public: |
||||
~SingularScalar() override = default; |
||||
|
||||
void InMsgImpl(Context<FieldDescriptor> field) const override { |
||||
field.Emit( |
||||
{ |
||||
{"field", field.desc().name()}, |
||||
{"Scalar", PrimitiveRsTypeName(field)}, |
||||
{"hazzer_thunk", GetAccessorThunkName(field, "has")}, |
||||
{"getter_thunk", GetAccessorThunkName(field, "")}, |
||||
{"setter_thunk", GetAccessorThunkName(field, "set")}, |
||||
{"clearer_thunk", GetAccessorThunkName(field, "clear")}, |
||||
}, |
||||
R"rs( |
||||
pub fn $field$(&self) -> Option<$Scalar$> { |
||||
if !unsafe { $hazzer_thunk$(self.msg) } { |
||||
return None; |
||||
} |
||||
Some(unsafe { $getter_thunk$(self.msg) }) |
||||
} |
||||
pub fn $field$_set(&mut self, val: Option<$Scalar$>) { |
||||
match val { |
||||
Some(val) => unsafe { $setter_thunk$(self.msg, val) }, |
||||
None => unsafe { $clearer_thunk$(self.msg) }, |
||||
} |
||||
} |
||||
)rs"); |
||||
} |
||||
|
||||
void InExternC(Context<FieldDescriptor> field) const override { |
||||
field.Emit( |
||||
{ |
||||
{"Scalar", PrimitiveRsTypeName(field)}, |
||||
{"hazzer_thunk", GetAccessorThunkName(field, "has")}, |
||||
{"getter_thunk", GetAccessorThunkName(field, "")}, |
||||
{"setter_thunk", GetAccessorThunkName(field, "set")}, |
||||
{"clearer_thunk", GetAccessorThunkName(field, "clear")}, |
||||
}, |
||||
R"rs( |
||||
fn $hazzer_thunk$(raw_msg: $NonNull$<u8>) -> bool; |
||||
fn $getter_thunk$(raw_msg: $NonNull$<u8>) -> $Scalar$; |
||||
fn $setter_thunk$(raw_msg: $NonNull$<u8>, val: $Scalar$); |
||||
fn $clearer_thunk$(raw_msg: $NonNull$<u8>); |
||||
)rs"); |
||||
} |
||||
|
||||
void InThunkCc(Context<FieldDescriptor> field) const override { |
||||
field.Emit( |
||||
{ |
||||
{"field", field.desc().name()}, |
||||
{"Scalar", cpp::PrimitiveTypeName(field.desc().cpp_type())}, |
||||
{"namespace", cpp::Namespace(field.desc().containing_type())}, |
||||
{"hazzer_thunk", GetAccessorThunkName(field, "has")}, |
||||
{"getter_thunk", GetAccessorThunkName(field, "")}, |
||||
{"setter_thunk", GetAccessorThunkName(field, "set")}, |
||||
{"clearer_thunk", GetAccessorThunkName(field, "clear")}, |
||||
}, |
||||
R"cc( |
||||
bool $hazzer_thunk$($namespace$::$Msg$* msg) { |
||||
return msg->has_$field$(); |
||||
} |
||||
$Scalar$ $getter_thunk$($namespace$::$Msg$* msg) { return msg->$field$(); } |
||||
void $setter_thunk$($namespace$::$Msg$* msg, $Scalar$ val) { |
||||
msg->set_$field$(val); |
||||
} |
||||
void $clearer_thunk$($namespace$::$Msg$* msg) { msg->clear_$field$(); } |
||||
)cc"); |
||||
} |
||||
}; |
||||
} // namespace
|
||||
|
||||
std::unique_ptr<AccessorGenerator> AccessorGenerator::ForSingularScalar( |
||||
Context<FieldDescriptor> field) { |
||||
return std::make_unique<SingularScalar>(); |
||||
} |
||||
} // namespace rust
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,302 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "google/protobuf/compiler/rust/message.h" |
||||
|
||||
#include "absl/log/absl_check.h" |
||||
#include "absl/log/absl_log.h" |
||||
#include "google/protobuf/compiler/cpp/names.h" |
||||
#include "google/protobuf/compiler/rust/accessors/accessors.h" |
||||
#include "google/protobuf/compiler/rust/context.h" |
||||
#include "google/protobuf/compiler/rust/naming.h" |
||||
#include "google/protobuf/descriptor.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace rust { |
||||
namespace { |
||||
void MessageStructFields(Context<Descriptor> msg) { |
||||
switch (msg.opts().kernel) { |
||||
case Kernel::kCpp: |
||||
msg.Emit(R"rs( |
||||
msg: $NonNull$<u8>, |
||||
)rs"); |
||||
return; |
||||
|
||||
case Kernel::kUpb: |
||||
msg.Emit(R"rs( |
||||
msg: $NonNull$<u8>, |
||||
arena: *mut $pb$::Arena, |
||||
)rs"); |
||||
return; |
||||
} |
||||
|
||||
ABSL_LOG(FATAL) << "unreachable"; |
||||
} |
||||
|
||||
void MessageNew(Context<Descriptor> msg) { |
||||
switch (msg.opts().kernel) { |
||||
case Kernel::kCpp: |
||||
msg.Emit(R"rs( |
||||
Self { msg: unsafe { __rust_proto_thunk__$pkg_Msg$__new() } } |
||||
)rs"); |
||||
return; |
||||
|
||||
case Kernel::kUpb: |
||||
msg.Emit(R"rs( |
||||
let arena = unsafe { $pb$::Arena::new() }; |
||||
let msg = unsafe { $pkg_Msg$_new(arena) }; |
||||
$Msg$ { msg, arena } |
||||
)rs"); |
||||
return; |
||||
} |
||||
|
||||
ABSL_LOG(FATAL) << "unreachable"; |
||||
} |
||||
|
||||
void MessageSerialize(Context<Descriptor> msg) { |
||||
switch (msg.opts().kernel) { |
||||
case Kernel::kCpp: |
||||
msg.Emit(R"rs( |
||||
unsafe { __rust_proto_thunk__$pkg_Msg$__serialize(self.msg) } |
||||
)rs"); |
||||
return; |
||||
|
||||
case Kernel::kUpb: |
||||
msg.Emit(R"rs( |
||||
let arena = unsafe { $pb$::__runtime::upb_Arena_New() }; |
||||
let mut len = 0; |
||||
unsafe { |
||||
let data = $pkg_Msg$_serialize(self.msg, arena, &mut len); |
||||
$pb$::SerializedData::from_raw_parts(arena, data, len) |
||||
} |
||||
)rs"); |
||||
return; |
||||
} |
||||
|
||||
ABSL_LOG(FATAL) << "unreachable"; |
||||
} |
||||
|
||||
void MessageDeserialize(Context<Descriptor> msg) { |
||||
switch (msg.opts().kernel) { |
||||
case Kernel::kCpp: |
||||
msg.Emit(R"rs( |
||||
let success = unsafe { |
||||
let data = $pb$::SerializedData::from_raw_parts( |
||||
$NonNull$::new(data.as_ptr() as *mut _).unwrap(), |
||||
data.len(), |
||||
); |
||||
|
||||
__rust_proto_thunk__$pkg_Msg$__deserialize(self.msg, data) |
||||
}; |
||||
success.then_some(()).ok_or($pb$::ParseError) |
||||
)rs"); |
||||
return; |
||||
|
||||
case Kernel::kUpb: |
||||
msg.Emit(R"rs( |
||||
let _ = data; |
||||
$std$::unimplemented!() |
||||
)rs"); |
||||
return; |
||||
} |
||||
|
||||
ABSL_LOG(FATAL) << "unreachable"; |
||||
} |
||||
|
||||
void MessageExterns(Context<Descriptor> msg) { |
||||
switch (msg.opts().kernel) { |
||||
case Kernel::kCpp: |
||||
msg.Emit(R"rs( |
||||
fn __rust_proto_thunk__$pkg_Msg$__new() -> $NonNull$<u8>; |
||||
fn __rust_proto_thunk__$pkg_Msg$__serialize(raw_msg: $NonNull$<u8>) |
||||
-> $pb$::SerializedData; |
||||
fn __rust_proto_thunk__$pkg_Msg$__deserialize( |
||||
raw_msg: $NonNull$<u8>, |
||||
data: $pb$::SerializedData, |
||||
) -> bool; |
||||
)rs"); |
||||
return; |
||||
|
||||
case Kernel::kUpb: |
||||
msg.Emit(R"rs( |
||||
fn $pkg_Msg$_new(arena: *mut $pb$::Arena) -> $NonNull$<u8>; |
||||
fn $pkg_Msg$_serialize( |
||||
msg: $NonNull$<u8>, |
||||
arena: *mut $pb$::Arena, |
||||
len: &mut usize) -> $NonNull$<u8>; |
||||
)rs"); |
||||
return; |
||||
} |
||||
|
||||
ABSL_LOG(FATAL) << "unreachable"; |
||||
} |
||||
} // namespace
|
||||
|
||||
MessageGenerator::MessageGenerator(Context<Descriptor> msg) { |
||||
accessors_.resize(msg.desc().field_count()); |
||||
for (int i = 0; i < msg.desc().field_count(); ++i) { |
||||
auto field = msg.WithDesc(msg.desc().field(i)); |
||||
accessors_[i] = AccessorGenerator::For(field); |
||||
if (accessors_[i] == nullptr) { |
||||
ABSL_LOG(WARNING) << "unsupported field: " << field.desc().full_name(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void MessageGenerator::GenerateRs(Context<Descriptor> msg) { |
||||
msg.Emit( |
||||
{ |
||||
{"Msg", msg.desc().name()}, |
||||
{"pkg_Msg", GetUnderscoreDelimitedFullName(msg)}, |
||||
{"Msg.fields", [&] { MessageStructFields(msg); }}, |
||||
{"Msg::new", [&] { MessageNew(msg); }}, |
||||
{"Msg::serialize", [&] { MessageSerialize(msg); }}, |
||||
{"Msg::deserialize", [&] { MessageDeserialize(msg); }}, |
||||
{"Msg_externs", [&] { MessageExterns(msg); }}, |
||||
{"accessor_fns", |
||||
[&] { |
||||
for (int i = 0; i < msg.desc().field_count(); ++i) { |
||||
auto& gen = accessors_[i]; |
||||
auto field = msg.WithDesc(*msg.desc().field(i)); |
||||
msg.Emit({{"comment", FieldInfoComment(field)}}, R"rs( |
||||
// $comment$
|
||||
)rs"); |
||||
|
||||
if (gen == nullptr) { |
||||
msg.Emit({{"field", field.desc().full_name()}}, R"rs( |
||||
// Unsupported! :(
|
||||
)rs"); |
||||
msg.printer().PrintRaw("\n"); |
||||
continue; |
||||
} |
||||
|
||||
gen->GenerateMsgImpl(field); |
||||
msg.printer().PrintRaw("\n"); |
||||
} |
||||
}}, |
||||
{"accessor_externs", |
||||
[&] { |
||||
for (int i = 0; i < msg.desc().field_count(); ++i) { |
||||
auto& gen = accessors_[i]; |
||||
if (gen == nullptr) continue; |
||||
|
||||
gen->GenerateExternC(msg.WithDesc(*msg.desc().field(i))); |
||||
msg.printer().PrintRaw("\n"); |
||||
} |
||||
}}, |
||||
}, |
||||
R"rs( |
||||
#[allow(non_camel_case_types)] |
||||
pub struct $Msg$ { |
||||
$Msg.fields$ |
||||
} |
||||
|
||||
impl $Msg$ { |
||||
pub fn new() -> Self { |
||||
$Msg::new$ |
||||
} |
||||
|
||||
pub fn serialize(&self) -> $pb$::SerializedData { |
||||
$Msg::serialize$ |
||||
} |
||||
pub fn deserialize(&mut self, data: &[u8]) -> Result<(), $pb$::ParseError> { |
||||
$Msg::deserialize$ |
||||
} |
||||
|
||||
$accessor_fns$ |
||||
} // impl $Msg$
|
||||
|
||||
extern "C" { |
||||
$Msg_externs$ |
||||
|
||||
$accessor_externs$ |
||||
} // extern "C" for $Msg$
|
||||
)rs"); |
||||
|
||||
if (msg.is_cpp()) { |
||||
msg.printer().PrintRaw("\n"); |
||||
msg.Emit({{"Msg", msg.desc().name()}}, R"rs( |
||||
impl $Msg$ { |
||||
pub fn __unstable_cpp_repr_grant_permission_to_break(&mut self) -> $NonNull$<u8> { |
||||
self.msg |
||||
} |
||||
} |
||||
)rs"); |
||||
} |
||||
} |
||||
|
||||
// Generates code for a particular message in `.pb.thunk.cc`.
|
||||
void MessageGenerator::GenerateThunkCc(Context<Descriptor> msg) { |
||||
ABSL_CHECK(msg.is_cpp()); |
||||
|
||||
msg.Emit( |
||||
{ |
||||
{"abi", "\"C\""}, // Workaround for syntax highlight bug in VSCode.
|
||||
{"Msg", msg.desc().name()}, |
||||
{"pkg_Msg", GetUnderscoreDelimitedFullName(msg)}, |
||||
{"namespace", cpp::Namespace(&msg.desc())}, |
||||
{"accessor_thunks", |
||||
[&] { |
||||
for (int i = 0; i < msg.desc().field_count(); ++i) { |
||||
auto& gen = accessors_[i]; |
||||
if (gen == nullptr) continue; |
||||
|
||||
gen->GenerateThunkCc(msg.WithDesc(*msg.desc().field(i))); |
||||
} |
||||
}}, |
||||
}, |
||||
R"cc( |
||||
extern $abi$ { |
||||
void* __rust_proto_thunk__$pkg_Msg$__new() { |
||||
return new $namespace$::$Msg$(); |
||||
} |
||||
|
||||
google::protobuf::rust_internal::SerializedData |
||||
__rust_proto_thunk__$pkg_Msg$__serialize($namespace$::$Msg$ * msg) { |
||||
return google::protobuf::rust_internal::SerializeMsg(msg); |
||||
} |
||||
|
||||
bool __rust_proto_thunk__$pkg_Msg$__deserialize( |
||||
$namespace$::$Msg$ * msg, |
||||
google::protobuf::rust_internal::SerializedData data) { |
||||
return msg->ParseFromArray(data.data, data.len); |
||||
} |
||||
|
||||
$accessor_thunks$ |
||||
} // extern $abi$
|
||||
)cc"); |
||||
} |
||||
|
||||
} // namespace rust
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,65 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2023 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_RUST_MESSAGE_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_RUST_MESSAGE_H__ |
||||
|
||||
#include <memory> |
||||
#include <vector> |
||||
|
||||
#include "google/protobuf/compiler/rust/accessors/accessors.h" |
||||
#include "google/protobuf/compiler/rust/context.h" |
||||
#include "google/protobuf/descriptor.h" |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace rust { |
||||
|
||||
class MessageGenerator final { |
||||
public: |
||||
explicit MessageGenerator(Context<Descriptor> msg); |
||||
|
||||
// Generates code for a particular message in `.pb.rs`.
|
||||
void GenerateRs(Context<Descriptor> msg); |
||||
|
||||
// Generates code for a particular message in `.pb.thunk.cc`.
|
||||
void GenerateThunkCc(Context<Descriptor> msg); |
||||
|
||||
private: |
||||
std::vector<std::unique_ptr<AccessorGenerator>> accessors_; |
||||
}; |
||||
|
||||
} // namespace rust
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_RUST_MESSAGE_H__
|
Loading…
Reference in new issue