From 966772278dfeb8f42004fcf612001cfe7a025b7f Mon Sep 17 00:00:00 2001 From: Justin King Date: Mon, 11 Dec 2023 11:12:57 -0800 Subject: [PATCH] Refactor value deserialization to be handle agnostic PiperOrigin-RevId: 589881956 --- base/BUILD | 1 + base/types/duration_type.cc | 26 +-- base/types/dyn_type.cc | 56 +----- base/types/map_type.cc | 52 +----- base/types/timestamp_type.cc | 26 +-- base/types/wrapper_type.cc | 107 +++--------- internal/BUILD | 14 ++ internal/deserialize.cc | 329 +++++++++++++++++++++++++++++++++++ internal/deserialize.h | 60 +++++++ 9 files changed, 443 insertions(+), 228 deletions(-) create mode 100644 internal/deserialize.cc create mode 100644 internal/deserialize.h diff --git a/base/BUILD b/base/BUILD index 6847677d8..41e2f851e 100644 --- a/base/BUILD +++ b/base/BUILD @@ -162,6 +162,7 @@ cc_library( "//common:memory", "//common:native_type", "//internal:casts", + "//internal:deserialize", "//internal:no_destructor", "//internal:number", "//internal:overloaded", diff --git a/base/types/duration_type.cc b/base/types/duration_type.cc index 76115459b..276d48cf4 100644 --- a/base/types/duration_type.cc +++ b/base/types/duration_type.cc @@ -18,16 +18,14 @@ #include "absl/time/time.h" #include "base/value_factory.h" #include "base/values/duration_value.h" -#include "internal/proto_wire.h" +#include "internal/deserialize.h" #include "internal/status_macros.h" namespace cel { namespace { -using internal::MakeProtoWireTag; -using internal::ProtoWireDecoder; -using internal::ProtoWireType; +using internal::DeserializeDuration; } // namespace @@ -36,24 +34,8 @@ CEL_INTERNAL_TYPE_IMPL(DurationType); absl::StatusOr> DurationType::NewValueFromAny( ValueFactory& value_factory, const absl::Cord& value) const { // google.protobuf.Duration. - int64_t seconds = 0; - int32_t nanos = 0; - ProtoWireDecoder decoder("google.protobuf.Duration", value); - while (decoder.HasNext()) { - CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); - if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { - CEL_ASSIGN_OR_RETURN(seconds, decoder.ReadVarint()); - continue; - } - if (tag == MakeProtoWireTag(2, ProtoWireType::kVarint)) { - CEL_ASSIGN_OR_RETURN(nanos, decoder.ReadVarint()); - continue; - } - CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); - } - decoder.EnsureFullyDecoded(); - return value_factory.CreateDurationValue(absl::Seconds(seconds) + - absl::Nanoseconds(nanos)); + CEL_ASSIGN_OR_RETURN(auto deserialized_value, DeserializeDuration(value)); + return value_factory.CreateDurationValue(deserialized_value); } } // namespace cel diff --git a/base/types/dyn_type.cc b/base/types/dyn_type.cc index 67e1ce015..b7690240b 100644 --- a/base/types/dyn_type.cc +++ b/base/types/dyn_type.cc @@ -14,20 +14,20 @@ #include "base/types/dyn_type.h" +#include + #include "absl/strings/cord.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "base/value_factory.h" -#include "internal/proto_wire.h" +#include "internal/deserialize.h" #include "internal/status_macros.h" namespace cel { namespace { -using internal::MakeProtoWireTag; -using internal::ProtoWireDecoder; -using internal::ProtoWireType; +using internal::DeserializeValue; } // namespace @@ -36,52 +36,8 @@ CEL_INTERNAL_TYPE_IMPL(DynType); absl::StatusOr> DynType::NewValueFromAny( ValueFactory& value_factory, const absl::Cord& value) const { // google.protobuf.Value. - Handle primitive = value_factory.GetNullValue(); - ProtoWireDecoder decoder("google.protobuf.Value", value); - while (decoder.HasNext()) { - CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); - if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { - CEL_ASSIGN_OR_RETURN(auto unused, decoder.ReadVarint()); - static_cast(unused); - primitive = value_factory.GetNullValue(); - continue; - } - if (tag == MakeProtoWireTag(2, ProtoWireType::kFixed64)) { - CEL_ASSIGN_OR_RETURN(auto number_value, decoder.ReadFixed64()); - primitive = value_factory.CreateDoubleValue(number_value); - continue; - } - if (tag == MakeProtoWireTag(3, ProtoWireType::kLengthDelimited)) { - CEL_ASSIGN_OR_RETURN(auto string_value, decoder.ReadLengthDelimited()); - CEL_ASSIGN_OR_RETURN(primitive, - value_factory.CreateStringValue(string_value)); - continue; - } - if (tag == MakeProtoWireTag(4, ProtoWireType::kVarint)) { - CEL_ASSIGN_OR_RETURN(auto bool_value, decoder.ReadVarint()); - primitive = value_factory.CreateBoolValue(bool_value); - continue; - } - if (tag == MakeProtoWireTag(5, ProtoWireType::kLengthDelimited)) { - CEL_ASSIGN_OR_RETURN(auto struct_value, decoder.ReadLengthDelimited()); - CEL_ASSIGN_OR_RETURN( - primitive, - value_factory.type_factory().GetJsonMapType()->NewValueFromAny( - value_factory, struct_value)); - continue; - } - if (tag == MakeProtoWireTag(6, ProtoWireType::kLengthDelimited)) { - CEL_ASSIGN_OR_RETURN(auto list_value, decoder.ReadLengthDelimited()); - CEL_ASSIGN_OR_RETURN( - primitive, - value_factory.type_factory().GetJsonListType()->NewValueFromAny( - value_factory, list_value)); - continue; - } - CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); - } - decoder.EnsureFullyDecoded(); - return primitive; + CEL_ASSIGN_OR_RETURN(auto deserialized_value, DeserializeValue(value)); + return value_factory.CreateValueFromJson(std::move(deserialized_value)); } absl::Span DynType::aliases() const { diff --git a/base/types/map_type.cc b/base/types/map_type.cc index d681a3905..c9c47735e 100644 --- a/base/types/map_type.cc +++ b/base/types/map_type.cc @@ -37,16 +37,14 @@ #include "base/values/map_value.h" #include "base/values/map_value_builder.h" #include "base/values/string_value.h" -#include "internal/proto_wire.h" +#include "internal/deserialize.h" #include "internal/status_macros.h" namespace cel { namespace { -using internal::MakeProtoWireTag; -using internal::ProtoWireDecoder; -using internal::ProtoWireType; +using internal::DeserializeStruct; } // namespace @@ -77,50 +75,8 @@ absl::StatusOr> MapType::NewValueFromAny( absl::StrCat("google.protobuf.Any cannot be deserialized as ", name())); } // google.protobuf.Struct. - CEL_ASSIGN_OR_RETURN(auto builder, NewValueBuilder(value_factory)); - ProtoWireDecoder decoder("google.protobuf.Struct", value); - while (decoder.HasNext()) { - CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); - if (tag == MakeProtoWireTag(1, ProtoWireType::kLengthDelimited)) { - // fields - CEL_ASSIGN_OR_RETURN(auto fields_value, decoder.ReadLengthDelimited()); - Handle field_name = value_factory.GetStringValue(); - Handle field_value = value_factory.GetNullValue(); - ProtoWireDecoder fields_decoder("google.protobuf.Struct.FieldsEntry", - fields_value); - while (fields_decoder.HasNext()) { - CEL_ASSIGN_OR_RETURN(auto fields_tag, fields_decoder.ReadTag()); - if (fields_tag == - MakeProtoWireTag(1, ProtoWireType::kLengthDelimited)) { - // key - CEL_ASSIGN_OR_RETURN(auto field_name_value, - fields_decoder.ReadLengthDelimited()); - CEL_ASSIGN_OR_RETURN(field_name, value_factory.CreateStringValue( - std::move(field_name_value))); - continue; - } - if (fields_tag == - MakeProtoWireTag(2, ProtoWireType::kLengthDelimited)) { - // value - CEL_ASSIGN_OR_RETURN(auto field_value_value, - fields_decoder.ReadLengthDelimited()); - CEL_ASSIGN_OR_RETURN( - field_value, - value_factory.type_factory().GetJsonValueType()->NewValueFromAny( - value_factory, field_value_value)); - continue; - } - CEL_RETURN_IF_ERROR(fields_decoder.SkipLengthValue()); - } - fields_decoder.EnsureFullyDecoded(); - CEL_RETURN_IF_ERROR( - builder->Put(std::move(field_name), std::move(field_value))); - continue; - } - CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); - } - decoder.EnsureFullyDecoded(); - return std::move(*builder).Build(); + CEL_ASSIGN_OR_RETURN(auto deserialized_value, DeserializeStruct(value)); + return value_factory.CreateMapValueFromJson(std::move(deserialized_value)); } absl::Span MapType::aliases() const { diff --git a/base/types/timestamp_type.cc b/base/types/timestamp_type.cc index 8c7a7f046..5444b36e6 100644 --- a/base/types/timestamp_type.cc +++ b/base/types/timestamp_type.cc @@ -18,16 +18,14 @@ #include "absl/time/time.h" #include "base/value_factory.h" #include "base/values/timestamp_value.h" -#include "internal/proto_wire.h" +#include "internal/deserialize.h" #include "internal/status_macros.h" namespace cel { namespace { -using internal::MakeProtoWireTag; -using internal::ProtoWireDecoder; -using internal::ProtoWireType; +using internal::DeserializeTimestamp; } // namespace @@ -36,24 +34,8 @@ CEL_INTERNAL_TYPE_IMPL(TimestampType); absl::StatusOr> TimestampType::NewValueFromAny( ValueFactory& value_factory, const absl::Cord& value) const { // google.protobuf.Timestamp. - int64_t seconds = 0; - int32_t nanos = 0; - ProtoWireDecoder decoder("google.protobuf.Timestamp", value); - while (decoder.HasNext()) { - CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); - if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { - CEL_ASSIGN_OR_RETURN(seconds, decoder.ReadVarint()); - continue; - } - if (tag == MakeProtoWireTag(2, ProtoWireType::kVarint)) { - CEL_ASSIGN_OR_RETURN(nanos, decoder.ReadVarint()); - continue; - } - CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); - } - decoder.EnsureFullyDecoded(); - return value_factory.CreateTimestampValue( - absl::UnixEpoch() + absl::Seconds(seconds) + absl::Nanoseconds(nanos)); + CEL_ASSIGN_OR_RETURN(auto deserialized_value, DeserializeTimestamp(value)); + return value_factory.CreateTimestampValue(deserialized_value); } } // namespace cel diff --git a/base/types/wrapper_type.cc b/base/types/wrapper_type.cc index f0f513ed7..59ed9db26 100644 --- a/base/types/wrapper_type.cc +++ b/base/types/wrapper_type.cc @@ -21,15 +21,19 @@ #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "base/value_factory.h" -#include "internal/proto_wire.h" +#include "internal/deserialize.h" +#include "internal/status_macros.h" namespace cel { namespace { -using internal::MakeProtoWireTag; -using internal::ProtoWireDecoder; -using internal::ProtoWireType; +using internal::DeserializeBoolValue; +using internal::DeserializeBytesValue; +using internal::DeserializeFloatValueOrDoubleValue; +using internal::DeserializeInt64Value; +using internal::DeserializeStringValue; +using internal::DeserializeUInt64Value; } // namespace @@ -143,113 +147,44 @@ absl::Span UintWrapperType::aliases() const { absl::StatusOr> BoolWrapperType::NewValueFromAny( ValueFactory& value_factory, const absl::Cord& value) const { // google.protobuf.BoolValue. - bool primitive = false; - ProtoWireDecoder decoder("google.protobuf.BoolValue", value); - while (decoder.HasNext()) { - CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); - if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { - CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadVarint()); - continue; - } - CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); - } - decoder.EnsureFullyDecoded(); - return value_factory.CreateBoolValue(primitive); + CEL_ASSIGN_OR_RETURN(auto deserialized_value, DeserializeBoolValue(value)); + return value_factory.CreateBoolValue(deserialized_value); } absl::StatusOr> DoubleWrapperType::NewValueFromAny( ValueFactory& value_factory, const absl::Cord& value) const { // google.protobuf.{FloatValue,DoubleValue}. - double primitive = 0.0; - ProtoWireDecoder decoder("google.protobuf.DoubleValue", value); - while (decoder.HasNext()) { - CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); - if (tag == MakeProtoWireTag(1, ProtoWireType::kFixed64)) { - // google.protobuf.DoubleValue - CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadFixed64()); - continue; - } - if (tag == MakeProtoWireTag(1, ProtoWireType::kFixed32)) { - // google.protobuf.FloatValue - CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadFixed32()); - continue; - } - CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); - } - decoder.EnsureFullyDecoded(); - return value_factory.CreateDoubleValue(primitive); + CEL_ASSIGN_OR_RETURN(auto deserialized_value, + DeserializeFloatValueOrDoubleValue(value)); + return value_factory.CreateDoubleValue(deserialized_value); } absl::StatusOr> IntWrapperType::NewValueFromAny( ValueFactory& value_factory, const absl::Cord& value) const { // google.protobuf.{Int32Value,Int64Value} - int64_t primitive = 0; - ProtoWireDecoder decoder("google.protobuf.Int64Value", value); - while (decoder.HasNext()) { - CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); - if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { - CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadVarint()); - continue; - } - CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); - } - decoder.EnsureFullyDecoded(); - return value_factory.CreateIntValue(primitive); + CEL_ASSIGN_OR_RETURN(auto deserialized_value, DeserializeInt64Value(value)); + return value_factory.CreateIntValue(deserialized_value); } absl::StatusOr> UintWrapperType::NewValueFromAny( ValueFactory& value_factory, const absl::Cord& value) const { // google.protobuf.{UInt32Value,UInt64Value} - uint64_t primitive = 0; - ProtoWireDecoder decoder("google.protobuf.UInt64Value", value); - while (decoder.HasNext()) { - CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); - if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { - CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadVarint()); - continue; - } - CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); - } - decoder.EnsureFullyDecoded(); - return value_factory.CreateUintValue(primitive); + CEL_ASSIGN_OR_RETURN(auto deserialized_value, DeserializeUInt64Value(value)); + return value_factory.CreateUintValue(deserialized_value); } absl::StatusOr> BytesWrapperType::NewValueFromAny( ValueFactory& value_factory, const absl::Cord& value) const { // google.protobuf.BytesValue - Handle primitive = value_factory.GetBytesValue(); - ProtoWireDecoder decoder("google.protobuf.BytesValue", value); - while (decoder.HasNext()) { - CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); - if (tag == MakeProtoWireTag(1, ProtoWireType::kLengthDelimited)) { - CEL_ASSIGN_OR_RETURN(auto primitive_value, decoder.ReadLengthDelimited()); - CEL_ASSIGN_OR_RETURN(primitive, value_factory.CreateBytesValue( - std::move(primitive_value))); - continue; - } - CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); - } - decoder.EnsureFullyDecoded(); - return primitive; + CEL_ASSIGN_OR_RETURN(auto deserialized_value, DeserializeBytesValue(value)); + return value_factory.CreateBytesValue(std::move(deserialized_value)); } absl::StatusOr> StringWrapperType::NewValueFromAny( ValueFactory& value_factory, const absl::Cord& value) const { // google.protobuf.StringValue - Handle primitive = value_factory.GetStringValue(); - ProtoWireDecoder decoder("google.protobuf.StringValue", value); - while (decoder.HasNext()) { - CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); - if (tag == MakeProtoWireTag(1, ProtoWireType::kLengthDelimited)) { - CEL_ASSIGN_OR_RETURN(auto primitive_value, decoder.ReadLengthDelimited()); - CEL_ASSIGN_OR_RETURN(primitive, value_factory.CreateStringValue( - std::move(primitive_value))); - continue; - } - CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); - } - decoder.EnsureFullyDecoded(); - return primitive; + CEL_ASSIGN_OR_RETURN(auto deserialized_value, DeserializeStringValue(value)); + return value_factory.CreateStringValue(std::move(deserialized_value)); } } // namespace cel diff --git a/internal/BUILD b/internal/BUILD index 4a15d5f2e..2a95ef96a 100644 --- a/internal/BUILD +++ b/internal/BUILD @@ -34,6 +34,20 @@ cc_test( ], ) +cc_library( + name = "deserialize", + srcs = ["deserialize.cc"], + hdrs = ["deserialize.h"], + deps = [ + ":proto_wire", + ":status_macros", + "//common:json", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings:cord", + "@com_google_absl//absl/time", + ], +) + cc_library( name = "benchmark", testonly = True, diff --git a/internal/deserialize.cc b/internal/deserialize.cc new file mode 100644 index 000000000..2039d1804 --- /dev/null +++ b/internal/deserialize.cc @@ -0,0 +1,329 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal/deserialize.h" + +#include +#include + +#include "absl/status/statusor.h" +#include "absl/strings/cord.h" +#include "absl/time/time.h" +#include "common/json.h" +#include "internal/proto_wire.h" +#include "internal/status_macros.h" + +namespace cel::internal { + +absl::StatusOr DeserializeDuration(const absl::Cord& data) { + int64_t seconds = 0; + int32_t nanos = 0; + ProtoWireDecoder decoder("google.protobuf.Duration", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { + CEL_ASSIGN_OR_RETURN(seconds, decoder.ReadVarint()); + continue; + } + if (tag == MakeProtoWireTag(2, ProtoWireType::kVarint)) { + CEL_ASSIGN_OR_RETURN(nanos, decoder.ReadVarint()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return absl::Seconds(seconds) + absl::Nanoseconds(nanos); +} + +absl::StatusOr DeserializeTimestamp(const absl::Cord& data) { + int64_t seconds = 0; + int32_t nanos = 0; + ProtoWireDecoder decoder("google.protobuf.Timestamp", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { + CEL_ASSIGN_OR_RETURN(seconds, decoder.ReadVarint()); + continue; + } + if (tag == MakeProtoWireTag(2, ProtoWireType::kVarint)) { + CEL_ASSIGN_OR_RETURN(nanos, decoder.ReadVarint()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return absl::UnixEpoch() + absl::Seconds(seconds) + absl::Nanoseconds(nanos); +} + +absl::StatusOr DeserializeBytesValue(const absl::Cord& data) { + absl::Cord primitive; + ProtoWireDecoder decoder("google.protobuf.BytesValue", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kLengthDelimited)) { + CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadLengthDelimited()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return primitive; +} + +absl::StatusOr DeserializeStringValue(const absl::Cord& data) { + absl::Cord primitive; + ProtoWireDecoder decoder("google.protobuf.StringValue", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kLengthDelimited)) { + CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadLengthDelimited()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return primitive; +} + +absl::StatusOr DeserializeBoolValue(const absl::Cord& data) { + bool primitive = false; + ProtoWireDecoder decoder("google.protobuf.BoolValue", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { + CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadVarint()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return primitive; +} + +absl::StatusOr DeserializeInt32Value(const absl::Cord& data) { + int32_t primitive = 0; + ProtoWireDecoder decoder("google.protobuf.Int32Value", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { + CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadVarint()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return primitive; +} + +absl::StatusOr DeserializeInt64Value(const absl::Cord& data) { + int64_t primitive = 0; + ProtoWireDecoder decoder("google.protobuf.Int64Value", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { + CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadVarint()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return primitive; +} + +absl::StatusOr DeserializeUInt32Value(const absl::Cord& data) { + uint32_t primitive = 0; + ProtoWireDecoder decoder("google.protobuf.UInt32Value", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { + CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadVarint()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return primitive; +} + +absl::StatusOr DeserializeUInt64Value(const absl::Cord& data) { + uint64_t primitive = 0; + ProtoWireDecoder decoder("google.protobuf.UInt64Value", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { + CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadVarint()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return primitive; +} + +absl::StatusOr DeserializeFloatValue(const absl::Cord& data) { + float primitive = 0.0f; + ProtoWireDecoder decoder("google.protobuf.FloatValue", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kFixed32)) { + CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadFixed32()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return primitive; +} + +absl::StatusOr DeserializeDoubleValue(const absl::Cord& data) { + double primitive = 0.0; + ProtoWireDecoder decoder("google.protobuf.DoubleValue", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kFixed64)) { + CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadFixed64()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return primitive; +} + +absl::StatusOr DeserializeFloatValueOrDoubleValue( + const absl::Cord& data) { + double primitive = 0.0; + ProtoWireDecoder decoder("google.protobuf.DoubleValue", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kFixed32)) { + CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadFixed32()); + continue; + } + if (tag == MakeProtoWireTag(1, ProtoWireType::kFixed64)) { + CEL_ASSIGN_OR_RETURN(primitive, decoder.ReadFixed64()); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return primitive; +} + +absl::StatusOr DeserializeValue(const absl::Cord& data) { + Json json = kJsonNull; + ProtoWireDecoder decoder("google.protobuf.Value", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kVarint)) { + CEL_ASSIGN_OR_RETURN(auto unused, decoder.ReadVarint()); + static_cast(unused); + json = kJsonNull; + continue; + } + if (tag == MakeProtoWireTag(2, ProtoWireType::kFixed64)) { + CEL_ASSIGN_OR_RETURN(auto number_value, decoder.ReadFixed64()); + json = number_value; + continue; + } + if (tag == MakeProtoWireTag(3, ProtoWireType::kLengthDelimited)) { + CEL_ASSIGN_OR_RETURN(auto string_value, decoder.ReadLengthDelimited()); + json = std::move(string_value); + continue; + } + if (tag == MakeProtoWireTag(4, ProtoWireType::kVarint)) { + CEL_ASSIGN_OR_RETURN(auto bool_value, decoder.ReadVarint()); + json = bool_value; + continue; + } + if (tag == MakeProtoWireTag(5, ProtoWireType::kLengthDelimited)) { + CEL_ASSIGN_OR_RETURN(auto struct_value, decoder.ReadLengthDelimited()); + CEL_ASSIGN_OR_RETURN(auto json_object, DeserializeStruct(struct_value)); + json = std::move(json_object); + continue; + } + if (tag == MakeProtoWireTag(6, ProtoWireType::kLengthDelimited)) { + CEL_ASSIGN_OR_RETURN(auto list_value, decoder.ReadLengthDelimited()); + CEL_ASSIGN_OR_RETURN(auto json_array, DeserializeListValue(list_value)); + json = std::move(json_array); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return json; +} + +absl::StatusOr DeserializeListValue(const absl::Cord& data) { + JsonArrayBuilder array_builder; + ProtoWireDecoder decoder("google.protobuf.ListValue", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kLengthDelimited)) { + // values + CEL_ASSIGN_OR_RETURN(auto element_value, decoder.ReadLengthDelimited()); + CEL_ASSIGN_OR_RETURN(auto element, DeserializeValue(element_value)); + array_builder.push_back(std::move(element)); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return std::move(array_builder).Build(); +} + +absl::StatusOr DeserializeStruct(const absl::Cord& data) { + JsonObjectBuilder object_builder; + ProtoWireDecoder decoder("google.protobuf.Struct", data); + while (decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto tag, decoder.ReadTag()); + if (tag == MakeProtoWireTag(1, ProtoWireType::kLengthDelimited)) { + // fields + CEL_ASSIGN_OR_RETURN(auto fields_value, decoder.ReadLengthDelimited()); + absl::Cord field_name; + Json field_value = kJsonNull; + ProtoWireDecoder fields_decoder("google.protobuf.Struct.FieldsEntry", + fields_value); + while (fields_decoder.HasNext()) { + CEL_ASSIGN_OR_RETURN(auto fields_tag, fields_decoder.ReadTag()); + if (fields_tag == + MakeProtoWireTag(1, ProtoWireType::kLengthDelimited)) { + // key + CEL_ASSIGN_OR_RETURN(field_name, + fields_decoder.ReadLengthDelimited()); + continue; + } + if (fields_tag == + MakeProtoWireTag(2, ProtoWireType::kLengthDelimited)) { + // value + CEL_ASSIGN_OR_RETURN(auto field_value_value, + fields_decoder.ReadLengthDelimited()); + CEL_ASSIGN_OR_RETURN(field_value, + DeserializeValue(field_value_value)); + continue; + } + CEL_RETURN_IF_ERROR(fields_decoder.SkipLengthValue()); + } + fields_decoder.EnsureFullyDecoded(); + object_builder.insert_or_assign(std::move(field_name), + std::move(field_value)); + continue; + } + CEL_RETURN_IF_ERROR(decoder.SkipLengthValue()); + } + decoder.EnsureFullyDecoded(); + return std::move(object_builder).Build(); +} + +} // namespace cel::internal diff --git a/internal/deserialize.h b/internal/deserialize.h new file mode 100644 index 000000000..4340d72eb --- /dev/null +++ b/internal/deserialize.h @@ -0,0 +1,60 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_CEL_CPP_INTERNAL_DESERIALIZE_H_ +#define THIRD_PARTY_CEL_CPP_INTERNAL_DESERIALIZE_H_ + +#include + +#include "absl/status/statusor.h" +#include "absl/strings/cord.h" +#include "absl/time/time.h" +#include "common/json.h" + +namespace cel::internal { + +absl::StatusOr DeserializeDuration(const absl::Cord& data); + +absl::StatusOr DeserializeTimestamp(const absl::Cord& data); + +absl::StatusOr DeserializeBytesValue(const absl::Cord& data); + +absl::StatusOr DeserializeStringValue(const absl::Cord& data); + +absl::StatusOr DeserializeBoolValue(const absl::Cord& data); + +absl::StatusOr DeserializeInt32Value(const absl::Cord& data); + +absl::StatusOr DeserializeInt64Value(const absl::Cord& data); + +absl::StatusOr DeserializeUInt32Value(const absl::Cord& data); + +absl::StatusOr DeserializeUInt64Value(const absl::Cord& data); + +absl::StatusOr DeserializeFloatValue(const absl::Cord& data); + +absl::StatusOr DeserializeDoubleValue(const absl::Cord& data); + +absl::StatusOr DeserializeFloatValueOrDoubleValue( + const absl::Cord& data); + +absl::StatusOr DeserializeValue(const absl::Cord& data); + +absl::StatusOr DeserializeListValue(const absl::Cord& data); + +absl::StatusOr DeserializeStruct(const absl::Cord& data); + +} // namespace cel::internal + +#endif // THIRD_PARTY_CEL_CPP_INTERNAL_DESERIALIZE_H_