aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar rsgowman <rgowman@google.com>2018-02-13 17:46:09 -0500
committerGravatar GitHub <noreply@github.com>2018-02-13 17:46:09 -0500
commitfe19fca0e521e3765e4ecf6a87b0a3d622a52b92 (patch)
tree24a4485215689063c94d40c764e08f9dee4758ca
parent95d0411e207e3eea64c035258745021ae20b676a (diff)
Serialize and deserialize null (#783)
* Build (grpc's) nanopb with -DPB_FIELD_16BIT We require (at least) 16 bit fields. (By default, nanopb uses 8 bit fields, ie allowing up to 256 field tags.) Also note that this patch adds this to grpc's nanopb, rather than to our nanopb. We'll need to eventually either: a) we instruct grpc to use our nanopb b) we rely on grpc's nanopb instead of using our own. (^ marked as a TODO for now.) * Add some dependant protos Imported from protobuf. Nanopb requires these to be present (though anything using libprotobuf does not, as these are already built into that.) * Add generated nanopb protos based off of newly added proto definitions * Build the nanopb protos * Serialize and deserialize null
-rw-r--r--Firestore/CMakeLists.txt1
-rw-r--r--Firestore/Protos/CMakeLists.txt45
-rw-r--r--Firestore/Protos/nanopb/google/protobuf/any.pb.c36
-rw-r--r--Firestore/Protos/nanopb/google/protobuf/any.pb.h69
-rw-r--r--Firestore/Protos/nanopb/google/protobuf/empty.pb.c34
-rw-r--r--Firestore/Protos/nanopb/google/protobuf/empty.pb.h66
-rw-r--r--Firestore/Protos/nanopb/google/protobuf/wrappers.pb.c81
-rw-r--r--Firestore/Protos/nanopb/google/protobuf/wrappers.pb.h147
-rw-r--r--Firestore/Protos/protos/google/protobuf/any.proto149
-rw-r--r--Firestore/Protos/protos/google/protobuf/empty.proto52
-rw-r--r--Firestore/Protos/protos/google/protobuf/wrappers.proto118
-rw-r--r--Firestore/core/src/firebase/firestore/remote/CMakeLists.txt2
-rw-r--r--Firestore/core/src/firebase/firestore/remote/serializer.cc88
-rw-r--r--Firestore/core/src/firebase/firestore/remote/serializer.h112
-rw-r--r--Firestore/core/test/firebase/firestore/remote/serializer_test.cc71
-rw-r--r--cmake/external/grpc.cmake10
16 files changed, 1069 insertions, 12 deletions
diff --git a/Firestore/CMakeLists.txt b/Firestore/CMakeLists.txt
index 25f27fa..28ac08f 100644
--- a/Firestore/CMakeLists.txt
+++ b/Firestore/CMakeLists.txt
@@ -68,3 +68,4 @@ include_directories(${FIREBASE_SOURCE_DIR})
include_directories(${FIREBASE_SOURCE_DIR}/Firestore/Protos/nanopb)
add_subdirectory(core)
+add_subdirectory(Protos)
diff --git a/Firestore/Protos/CMakeLists.txt b/Firestore/Protos/CMakeLists.txt
new file mode 100644
index 0000000..f20f702
--- /dev/null
+++ b/Firestore/Protos/CMakeLists.txt
@@ -0,0 +1,45 @@
+cc_library(
+ firebase_firestore_protos_nanopb
+ SOURCES
+ nanopb/firestore/local/maybe_document.pb.c
+ nanopb/firestore/local/maybe_document.pb.h
+ nanopb/firestore/local/mutation.pb.c
+ nanopb/firestore/local/mutation.pb.h
+ nanopb/firestore/local/target.pb.c
+ nanopb/firestore/local/target.pb.h
+ nanopb/google/api/annotations.pb.c
+ nanopb/google/api/annotations.pb.h
+ nanopb/google/api/http.pb.c
+ nanopb/google/api/http.pb.h
+ nanopb/google/firestore/v1beta1/common.pb.c
+ nanopb/google/firestore/v1beta1/common.pb.h
+ nanopb/google/firestore/v1beta1/document.pb.c
+ nanopb/google/firestore/v1beta1/document.pb.h
+ nanopb/google/firestore/v1beta1/firestore.pb.c
+ nanopb/google/firestore/v1beta1/firestore.pb.h
+ nanopb/google/firestore/v1beta1/query.pb.c
+ nanopb/google/firestore/v1beta1/query.pb.h
+ nanopb/google/firestore/v1beta1/write.pb.c
+ nanopb/google/firestore/v1beta1/write.pb.h
+ nanopb/google/protobuf/any.pb.c
+ nanopb/google/protobuf/any.pb.h
+ nanopb/google/protobuf/empty.pb.c
+ nanopb/google/protobuf/empty.pb.h
+ nanopb/google/protobuf/struct.pb.c
+ nanopb/google/protobuf/struct.pb.h
+ nanopb/google/protobuf/timestamp.pb.c
+ nanopb/google/protobuf/timestamp.pb.h
+ nanopb/google/protobuf/wrappers.pb.c
+ nanopb/google/protobuf/wrappers.pb.h
+ nanopb/google/rpc/status.pb.c
+ nanopb/google/rpc/status.pb.h
+ nanopb/google/type/latlng.pb.c
+ nanopb/google/type/latlng.pb.h
+ DEPENDS
+ nanopb
+)
+
+target_compile_definitions(
+ firebase_firestore_protos_nanopb PUBLIC
+ -DPB_FIELD_16BIT
+)
diff --git a/Firestore/Protos/nanopb/google/protobuf/any.pb.c b/Firestore/Protos/nanopb/google/protobuf/any.pb.c
new file mode 100644
index 0000000..b28d0ba
--- /dev/null
+++ b/Firestore/Protos/nanopb/google/protobuf/any.pb.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+ *
+ * http://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.
+ */
+
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.3.8 at Mon Feb 12 11:03:06 2018. */
+
+#include "any.pb.h"
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+
+const pb_field_t google_protobuf_Any_fields[3] = {
+ PB_FIELD( 1, STRING , SINGULAR, CALLBACK, FIRST, google_protobuf_Any, type_url, type_url, 0),
+ PB_FIELD( 2, BYTES , SINGULAR, CALLBACK, OTHER, google_protobuf_Any, value, type_url, 0),
+ PB_LAST_FIELD
+};
+
+
+/* @@protoc_insertion_point(eof) */
diff --git a/Firestore/Protos/nanopb/google/protobuf/any.pb.h b/Firestore/Protos/nanopb/google/protobuf/any.pb.h
new file mode 100644
index 0000000..10a722e
--- /dev/null
+++ b/Firestore/Protos/nanopb/google/protobuf/any.pb.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+ *
+ * http://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.
+ */
+
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.3.8 at Mon Feb 12 11:03:06 2018. */
+
+#ifndef PB_GOOGLE_PROTOBUF_ANY_PB_H_INCLUDED
+#define PB_GOOGLE_PROTOBUF_ANY_PB_H_INCLUDED
+#include <pb.h>
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Struct definitions */
+typedef struct _google_protobuf_Any {
+ pb_callback_t type_url;
+ pb_callback_t value;
+/* @@protoc_insertion_point(struct:google_protobuf_Any) */
+} google_protobuf_Any;
+
+/* Default values for struct fields */
+
+/* Initializer values for message structs */
+#define google_protobuf_Any_init_default {{{NULL}, NULL}, {{NULL}, NULL}}
+#define google_protobuf_Any_init_zero {{{NULL}, NULL}, {{NULL}, NULL}}
+
+/* Field tags (for use in manual encoding/decoding) */
+#define google_protobuf_Any_type_url_tag 1
+#define google_protobuf_Any_value_tag 2
+
+/* Struct field encoding specification for nanopb */
+extern const pb_field_t google_protobuf_Any_fields[3];
+
+/* Maximum encoded size of messages (where known) */
+/* google_protobuf_Any_size depends on runtime parameters */
+
+/* Message IDs (where set with "msgid" option) */
+#ifdef PB_MSGID
+
+#define ANY_MESSAGES \
+
+
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+/* @@protoc_insertion_point(eof) */
+
+#endif
diff --git a/Firestore/Protos/nanopb/google/protobuf/empty.pb.c b/Firestore/Protos/nanopb/google/protobuf/empty.pb.c
new file mode 100644
index 0000000..050af9c
--- /dev/null
+++ b/Firestore/Protos/nanopb/google/protobuf/empty.pb.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+ *
+ * http://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.
+ */
+
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.3.8 at Mon Feb 12 11:03:06 2018. */
+
+#include "empty.pb.h"
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+
+const pb_field_t google_protobuf_Empty_fields[1] = {
+ PB_LAST_FIELD
+};
+
+
+/* @@protoc_insertion_point(eof) */
diff --git a/Firestore/Protos/nanopb/google/protobuf/empty.pb.h b/Firestore/Protos/nanopb/google/protobuf/empty.pb.h
new file mode 100644
index 0000000..466e1fd
--- /dev/null
+++ b/Firestore/Protos/nanopb/google/protobuf/empty.pb.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+ *
+ * http://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.
+ */
+
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.3.8 at Mon Feb 12 11:03:06 2018. */
+
+#ifndef PB_GOOGLE_PROTOBUF_EMPTY_PB_H_INCLUDED
+#define PB_GOOGLE_PROTOBUF_EMPTY_PB_H_INCLUDED
+#include <pb.h>
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Struct definitions */
+typedef struct _google_protobuf_Empty {
+ char dummy_field;
+/* @@protoc_insertion_point(struct:google_protobuf_Empty) */
+} google_protobuf_Empty;
+
+/* Default values for struct fields */
+
+/* Initializer values for message structs */
+#define google_protobuf_Empty_init_default {0}
+#define google_protobuf_Empty_init_zero {0}
+
+/* Field tags (for use in manual encoding/decoding) */
+
+/* Struct field encoding specification for nanopb */
+extern const pb_field_t google_protobuf_Empty_fields[1];
+
+/* Maximum encoded size of messages (where known) */
+#define google_protobuf_Empty_size 0
+
+/* Message IDs (where set with "msgid" option) */
+#ifdef PB_MSGID
+
+#define EMPTY_MESSAGES \
+
+
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+/* @@protoc_insertion_point(eof) */
+
+#endif
diff --git a/Firestore/Protos/nanopb/google/protobuf/wrappers.pb.c b/Firestore/Protos/nanopb/google/protobuf/wrappers.pb.c
new file mode 100644
index 0000000..41ab3c6
--- /dev/null
+++ b/Firestore/Protos/nanopb/google/protobuf/wrappers.pb.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+ *
+ * http://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.
+ */
+
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.3.8 at Mon Feb 12 11:03:06 2018. */
+
+#include "wrappers.pb.h"
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+
+const pb_field_t google_protobuf_DoubleValue_fields[2] = {
+ PB_FIELD( 1, DOUBLE , SINGULAR, STATIC , FIRST, google_protobuf_DoubleValue, value, value, 0),
+ PB_LAST_FIELD
+};
+
+const pb_field_t google_protobuf_FloatValue_fields[2] = {
+ PB_FIELD( 1, FLOAT , SINGULAR, STATIC , FIRST, google_protobuf_FloatValue, value, value, 0),
+ PB_LAST_FIELD
+};
+
+const pb_field_t google_protobuf_Int64Value_fields[2] = {
+ PB_FIELD( 1, INT64 , SINGULAR, STATIC , FIRST, google_protobuf_Int64Value, value, value, 0),
+ PB_LAST_FIELD
+};
+
+const pb_field_t google_protobuf_UInt64Value_fields[2] = {
+ PB_FIELD( 1, UINT64 , SINGULAR, STATIC , FIRST, google_protobuf_UInt64Value, value, value, 0),
+ PB_LAST_FIELD
+};
+
+const pb_field_t google_protobuf_Int32Value_fields[2] = {
+ PB_FIELD( 1, INT32 , SINGULAR, STATIC , FIRST, google_protobuf_Int32Value, value, value, 0),
+ PB_LAST_FIELD
+};
+
+const pb_field_t google_protobuf_UInt32Value_fields[2] = {
+ PB_FIELD( 1, UINT32 , SINGULAR, STATIC , FIRST, google_protobuf_UInt32Value, value, value, 0),
+ PB_LAST_FIELD
+};
+
+const pb_field_t google_protobuf_BoolValue_fields[2] = {
+ PB_FIELD( 1, BOOL , SINGULAR, STATIC , FIRST, google_protobuf_BoolValue, value, value, 0),
+ PB_LAST_FIELD
+};
+
+const pb_field_t google_protobuf_StringValue_fields[2] = {
+ PB_FIELD( 1, STRING , SINGULAR, CALLBACK, FIRST, google_protobuf_StringValue, value, value, 0),
+ PB_LAST_FIELD
+};
+
+const pb_field_t google_protobuf_BytesValue_fields[2] = {
+ PB_FIELD( 1, BYTES , SINGULAR, CALLBACK, FIRST, google_protobuf_BytesValue, value, value, 0),
+ PB_LAST_FIELD
+};
+
+
+/* On some platforms (such as AVR), double is really float.
+ * These are not directly supported by nanopb, but see example_avr_double.
+ * To get rid of this error, remove any double fields from your .proto.
+ */
+PB_STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES)
+
+/* @@protoc_insertion_point(eof) */
diff --git a/Firestore/Protos/nanopb/google/protobuf/wrappers.pb.h b/Firestore/Protos/nanopb/google/protobuf/wrappers.pb.h
new file mode 100644
index 0000000..0e98785
--- /dev/null
+++ b/Firestore/Protos/nanopb/google/protobuf/wrappers.pb.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2018 Google
+ *
+ * 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
+ *
+ * http://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.
+ */
+
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.3.8 at Mon Feb 12 11:03:06 2018. */
+
+#ifndef PB_GOOGLE_PROTOBUF_WRAPPERS_PB_H_INCLUDED
+#define PB_GOOGLE_PROTOBUF_WRAPPERS_PB_H_INCLUDED
+#include <pb.h>
+
+/* @@protoc_insertion_point(includes) */
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Struct definitions */
+typedef struct _google_protobuf_BytesValue {
+ pb_callback_t value;
+/* @@protoc_insertion_point(struct:google_protobuf_BytesValue) */
+} google_protobuf_BytesValue;
+
+typedef struct _google_protobuf_StringValue {
+ pb_callback_t value;
+/* @@protoc_insertion_point(struct:google_protobuf_StringValue) */
+} google_protobuf_StringValue;
+
+typedef struct _google_protobuf_BoolValue {
+ bool value;
+/* @@protoc_insertion_point(struct:google_protobuf_BoolValue) */
+} google_protobuf_BoolValue;
+
+typedef struct _google_protobuf_DoubleValue {
+ double value;
+/* @@protoc_insertion_point(struct:google_protobuf_DoubleValue) */
+} google_protobuf_DoubleValue;
+
+typedef struct _google_protobuf_FloatValue {
+ float value;
+/* @@protoc_insertion_point(struct:google_protobuf_FloatValue) */
+} google_protobuf_FloatValue;
+
+typedef struct _google_protobuf_Int32Value {
+ int32_t value;
+/* @@protoc_insertion_point(struct:google_protobuf_Int32Value) */
+} google_protobuf_Int32Value;
+
+typedef struct _google_protobuf_Int64Value {
+ int64_t value;
+/* @@protoc_insertion_point(struct:google_protobuf_Int64Value) */
+} google_protobuf_Int64Value;
+
+typedef struct _google_protobuf_UInt32Value {
+ uint32_t value;
+/* @@protoc_insertion_point(struct:google_protobuf_UInt32Value) */
+} google_protobuf_UInt32Value;
+
+typedef struct _google_protobuf_UInt64Value {
+ uint64_t value;
+/* @@protoc_insertion_point(struct:google_protobuf_UInt64Value) */
+} google_protobuf_UInt64Value;
+
+/* Default values for struct fields */
+
+/* Initializer values for message structs */
+#define google_protobuf_DoubleValue_init_default {0}
+#define google_protobuf_FloatValue_init_default {0}
+#define google_protobuf_Int64Value_init_default {0}
+#define google_protobuf_UInt64Value_init_default {0}
+#define google_protobuf_Int32Value_init_default {0}
+#define google_protobuf_UInt32Value_init_default {0}
+#define google_protobuf_BoolValue_init_default {0}
+#define google_protobuf_StringValue_init_default {{{NULL}, NULL}}
+#define google_protobuf_BytesValue_init_default {{{NULL}, NULL}}
+#define google_protobuf_DoubleValue_init_zero {0}
+#define google_protobuf_FloatValue_init_zero {0}
+#define google_protobuf_Int64Value_init_zero {0}
+#define google_protobuf_UInt64Value_init_zero {0}
+#define google_protobuf_Int32Value_init_zero {0}
+#define google_protobuf_UInt32Value_init_zero {0}
+#define google_protobuf_BoolValue_init_zero {0}
+#define google_protobuf_StringValue_init_zero {{{NULL}, NULL}}
+#define google_protobuf_BytesValue_init_zero {{{NULL}, NULL}}
+
+/* Field tags (for use in manual encoding/decoding) */
+#define google_protobuf_BytesValue_value_tag 1
+#define google_protobuf_StringValue_value_tag 1
+#define google_protobuf_BoolValue_value_tag 1
+#define google_protobuf_DoubleValue_value_tag 1
+#define google_protobuf_FloatValue_value_tag 1
+#define google_protobuf_Int32Value_value_tag 1
+#define google_protobuf_Int64Value_value_tag 1
+#define google_protobuf_UInt32Value_value_tag 1
+#define google_protobuf_UInt64Value_value_tag 1
+
+/* Struct field encoding specification for nanopb */
+extern const pb_field_t google_protobuf_DoubleValue_fields[2];
+extern const pb_field_t google_protobuf_FloatValue_fields[2];
+extern const pb_field_t google_protobuf_Int64Value_fields[2];
+extern const pb_field_t google_protobuf_UInt64Value_fields[2];
+extern const pb_field_t google_protobuf_Int32Value_fields[2];
+extern const pb_field_t google_protobuf_UInt32Value_fields[2];
+extern const pb_field_t google_protobuf_BoolValue_fields[2];
+extern const pb_field_t google_protobuf_StringValue_fields[2];
+extern const pb_field_t google_protobuf_BytesValue_fields[2];
+
+/* Maximum encoded size of messages (where known) */
+#define google_protobuf_DoubleValue_size 9
+#define google_protobuf_FloatValue_size 5
+#define google_protobuf_Int64Value_size 11
+#define google_protobuf_UInt64Value_size 11
+#define google_protobuf_Int32Value_size 11
+#define google_protobuf_UInt32Value_size 6
+#define google_protobuf_BoolValue_size 2
+/* google_protobuf_StringValue_size depends on runtime parameters */
+/* google_protobuf_BytesValue_size depends on runtime parameters */
+
+/* Message IDs (where set with "msgid" option) */
+#ifdef PB_MSGID
+
+#define WRAPPERS_MESSAGES \
+
+
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+/* @@protoc_insertion_point(eof) */
+
+#endif
diff --git a/Firestore/Protos/protos/google/protobuf/any.proto b/Firestore/Protos/protos/google/protobuf/any.proto
new file mode 100644
index 0000000..c748667
--- /dev/null
+++ b/Firestore/Protos/protos/google/protobuf/any.proto
@@ -0,0 +1,149 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "github.com/golang/protobuf/ptypes/any";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "AnyProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// `Any` contains an arbitrary serialized protocol buffer message along with a
+// URL that describes the type of the serialized message.
+//
+// Protobuf library provides support to pack/unpack Any values in the form
+// of utility functions or additional generated methods of the Any type.
+//
+// Example 1: Pack and unpack a message in C++.
+//
+// Foo foo = ...;
+// Any any;
+// any.PackFrom(foo);
+// ...
+// if (any.UnpackTo(&foo)) {
+// ...
+// }
+//
+// Example 2: Pack and unpack a message in Java.
+//
+// Foo foo = ...;
+// Any any = Any.pack(foo);
+// ...
+// if (any.is(Foo.class)) {
+// foo = any.unpack(Foo.class);
+// }
+//
+// Example 3: Pack and unpack a message in Python.
+//
+// foo = Foo(...)
+// any = Any()
+// any.Pack(foo)
+// ...
+// if any.Is(Foo.DESCRIPTOR):
+// any.Unpack(foo)
+// ...
+//
+// Example 4: Pack and unpack a message in Go
+//
+// foo := &pb.Foo{...}
+// any, err := ptypes.MarshalAny(foo)
+// ...
+// foo := &pb.Foo{}
+// if err := ptypes.UnmarshalAny(any, foo); err != nil {
+// ...
+// }
+//
+// The pack methods provided by protobuf library will by default use
+// 'type.googleapis.com/full.type.name' as the type URL and the unpack
+// methods only use the fully qualified type name after the last '/'
+// in the type URL, for example "foo.bar.com/x/y.z" will yield type
+// name "y.z".
+//
+//
+// JSON
+// ====
+// The JSON representation of an `Any` value uses the regular
+// representation of the deserialized, embedded message, with an
+// additional field `@type` which contains the type URL. Example:
+//
+// package google.profile;
+// message Person {
+// string first_name = 1;
+// string last_name = 2;
+// }
+//
+// {
+// "@type": "type.googleapis.com/google.profile.Person",
+// "firstName": <string>,
+// "lastName": <string>
+// }
+//
+// If the embedded message type is well-known and has a custom JSON
+// representation, that representation will be embedded adding a field
+// `value` which holds the custom JSON in addition to the `@type`
+// field. Example (for message [google.protobuf.Duration][]):
+//
+// {
+// "@type": "type.googleapis.com/google.protobuf.Duration",
+// "value": "1.212s"
+// }
+//
+message Any {
+ // A URL/resource name whose content describes the type of the
+ // serialized protocol buffer message.
+ //
+ // For URLs which use the scheme `http`, `https`, or no scheme, the
+ // following restrictions and interpretations apply:
+ //
+ // * If no scheme is provided, `https` is assumed.
+ // * The last segment of the URL's path must represent the fully
+ // qualified name of the type (as in `path/google.protobuf.Duration`).
+ // The name should be in a canonical form (e.g., leading "." is
+ // not accepted).
+ // * An HTTP GET on the URL must yield a [google.protobuf.Type][]
+ // value in binary format, or produce an error.
+ // * Applications are allowed to cache lookup results based on the
+ // URL, or have them precompiled into a binary to avoid any
+ // lookup. Therefore, binary compatibility needs to be preserved
+ // on changes to types. (Use versioned type names to manage
+ // breaking changes.)
+ //
+ // Schemes other than `http`, `https` (or the empty scheme) might be
+ // used with implementation specific semantics.
+ //
+ string type_url = 1;
+
+ // Must be a valid serialized protocol buffer of the above specified type.
+ bytes value = 2;
+}
diff --git a/Firestore/Protos/protos/google/protobuf/empty.proto b/Firestore/Protos/protos/google/protobuf/empty.proto
new file mode 100644
index 0000000..03cacd2
--- /dev/null
+++ b/Firestore/Protos/protos/google/protobuf/empty.proto
@@ -0,0 +1,52 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 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.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option go_package = "github.com/golang/protobuf/ptypes/empty";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "EmptyProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option cc_enable_arenas = true;
+
+// A generic empty message that you can re-use to avoid defining duplicated
+// empty messages in your APIs. A typical example is to use it as the request
+// or the response type of an API method. For instance:
+//
+// service Foo {
+// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
+// }
+//
+// The JSON representation for `Empty` is empty JSON object `{}`.
+message Empty {}
diff --git a/Firestore/Protos/protos/google/protobuf/wrappers.proto b/Firestore/Protos/protos/google/protobuf/wrappers.proto
new file mode 100644
index 0000000..0194763
--- /dev/null
+++ b/Firestore/Protos/protos/google/protobuf/wrappers.proto
@@ -0,0 +1,118 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 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.
+
+// Wrappers for primitive (non-message) types. These types are useful
+// for embedding primitives in the `google.protobuf.Any` type and for places
+// where we need to distinguish between the absence of a primitive
+// typed field and its default value.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+option cc_enable_arenas = true;
+option go_package = "github.com/golang/protobuf/ptypes/wrappers";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "WrappersProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+
+// Wrapper message for `double`.
+//
+// The JSON representation for `DoubleValue` is JSON number.
+message DoubleValue {
+ // The double value.
+ double value = 1;
+}
+
+// Wrapper message for `float`.
+//
+// The JSON representation for `FloatValue` is JSON number.
+message FloatValue {
+ // The float value.
+ float value = 1;
+}
+
+// Wrapper message for `int64`.
+//
+// The JSON representation for `Int64Value` is JSON string.
+message Int64Value {
+ // The int64 value.
+ int64 value = 1;
+}
+
+// Wrapper message for `uint64`.
+//
+// The JSON representation for `UInt64Value` is JSON string.
+message UInt64Value {
+ // The uint64 value.
+ uint64 value = 1;
+}
+
+// Wrapper message for `int32`.
+//
+// The JSON representation for `Int32Value` is JSON number.
+message Int32Value {
+ // The int32 value.
+ int32 value = 1;
+}
+
+// Wrapper message for `uint32`.
+//
+// The JSON representation for `UInt32Value` is JSON number.
+message UInt32Value {
+ // The uint32 value.
+ uint32 value = 1;
+}
+
+// Wrapper message for `bool`.
+//
+// The JSON representation for `BoolValue` is JSON `true` and `false`.
+message BoolValue {
+ // The bool value.
+ bool value = 1;
+}
+
+// Wrapper message for `string`.
+//
+// The JSON representation for `StringValue` is JSON string.
+message StringValue {
+ // The string value.
+ string value = 1;
+}
+
+// Wrapper message for `bytes`.
+//
+// The JSON representation for `BytesValue` is JSON string.
+message BytesValue {
+ // The bytes value.
+ bytes value = 1;
+}
diff --git a/Firestore/core/src/firebase/firestore/remote/CMakeLists.txt b/Firestore/core/src/firebase/firestore/remote/CMakeLists.txt
index a218e3b..7f528fb 100644
--- a/Firestore/core/src/firebase/firestore/remote/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/remote/CMakeLists.txt
@@ -20,6 +20,8 @@ cc_library(
serializer.h
serializer.cc
DEPENDS
+ firebase_firestore_model
+ firebase_firestore_protos_nanopb
grpc::grpc
nanopb
)
diff --git a/Firestore/core/src/firebase/firestore/remote/serializer.cc b/Firestore/core/src/firebase/firestore/remote/serializer.cc
index d3cdd3f..e503d09 100644
--- a/Firestore/core/src/firebase/firestore/remote/serializer.cc
+++ b/Firestore/core/src/firebase/firestore/remote/serializer.cc
@@ -16,16 +16,94 @@
#include "Firestore/core/src/firebase/firestore/remote/serializer.h"
-// TODO(rsgowman): These are (currently!) unnecessary includes. Adding for now
-// to ensure we can find nanopb's generated header files.
-#include "Firestore/Protos/nanopb/google/firestore/v1beta1/document.pb.h"
-#include "Firestore/Protos/nanopb/google/protobuf/timestamp.pb.h"
+#include <pb_decode.h>
+#include <pb_encode.h>
namespace firebase {
namespace firestore {
namespace remote {
-Serializer::Serializer() {
+using firebase::firestore::model::FieldValue;
+
+Serializer::TypedValue Serializer::EncodeFieldValue(
+ const FieldValue& field_value) {
+ Serializer::TypedValue proto_value{
+ field_value.type(), google_firestore_v1beta1_Value_init_default};
+ switch (field_value.type()) {
+ case FieldValue::Type::Null:
+ proto_value.value.null_value = google_protobuf_NullValue_NULL_VALUE;
+ break;
+ default:
+ // TODO(rsgowman): implement the other types
+ abort();
+ }
+ return proto_value;
+}
+
+void Serializer::EncodeTypedValue(const TypedValue& value,
+ std::vector<uint8_t>* out_bytes) {
+ bool status;
+ // TODO(rsgowman): how large should the output buffer be? Do some
+ // investigation to see if we can get nanopb to tell us how much space it's
+ // going to need.
+ uint8_t buf[1024];
+ pb_ostream_t stream = pb_ostream_from_buffer(buf, sizeof(buf));
+ switch (value.type) {
+ case FieldValue::Type::Null:
+ status = pb_encode_tag(&stream, PB_WT_VARINT,
+ google_firestore_v1beta1_Value_null_value_tag);
+ if (!status) {
+ // TODO(rsgowman): figure out error handling
+ abort();
+ }
+
+ status = pb_encode_varint(&stream, value.value.null_value);
+ if (!status) {
+ // TODO(rsgowman): figure out error handling
+ abort();
+ }
+
+ out_bytes->insert(out_bytes->end(), buf, buf + stream.bytes_written);
+
+ break;
+
+ default:
+ // TODO(rsgowman): implement the other types
+ abort();
+ }
+}
+
+FieldValue Serializer::DecodeFieldValue(
+ const Serializer::TypedValue& value_proto) {
+ switch (value_proto.type) {
+ case FieldValue::Type::Null:
+ return FieldValue::NullValue();
+ default:
+ // TODO(rsgowman): implement the other types
+ abort();
+ }
+}
+
+Serializer::TypedValue Serializer::DecodeTypedValue(const uint8_t* bytes,
+ size_t length) {
+ pb_istream_t stream = pb_istream_from_buffer(bytes, length);
+ pb_wire_type_t wire_type;
+ uint32_t tag;
+ bool eof;
+ bool status = pb_decode_tag(&stream, &wire_type, &tag, &eof);
+ if (!status || wire_type != PB_WT_VARINT) {
+ // TODO(rsgowman): figure out error handling
+ abort();
+ }
+
+ switch (tag) {
+ case google_firestore_v1beta1_Value_null_value_tag:
+ return Serializer::TypedValue{
+ FieldValue::Type::Null, google_firestore_v1beta1_Value_init_default};
+ default:
+ // TODO(rsgowman): figure out error handling
+ abort();
+ }
}
} // namespace remote
diff --git a/Firestore/core/src/firebase/firestore/remote/serializer.h b/Firestore/core/src/firebase/firestore/remote/serializer.h
index 4dc6b9e..518cff4 100644
--- a/Firestore/core/src/firebase/firestore/remote/serializer.h
+++ b/Firestore/core/src/firebase/firestore/remote/serializer.h
@@ -17,16 +17,26 @@
#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_SERIALIZER_H_
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_REMOTE_SERIALIZER_H_
+#include <stdint.h>
+#include <stdlib.h>
+#include <vector>
+
+#include "Firestore/Protos/nanopb/google/firestore/v1beta1/document.pb.h"
+#include "Firestore/core/src/firebase/firestore/model/field_value.h"
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+
namespace firebase {
namespace firestore {
namespace remote {
/**
* @brief Converts internal model objects to their equivalent protocol buffer
- * form.
+ * form, and protocol buffer objects to their equivalent bytes.
*
- * Methods starting with "Encode" convert to a protocol buffer and methods
- * starting with "Decode" convert from a protocol buffer.
+ * Methods starting with "Encode" either convert from a model object to a
+ * protocol buffer or from a protocol buffer to bytes, and methods starting with
+ * "Decode" either convert from a protocol buffer to a model object or from
+ * bytes to a protocol buffer.
*
*/
// TODO(rsgowman): Original docs also has this: "Throws an exception if a
@@ -34,10 +44,102 @@ namespace remote {
// interpret." Adjust for C++.
class Serializer {
public:
- // TODO(rsgowman): Adjust ctor to accept a DatabaseID... once that exists.
- Serializer(/*DatabaseID databaseId*/);
+ /**
+ * @brief Wraps (nanopb) google_firestore_v1beta1_Value with type information.
+ */
+ struct TypedValue {
+ firebase::firestore::model::FieldValue::Type type;
+ google_firestore_v1beta1_Value value;
+ };
+
+ Serializer() {
+ }
+ // TODO(rsgowman): We eventually need the DatabaseId, but can't add it just
+ // yet since it's not used yet (which travis complains about). So for now,
+ // we'll create a parameterless ctor (above) that likely won't exist in the
+ // final version of this class.
+ ///**
+ // * @param database_id Must remain valid for the lifetime of this Serializer
+ // * object.
+ // */
+ // explicit Serializer(const firebase::firestore::model::DatabaseId&
+ // database_id)
+ // : database_id_(database_id) {
+ //}
+
+ /**
+ * Converts the FieldValue model passed into the Value proto equivalent.
+ *
+ * @param field_value the model to convert.
+ * @return the proto representation of the model.
+ */
+ static Serializer::TypedValue EncodeFieldValue(
+ const firebase::firestore::model::FieldValue& field_value);
+
+ /**
+ * @brief Converts the value proto passed into bytes.
+ *
+ * @param[out] out_bytes A buffer to place the output. The bytes will be
+ * appended to this vector.
+ */
+ // TODO(rsgowman): error handling, incl return code.
+ static void EncodeTypedValue(const TypedValue& value,
+ std::vector<uint8_t>* out_bytes);
+
+ /**
+ * Converts from the proto Value format to the model FieldValue format
+ *
+ * @return The model equivalent of the proto data.
+ */
+ static firebase::firestore::model::FieldValue DecodeFieldValue(
+ const Serializer::TypedValue& value_proto);
+
+ /**
+ * @brief Converts from bytes to the nanopb proto.
+ *
+ * @param bytes The bytes to convert. It's assumed that exactly all of the
+ * bytes will be used by this conversion.
+ * @return The (nanopb) proto equivalent of the bytes.
+ */
+ // TODO(rsgowman): error handling.
+ static TypedValue DecodeTypedValue(const uint8_t* bytes, size_t length);
+
+ /**
+ * @brief Converts from bytes to the nanopb proto.
+ *
+ * @param bytes The bytes to convert. It's assumed that exactly all of the
+ * bytes will be used by this conversion.
+ * @return The (nanopb) proto equivalent of the bytes.
+ */
+ // TODO(rsgowman): error handling.
+ static TypedValue DecodeTypedValue(const std::vector<uint8_t>& bytes) {
+ return DecodeTypedValue(bytes.data(), bytes.size());
+ }
+
+ private:
+ // TODO(rsgowman): We don't need the database_id_ yet (but will eventually).
+ // const firebase::firestore::model::DatabaseId& database_id_;
};
+inline bool operator==(const Serializer::TypedValue& lhs,
+ const Serializer::TypedValue& rhs) {
+ if (lhs.type != rhs.type) {
+ return false;
+ }
+
+ switch (lhs.type) {
+ case firebase::firestore::model::FieldValue::Type::Null:
+ FIREBASE_DEV_ASSERT(lhs.value.null_value ==
+ google_protobuf_NullValue_NULL_VALUE);
+ FIREBASE_DEV_ASSERT(rhs.value.null_value ==
+ google_protobuf_NullValue_NULL_VALUE);
+ return true;
+ default:
+ // TODO(rsgowman): implement the other types
+ abort();
+ }
+}
+
} // namespace remote
} // namespace firestore
} // namespace firebase
diff --git a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc
index 1be5a87..35f417e 100644
--- a/Firestore/core/test/firebase/firestore/remote/serializer_test.cc
+++ b/Firestore/core/test/firebase/firestore/remote/serializer_test.cc
@@ -16,8 +16,15 @@
#include "Firestore/core/src/firebase/firestore/remote/serializer.h"
-#include <gtest/gtest.h>
+#include <pb.h>
#include <pb_encode.h>
+#include <vector>
+
+#include "Firestore/core/src/firebase/firestore/model/field_value.h"
+#include "gtest/gtest.h"
+
+using firebase::firestore::model::FieldValue;
+using firebase::firestore::remote::Serializer;
TEST(Serializer, CanLinkToNanopb) {
// This test doesn't actually do anything interesting as far as actually using
@@ -26,3 +33,65 @@ TEST(Serializer, CanLinkToNanopb) {
// the test.
pb_ostream_from_buffer(NULL, 0);
}
+
+// Fixture for running serializer tests.
+class SerializerTest : public ::testing::Test {
+ public:
+ SerializerTest() : serializer(/*DatabaseId("p", "d")*/) {
+ }
+ Serializer serializer;
+
+ void ExpectRoundTrip(const FieldValue& model,
+ const Serializer::TypedValue& proto,
+ FieldValue::Type type) {
+ EXPECT_EQ(type, model.type());
+ EXPECT_EQ(type, proto.type);
+ Serializer::TypedValue actual_proto = serializer.EncodeFieldValue(model);
+ EXPECT_EQ(type, actual_proto.type);
+ EXPECT_EQ(proto, actual_proto);
+ EXPECT_EQ(model, serializer.DecodeFieldValue(proto));
+ }
+
+ void ExpectRoundTrip(const Serializer::TypedValue& proto,
+ std::vector<uint8_t> bytes,
+ FieldValue::Type type) {
+ EXPECT_EQ(type, proto.type);
+ std::vector<uint8_t> actual_bytes;
+ Serializer::EncodeTypedValue(proto, &actual_bytes);
+ EXPECT_EQ(bytes, actual_bytes);
+ Serializer::TypedValue actual_proto = Serializer::DecodeTypedValue(bytes);
+ EXPECT_EQ(type, actual_proto.type);
+ EXPECT_EQ(proto, actual_proto);
+ }
+};
+
+TEST_F(SerializerTest, EncodesNullModelToProto) {
+ FieldValue model = FieldValue::NullValue();
+ Serializer::TypedValue proto{FieldValue::Type::Null,
+ google_firestore_v1beta1_Value_init_default};
+ // sanity check (the _init_default above should set this to _NULL_VALUE)
+ EXPECT_EQ(google_protobuf_NullValue_NULL_VALUE, proto.value.null_value);
+ ExpectRoundTrip(model, proto, FieldValue::Type::Null);
+}
+
+TEST_F(SerializerTest, EncodesNullProtoToBytes) {
+ Serializer::TypedValue proto{FieldValue::Type::Null,
+ google_firestore_v1beta1_Value_init_default};
+ // sanity check (the _init_default above should set this to _NULL_VALUE)
+ EXPECT_EQ(google_protobuf_NullValue_NULL_VALUE, proto.value.null_value);
+
+ /* NB: proto bytes were created via:
+ echo 'null_value: NULL_VALUE' \
+ | ./build/external/protobuf/src/protobuf-build/src/protoc \
+ -I./Firestore/Protos/protos \
+ -I./build/external/protobuf/src/protobuf/src/ \
+ --encode=google.firestore.v1beta1.Value \
+ google/firestore/v1beta1/document.proto \
+ > output.bin
+ */
+ std::vector<uint8_t> bytes{0x58, 0x00};
+ ExpectRoundTrip(proto, bytes, FieldValue::Type::Null);
+}
+
+// TODO(rsgowman): Test [en|de]coding multiple protos into the same output
+// vector.
diff --git a/cmake/external/grpc.cmake b/cmake/external/grpc.cmake
index 0af6b31..d545087 100644
--- a/cmake/external/grpc.cmake
+++ b/cmake/external/grpc.cmake
@@ -68,7 +68,15 @@ else()
PREFIX ${PROJECT_BINARY_DIR}/external/grpc
- CMAKE_ARGS ${CMAKE_ARGS}
+ # TODO(rsgowman): We're currently building nanopb twice; once via grpc, and
+ # once via nanopb. The version from grpc is the one that actually ends up
+ # being used. We need to fix this such that either:
+ # a) we instruct grpc to use our nanopb
+ # b) we rely on grpc's nanopb instead of using our own.
+ # For now, we'll pass in the necessary nanopb cflags into grpc. (We require
+ # 16 bit fields. Without explicitly requesting this, nanopb uses 8 bit
+ # fields.)
+ CMAKE_ARGS ${CMAKE_ARGS};-DCMAKE_C_FLAGS=-DPB_FIELD_16BIT;DCMAKE_CXX_FLAGS=-DPB_FIELD_16BIT
BUILD_COMMAND
${CMAKE_COMMAND} --build . --target grpc