feat add protobuf for C++11

This commit is contained in:
tqcq
2024-03-13 18:11:02 +08:00
parent 4ea52bd2da
commit f8d2b051ee
753 changed files with 409279 additions and 2 deletions

View File

@@ -0,0 +1,95 @@
// See README.txt for information and build instructions.
import com.example.tutorial.protos.AddressBook;
import com.example.tutorial.protos.Person;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintStream;
class AddPerson {
// This function fills in a Person message based on user input.
static Person PromptForAddress(BufferedReader stdin,
PrintStream stdout) throws IOException {
Person.Builder person = Person.newBuilder();
stdout.print("Enter person ID: ");
person.setId(Integer.valueOf(stdin.readLine()));
stdout.print("Enter name: ");
person.setName(stdin.readLine());
stdout.print("Enter email address (blank for none): ");
String email = stdin.readLine();
if (email.length() > 0) {
person.setEmail(email);
}
while (true) {
stdout.print("Enter a phone number (or leave blank to finish): ");
String number = stdin.readLine();
if (number.length() == 0) {
break;
}
Person.PhoneNumber.Builder phoneNumber =
Person.PhoneNumber.newBuilder().setNumber(number);
stdout.print("Is this a mobile, home, or work phone? ");
String type = stdin.readLine();
if (type.equals("mobile")) {
phoneNumber.setType(Person.PhoneType.MOBILE);
} else if (type.equals("home")) {
phoneNumber.setType(Person.PhoneType.HOME);
} else if (type.equals("work")) {
phoneNumber.setType(Person.PhoneType.WORK);
} else {
stdout.println("Unknown phone type. Using default.");
}
person.addPhones(phoneNumber);
}
return person.build();
}
// Main function: Reads the entire address book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Usage: AddPerson ADDRESS_BOOK_FILE");
System.exit(-1);
}
AddressBook.Builder addressBook = AddressBook.newBuilder();
// Read the existing address book.
try {
FileInputStream input = new FileInputStream(args[0]);
try {
addressBook.mergeFrom(input);
} finally {
try { input.close(); } catch (Throwable ignore) {}
}
} catch (FileNotFoundException e) {
System.out.println(args[0] + ": File not found. Creating a new file.");
}
// Add an address.
addressBook.addPeople(
PromptForAddress(new BufferedReader(new InputStreamReader(System.in)),
System.out));
// Write the new address book back to disk.
FileOutputStream output = new FileOutputStream(args[0]);
try {
addressBook.build().writeTo(output);
} finally {
output.close();
}
}
}

View File

@@ -0,0 +1,137 @@
# This BUILD file shows how to use protobuf with bazel. Before you can use
# proto_library/<lang>_proto_library rules in a BUILD file, you need to
# include protobuf repo as remote repositories in your WORKSPACE file. See
# the WORKSPACE file in the same directory with this BUILD file for an
# example.
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_proto_library")
load("@rules_java//java:defs.bzl", "java_binary", "java_lite_proto_library", "java_proto_library")
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
load("@rules_proto//proto:defs.bzl", "proto_library")
# For each .proto file, a proto_library target should be defined. This target
# is not bound to any particular language. Instead, it defines the dependency
# graph of the .proto files (i.e., proto imports) and serves as the provider
# of .proto source files to the protocol compiler.
#
# Remote repository "com_google_protobuf" must be defined to use this rule.
proto_library(
name = "addressbook_proto",
srcs = ["addressbook.proto"],
deps = ["@com_google_protobuf//:timestamp_proto"],
)
# The cc_proto_library rule generates C++ code for a proto_library rule. It
# must have exactly one proto_library dependency. If you want to use multiple
# proto_library targets, create a separate cc_proto_library target for each
# of them.
#
# Remote repository "com_google_protobuf_cc" must be defined to use this rule.
cc_proto_library(
name = "addressbook_cc_proto",
deps = [":addressbook_proto"],
)
# cc_library/cc_binary targets can depend on cc_proto_library targets.
cc_binary(
name = "add_person_cpp",
srcs = ["add_person.cc"],
deps = [":addressbook_cc_proto"],
)
cc_binary(
name = "list_people_cpp",
srcs = ["list_people.cc"],
deps = [":addressbook_cc_proto"],
)
# Similar to cc_proto_library but for Java.
#
# Remote repository "com_google_protobuf_java" must be defined to use this rule.
java_proto_library(
name = "addressbook_java_proto",
deps = [":addressbook_proto"],
)
java_binary(
name = "add_person_java",
srcs = ["AddPerson.java"],
main_class = "AddPerson",
deps = [":addressbook_java_proto"],
)
java_binary(
name = "list_people_java",
srcs = ["ListPeople.java"],
main_class = "ListPeople",
deps = [":addressbook_java_proto"],
)
# Java lite.
#
# Remote repository "com_google_protobuf_javalite" must be defined to use this
# rule.
java_lite_proto_library(
name = "addressbook_java_lite_proto",
deps = [":addressbook_proto"],
)
# Java lite API is a subset of the regular Java API so if you only uses this
# subset in your code, you can actually compile your code against both (i.e.,
# share code between server build and Android build).
#
# The lite version has a smaller code size, and you can see that by comparing
# the resulted .jar file:
#
# $ bazel build :add_person_java_deploy.jar :add_person_java_lite_deploy.jar
# $ ls -l bazel-bin/*_deploy.jar
# -r-xr-xr-x 1 xiaofeng eng 1230797 Sep 8 12:24 bazel-bin/add_person_java_deploy.jar
# -r-xr-xr-x 1 xiaofeng eng 236166 Sep 8 12:24 bazel-bin/add_person_java_lite_deploy.jar
#
# In the above example, the lite .jar file is 6 times smaller. With proper
# proguard inlining/stripping, the difference can be much more larger than
# that.
java_binary(
name = "add_person_java_lite",
srcs = ["AddPerson.java"],
main_class = "AddPerson",
deps = [":addressbook_java_lite_proto"],
)
java_binary(
name = "list_people_java_lite",
srcs = ["ListPeople.java"],
main_class = "ListPeople",
deps = [":addressbook_java_lite_proto"],
)
# Files included in all source distributions
pkg_files(
name = "dist_files",
srcs = [
"AddPerson.java",
"BUILD.bazel",
"CMakeLists.txt",
"ListPeople.java",
"Makefile",
"README.md",
"WORKSPACE",
"add_person.cc",
"add_person.dart",
"add_person.py",
"addressbook.proto",
"go/cmd/add_person/add_person.go",
"go/cmd/add_person/add_person_test.go",
"go/cmd/list_people/list_people.go",
"go/cmd/list_people/list_people_test.go",
"go/go.mod",
"go/go.sum",
"list_people.cc",
"list_people.dart",
"list_people.py",
"pubspec.yaml",
],
prefix = "examples/",
strip_prefix = strip_prefix.from_root(""),
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,48 @@
# Minimum CMake required
cmake_minimum_required(VERSION 2.8.12)
# Project
project(protobuf-examples)
# Find required protobuf package
find_package(protobuf CONFIG REQUIRED)
if(protobuf_VERBOSE)
message(STATUS "Using Protocol Buffers ${protobuf_VERSION}")
endif()
set(CMAKE_INCLUDE_CURRENT_DIR TRUE)
# http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F
if(MSVC AND protobuf_MSVC_STATIC_RUNTIME)
foreach(flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag_var} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif(${flag_var} MATCHES "/MD")
endforeach()
endif()
foreach(example add_person list_people)
set(${example}_SRCS ${example}.cc)
set(${example}_PROTOS addressbook.proto)
#Code Generation
if(protobuf_MODULE_COMPATIBLE) #Legacy Support
protobuf_generate_cpp(${example}_PROTO_SRCS ${example}_PROTO_HDRS ${${example}_PROTOS})
list(APPEND ${example}_SRCS ${${example}_PROTO_SRCS} ${${example}_PROTO_HDRS})
endif()
#Executable setup
set(executable_name ${example}_cpp)
add_executable(${executable_name} ${${example}_SRCS} ${${example}_PROTOS})
if(protobuf_MODULE_COMPATIBLE) #Legacy mode
target_include_directories(${executable_name} PUBLIC ${PROTOBUF_INCLUDE_DIRS})
target_link_libraries(${executable_name} ${PROTOBUF_LIBRARIES})
else()
target_link_libraries(${executable_name} protobuf::libprotobuf)
protobuf_generate(TARGET ${executable_name})
endif()
endforeach()

View File

@@ -0,0 +1,53 @@
// See README.txt for information and build instructions.
import com.example.tutorial.protos.AddressBook;
import com.example.tutorial.protos.Person;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
class ListPeople {
// Iterates though all people in the AddressBook and prints info about them.
static void Print(AddressBook addressBook) {
for (Person person: addressBook.getPeopleList()) {
System.out.println("Person ID: " + person.getId());
System.out.println(" Name: " + person.getName());
if (!person.getEmail().isEmpty()) {
System.out.println(" E-mail address: " + person.getEmail());
}
for (Person.PhoneNumber phoneNumber : person.getPhonesList()) {
switch (phoneNumber.getType()) {
case MOBILE:
System.out.print(" Mobile phone #: ");
break;
case HOME:
System.out.print(" Home phone #: ");
break;
case WORK:
System.out.print(" Work phone #: ");
break;
default:
System.out.println(" Unknown phone #: ");
break;
}
System.out.println(phoneNumber.getNumber());
}
}
}
// Main function: Reads the entire address book from a file and prints all
// the information inside.
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Usage: ListPeople ADDRESS_BOOK_FILE");
System.exit(-1);
}
// Read the existing address book.
AddressBook addressBook =
AddressBook.parseFrom(new FileInputStream(args[0]));
Print(addressBook);
}
}

View File

@@ -0,0 +1,91 @@
# See README.txt.
.PHONY: all cpp java python clean
all: cpp java python
cpp: add_person_cpp list_people_cpp
dart: add_person_dart list_people_dart
go: add_person_go list_people_go
gotest: add_person_gotest list_people_gotest
java: add_person_java list_people_java
python: add_person_python list_people_python
clean:
rm -f add_person_cpp list_people_cpp add_person_java list_people_java add_person_python list_people_python
rm -f javac_middleman AddPerson*.class ListPeople*.class com/example/tutorial/*.class
rm -f protoc_middleman addressbook.pb.cc addressbook.pb.h addressbook_pb2.py com/example/tutorial/AddressBookProtos.java
rm -f *.pyc
rm -f go/tutorialpb/*.pb.go add_person_go list_people_go
rm -f protoc_middleman_dart dart_tutorial/*.pb*.dart
rmdir dart_tutorial 2>/dev/null || true
rmdir tutorial 2>/dev/null || true
rmdir com/example/tutorial 2>/dev/null || true
rmdir com/example 2>/dev/null || true
rmdir com 2>/dev/null || true
protoc_middleman: addressbook.proto
protoc $$PROTO_PATH --cpp_out=. --java_out=. --python_out=. addressbook.proto
@touch protoc_middleman
go/tutorialpb/addressbook.pb.go: addressbook.proto
mkdir -p go/tutorialpb # make directory for go package
protoc $$PROTO_PATH --go_opt=paths=source_relative --go_out=go/tutorialpb addressbook.proto
protoc_middleman_dart: addressbook.proto
mkdir -p dart_tutorial # make directory for the dart package
protoc -I ../src/:. --dart_out=dart_tutorial addressbook.proto ../src/google/protobuf/timestamp.proto
pub get
@touch protoc_middleman_dart
add_person_cpp: add_person.cc protoc_middleman
pkg-config --cflags protobuf # fails if protobuf is not installed
c++ -std=c++11 add_person.cc addressbook.pb.cc -o add_person_cpp `pkg-config --cflags --libs protobuf`
list_people_cpp: list_people.cc protoc_middleman
pkg-config --cflags protobuf # fails if protobuf is not installed
c++ -std=c++11 list_people.cc addressbook.pb.cc -o list_people_cpp `pkg-config --cflags --libs protobuf`
add_person_dart: add_person.dart protoc_middleman_dart
list_people_dart: list_people.dart protoc_middleman_dart
add_person_go: go/cmd/add_person/add_person.go go/tutorialpb/addressbook.pb.go
cd go && go build -o ../add_person_go ./cmd/add_person
add_person_gotest: go/tutorialpb/addressbook.pb.go
cd go && go test ./cmd/add_person
list_people_go: go/cmd/list_people/list_people.go go/tutorialpb/addressbook.pb.go
cd go && go build -o ../list_people_go ./cmd/list_people
list_people_gotest: go/tutorialpb/addressbook.pb.go
cd go && go test ./cmd/list_people
javac_middleman: AddPerson.java ListPeople.java protoc_middleman
javac -cp $$CLASSPATH AddPerson.java ListPeople.java com/example/tutorial/AddressBookProtos.java
@touch javac_middleman
add_person_java: javac_middleman
@echo "Writing shortcut script add_person_java..."
@echo '#! /bin/sh' > add_person_java
@echo 'java -classpath .:$$CLASSPATH AddPerson "$$@"' >> add_person_java
@chmod +x add_person_java
list_people_java: javac_middleman
@echo "Writing shortcut script list_people_java..."
@echo '#! /bin/sh' > list_people_java
@echo 'java -classpath .:$$CLASSPATH ListPeople "$$@"' >> list_people_java
@chmod +x list_people_java
add_person_python: add_person.py protoc_middleman
@echo "Writing shortcut script add_person_python..."
@echo '#! /bin/sh' > add_person_python
@echo './add_person.py "$$@"' >> add_person_python
@chmod +x add_person_python
list_people_python: list_people.py protoc_middleman
@echo "Writing shortcut script list_people_python..."
@echo '#! /bin/sh' > list_people_python
@echo './list_people.py "$$@"' >> list_people_python
@chmod +x list_people_python

View File

@@ -0,0 +1,140 @@
# Protocol Buffers - Code Example
This directory contains example code that uses Protocol Buffers to manage an
address book. Two programs are provided for each supported language. The
add_person example adds a new person to an address book, prompting the user to
input the person's information. The list_people example lists people already in
the address book. The examples use the exact same format in all three languages,
so you can, for example, use add_person_java to create an address book and then
use list_people_python to read it.
These examples are part of the Protocol Buffers tutorial, located at:
https://developers.google.com/protocol-buffers/docs/tutorials
## Build the example using bazel
The example requires bazel 0.5.4 or newer to build. You can download/install
the latest version of bazel from bazel's release page:
https://github.com/bazelbuild/bazel/releases
Once you have bazel installed, simply run the following command in this examples
directory to build the code:
$ bazel build :all
Then you can run the built binary:
$ bazel-bin/add_person_cpp addressbook.data
To use protobuf in your own bazel project, please follow instructions in the
[BUILD](BUILD) file and [WORKSPACE](WORKSPACE) file.
## Build the example using make
You must install the protobuf package before you can build it using make. The
minimum requirement is to install protocol compiler (i.e., the protoc binary)
and the protobuf runtime for the language you want to build.
You can simply run "make" to build the example for all languages (except for
Go). However, since different language has different installation requirement,
it will likely fail. It's better to follow individual instructions below to
build only the language you are interested in.
### C++
You can follow instructions in [../src/README.md](../src/README.md) to install
protoc and protobuf C++ runtime from source.
Then run "make cpp" in this examples directory to build the C++ example. It
will create two executables: add_person_cpp and list_people_cpp. These programs
simply take an address book file as their parameter. The add_person_cpp
programs will create the file if it doesn't already exist.
To run the examples:
$ ./add_person_cpp addressbook.data
$ ./list_people_cpp addressbook.data
Note that on some platforms you may have to edit the Makefile and remove
"-lpthread" from the linker commands (perhaps replacing it with something else).
We didn't do this automatically because we wanted to keep the example simple.
### Python
Follow instructions in [../README.md](../README.md) to install protoc and then
follow [../python/README.md](../python/README.md) to install protobuf python
runtime from source. You can also install python runtime using pip:
$ pip install protobuf
Make sure the runtime version is the same as protoc binary, or it may not work.
After you have install both protoc and python runtime, run "make python" to
build two executables (shell scripts actually): add_person_python and
list_people_python. They work the same way as the C++ executables.
### Java
Follow instructions in [../README.md](../README.md) to install protoc and then
download protobuf Java runtime .jar file from maven:
https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java
Then run the following:
$ export CLASSPATH=/path/to/protobuf-java-[version].jar
$ make java
This will create the add_person_java/list_people_java executables (shell
scripts) and can be used to create/display an address book data file.
### Go
Follow instructions in [../README.md](../README.md) to install protoc. Then
install the Go protoc plugin (protoc-gen-go):
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
The "go install" command will install protoc-gen-go into the GOBIN
directory. You can set the $GOBIN environment variable before
running "go install" to change the install location. Make sure the
install directory is in your shell $PATH.
Build the Go samples with "make go". This creates the following
executable files in the current directory:
add_person_go list_people_go
To run the example:
./add_person_go addressbook.data
to add a person to the protocol buffer encoded file addressbook.data. The file
is created if it does not exist. To view the data, run:
./list_people_go addressbook.data
Observe that the C++, Python, Java, and Dart examples in this directory run in a
similar way and can view/modify files created by the Go example and vice
versa.
### Dart
First, follow the instructions in [../README.md](../README.md) to install the Protocol Buffer Compiler (protoc).
Then, install the Dart Protocol Buffer plugin as described [here](https://github.com/dart-lang/dart-protoc-plugin#how-to-build-and-use).
Note, the executable `bin/protoc-gen-dart` must be in your `PATH` for `protoc` to find it.
Build the Dart samples in this directory with `make dart`.
To run the examples:
```sh
$ dart add_person.dart addressbook.data
$ dart list_people.dart addressbook.data
```
The two programs take a protocol buffer encoded file as their parameter.
The first can be used to add a person to the file. The file is created
if it does not exist. The second displays the data in the file.

View File

@@ -0,0 +1,31 @@
workspace(name = "com_google_protobuf_examples")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# This com_google_protobuf repository is required for proto_library rule.
# It provides the protocol compiler binary (i.e., protoc).
#
# We declare it as local_repository so we can test changes
# before they get merged. You'll want to use the following instead:
#
# http_archive(
# name = "com_google_protobuf",
# strip_prefix = "protobuf-main",
# urls = ["https://github.com/protocolbuffers/protobuf/archive/main.zip"],
# )
local_repository(
name = "com_google_protobuf",
path = "..",
)
# Similar to com_google_protobuf but for Java lite. If you are building
# for Android, the lite version should be preferred because it has a much
# smaller code size.
local_repository(
name = "com_google_protobuf_javalite",
path = "..",
)
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
protobuf_deps()

View File

@@ -0,0 +1,102 @@
// See README.txt for information and build instructions.
#include <ctime>
#include <fstream>
#include <google/protobuf/util/time_util.h>
#include <iostream>
#include <string>
#include "addressbook.pb.h"
using namespace std;
using google::protobuf::util::TimeUtil;
// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
cout << "Enter person ID number: ";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');
cout << "Enter name: ";
getline(cin, *person->mutable_name());
cout << "Enter email address (blank for none): ";
string email;
getline(cin, email);
if (!email.empty()) {
person->set_email(email);
}
while (true) {
cout << "Enter a phone number (or leave blank to finish): ";
string number;
getline(cin, number);
if (number.empty()) {
break;
}
tutorial::Person::PhoneNumber* phone_number = person->add_phones();
phone_number->set_number(number);
cout << "Is this a mobile, home, or work phone? ";
string type;
getline(cin, type);
if (type == "mobile") {
phone_number->set_type(tutorial::Person::MOBILE);
} else if (type == "home") {
phone_number->set_type(tutorial::Person::HOME);
} else if (type == "work") {
phone_number->set_type(tutorial::Person::WORK);
} else {
cout << "Unknown phone type. Using default." << endl;
}
}
*person->mutable_last_updated() = TimeUtil::SecondsToTimestamp(time(NULL));
}
// Main function: Reads the entire address book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 2) {
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
return -1;
}
tutorial::AddressBook address_book;
{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!input) {
cout << argv[1] << ": File not found. Creating a new file." << endl;
} else if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}
// Add an address.
PromptForAddress(address_book.add_people());
{
// Write the new address book back to disk.
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
if (!address_book.SerializeToOstream(&output)) {
cerr << "Failed to write address book." << endl;
return -1;
}
}
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return 0;
}

View File

@@ -0,0 +1,67 @@
import 'dart:io';
import 'dart_tutorial/addressbook.pb.dart';
/// This function fills in a Person message based on user input.
Person promptForAddress() {
final person = Person();
print('Enter person ID: ');
final input = stdin.readLineSync();
person.id = int.parse(input);
print('Enter name');
person.name = stdin.readLineSync();
print('Enter email address (blank for none) : ');
final email = stdin.readLineSync();
if (email.isNotEmpty) person.email = email;
while (true) {
print('Enter a phone number (or leave blank to finish): ');
final number = stdin.readLineSync();
if (number.isEmpty) break;
final phoneNumber = Person_PhoneNumber()..number = number;
print('Is this a mobile, home, or work phone? ');
final type = stdin.readLineSync();
switch (type) {
case 'mobile':
phoneNumber.type = Person_PhoneType.MOBILE;
break;
case 'home':
phoneNumber.type = Person_PhoneType.HOME;
break;
case 'work':
phoneNumber.type = Person_PhoneType.WORK;
break;
default:
print('Unknown phone type. Using default.');
}
person.phones.add(phoneNumber);
}
return person;
}
/// Reads the entire address book from a file, adds one person based
/// on user input, then writes it back out to the same file.
void main(List<String> arguments) {
if (arguments.length != 1) {
print('Usage: add_person ADDRESS_BOOK_FILE');
exit(-1);
}
final file = File(arguments.first);
AddressBook addressBook;
if (!file.existsSync()) {
print('File not found. Creating new file.');
addressBook = AddressBook();
} else {
addressBook = AddressBook.fromBuffer(file.readAsBytesSync());
}
addressBook.people.add(promptForAddress());
file.writeAsBytes(addressBook.writeToBuffer());
}

View File

@@ -0,0 +1,63 @@
#! /usr/bin/env python
# See README.txt for information and build instructions.
import addressbook_pb2
import sys
try:
raw_input # Python 2
except NameError:
raw_input = input # Python 3
# This function fills in a Person message based on user input.
def PromptForAddress(person):
person.id = int(raw_input("Enter person ID number: "))
person.name = raw_input("Enter name: ")
email = raw_input("Enter email address (blank for none): ")
if email != "":
person.email = email
while True:
number = raw_input("Enter a phone number (or leave blank to finish): ")
if number == "":
break
phone_number = person.phones.add()
phone_number.number = number
type = raw_input("Is this a mobile, home, or work phone? ")
if type == "mobile":
phone_number.type = addressbook_pb2.Person.MOBILE
elif type == "home":
phone_number.type = addressbook_pb2.Person.HOME
elif type == "work":
phone_number.type = addressbook_pb2.Person.WORK
else:
print("Unknown phone type; leaving as default value.")
# Main procedure: Reads the entire address book from a file,
# adds one person based on user input, then writes it back out to the same
# file.
if len(sys.argv) != 2:
print("Usage:", sys.argv[0], "ADDRESS_BOOK_FILE")
sys.exit(-1)
address_book = addressbook_pb2.AddressBook()
# Read the existing address book.
try:
with open(sys.argv[1], "rb") as f:
address_book.ParseFromString(f.read())
except IOError:
print(sys.argv[1] + ": File not found. Creating a new file.")
# Add an address.
PromptForAddress(address_book.people.add())
# Write the new address book back to disk.
with open(sys.argv[1], "wb") as f:
f.write(address_book.SerializeToString())

View File

@@ -0,0 +1,56 @@
// See README.txt for information and build instructions.
//
// Note: START and END tags are used in comments to define sections used in
// tutorials. They are not part of the syntax for Protocol Buffers.
//
// To get an in-depth walkthrough of this file and the related examples, see:
// https://developers.google.com/protocol-buffers/docs/tutorials
// [START declaration]
syntax = "proto3";
package tutorial;
import "google/protobuf/timestamp.proto";
// [END declaration]
// [START java_declaration]
option java_multiple_files = true;
option java_package = "com.example.tutorial.protos";
option java_outer_classname = "AddressBookProtos";
// [END java_declaration]
// [START csharp_declaration]
option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
// [END csharp_declaration]
// [START go_declaration]
option go_package = "github.com/protocolbuffers/protobuf/examples/go/tutorialpb";
// [END go_declaration]
// [START messages]
message Person {
string name = 1;
int32 id = 2; // Unique ID number for this person.
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
google.protobuf.Timestamp last_updated = 5;
}
// Our address book file is just one of these.
message AddressBook {
repeated Person people = 1;
}
// [END messages]

View File

@@ -0,0 +1,133 @@
package main
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"strings"
pb "github.com/protocolbuffers/protobuf/examples/go/tutorialpb"
"google.golang.org/protobuf/proto"
)
func promptForAddress(r io.Reader) (*pb.Person, error) {
// A protocol buffer can be created like any struct.
p := &pb.Person{}
rd := bufio.NewReader(r)
fmt.Print("Enter person ID number: ")
// An int32 field in the .proto file is represented as an int32 field
// in the generated Go struct.
if _, err := fmt.Fscanf(rd, "%d\n", &p.Id); err != nil {
return p, err
}
fmt.Print("Enter name: ")
name, err := rd.ReadString('\n')
if err != nil {
return p, err
}
// A string field in the .proto file results in a string field in Go.
// We trim the whitespace because rd.ReadString includes the trailing
// newline character in its output.
p.Name = strings.TrimSpace(name)
fmt.Print("Enter email address (blank for none): ")
email, err := rd.ReadString('\n')
if err != nil {
return p, err
}
p.Email = strings.TrimSpace(email)
for {
fmt.Print("Enter a phone number (or leave blank to finish): ")
phone, err := rd.ReadString('\n')
if err != nil {
return p, err
}
phone = strings.TrimSpace(phone)
if phone == "" {
break
}
// The PhoneNumber message type is nested within the Person
// message in the .proto file. This results in a Go struct
// named using the name of the parent prefixed to the name of
// the nested message. Just as with pb.Person, it can be
// created like any other struct.
pn := &pb.Person_PhoneNumber{
Number: phone,
}
fmt.Print("Is this a mobile, home, or work phone? ")
ptype, err := rd.ReadString('\n')
if err != nil {
return p, err
}
ptype = strings.TrimSpace(ptype)
// A proto enum results in a Go constant for each enum value.
switch ptype {
case "mobile":
pn.Type = pb.Person_MOBILE
case "home":
pn.Type = pb.Person_HOME
case "work":
pn.Type = pb.Person_WORK
default:
fmt.Printf("Unknown phone type %q. Using default.\n", ptype)
}
// A repeated proto field maps to a slice field in Go. We can
// append to it like any other slice.
p.Phones = append(p.Phones, pn)
}
return p, nil
}
// Main reads the entire address book from a file, adds one person based on
// user input, then writes it back out to the same file.
func main() {
if len(os.Args) != 2 {
log.Fatalf("Usage: %s ADDRESS_BOOK_FILE\n", os.Args[0])
}
fname := os.Args[1]
// Read the existing address book.
in, err := ioutil.ReadFile(fname)
if err != nil {
if os.IsNotExist(err) {
fmt.Printf("%s: File not found. Creating new file.\n", fname)
} else {
log.Fatalln("Error reading file:", err)
}
}
// [START marshal_proto]
book := &pb.AddressBook{}
// [START_EXCLUDE]
if err := proto.Unmarshal(in, book); err != nil {
log.Fatalln("Failed to parse address book:", err)
}
// Add an address.
addr, err := promptForAddress(os.Stdin)
if err != nil {
log.Fatalln("Error with address:", err)
}
book.People = append(book.People, addr)
// [END_EXCLUDE]
// Write the new address book back to disk.
out, err := proto.Marshal(book)
if err != nil {
log.Fatalln("Failed to encode address book:", err)
}
if err := ioutil.WriteFile(fname, out, 0644); err != nil {
log.Fatalln("Failed to write address book:", err)
}
// [END marshal_proto]
}

View File

@@ -0,0 +1,58 @@
package main
import (
"strings"
"testing"
pb "github.com/protocolbuffers/protobuf/examples/go/tutorialpb"
"google.golang.org/protobuf/proto"
)
func TestPromptForAddressReturnsAddress(t *testing.T) {
in := `12345
Example Name
name@example.com
123-456-7890
home
222-222-2222
mobile
111-111-1111
work
777-777-7777
unknown
`
got, err := promptForAddress(strings.NewReader(in))
if err != nil {
t.Fatalf("promptForAddress(%q) had unexpected error: %s", in, err.Error())
}
if got.Id != 12345 {
t.Errorf("promptForAddress(%q) got %d, want ID %d", in, got.Id, 12345)
}
if got.Name != "Example Name" {
t.Errorf("promptForAddress(%q) => want name %q, got %q", in, "Example Name", got.Name)
}
if got.Email != "name@example.com" {
t.Errorf("promptForAddress(%q) => want email %q, got %q", in, "name@example.com", got.Email)
}
want := []*pb.Person_PhoneNumber{
{Number: "123-456-7890", Type: pb.Person_HOME},
{Number: "222-222-2222", Type: pb.Person_MOBILE},
{Number: "111-111-1111", Type: pb.Person_WORK},
{Number: "777-777-7777", Type: pb.Person_MOBILE},
}
if len(got.Phones) != len(want) {
t.Errorf("want %d phone numbers, got %d", len(want), len(got.Phones))
}
phones := len(got.Phones)
if phones > len(want) {
phones = len(want)
}
for i := 0; i < phones; i++ {
if !proto.Equal(got.Phones[i], want[i]) {
t.Errorf("want phone %q, got %q", want[i], got.Phones[i])
}
}
}

View File

@@ -0,0 +1,61 @@
package main
import (
"fmt"
"io"
"io/ioutil"
"log"
"os"
pb "github.com/protocolbuffers/protobuf/examples/go/tutorialpb"
"google.golang.org/protobuf/proto"
)
func writePerson(w io.Writer, p *pb.Person) {
fmt.Fprintln(w, "Person ID:", p.Id)
fmt.Fprintln(w, " Name:", p.Name)
if p.Email != "" {
fmt.Fprintln(w, " E-mail address:", p.Email)
}
for _, pn := range p.Phones {
switch pn.Type {
case pb.Person_MOBILE:
fmt.Fprint(w, " Mobile phone #: ")
case pb.Person_HOME:
fmt.Fprint(w, " Home phone #: ")
case pb.Person_WORK:
fmt.Fprint(w, " Work phone #: ")
}
fmt.Fprintln(w, pn.Number)
}
}
func listPeople(w io.Writer, book *pb.AddressBook) {
for _, p := range book.People {
writePerson(w, p)
}
}
// Main reads the entire address book from a file and prints all the
// information inside.
func main() {
if len(os.Args) != 2 {
log.Fatalf("Usage: %s ADDRESS_BOOK_FILE\n", os.Args[0])
}
fname := os.Args[1]
// [START unmarshal_proto]
// Read the existing address book.
in, err := ioutil.ReadFile(fname)
if err != nil {
log.Fatalln("Error reading file:", err)
}
book := &pb.AddressBook{}
if err := proto.Unmarshal(in, book); err != nil {
log.Fatalln("Failed to parse address book:", err)
}
// [END unmarshal_proto]
listPeople(os.Stdout, book)
}

View File

@@ -0,0 +1,120 @@
package main
import (
"bytes"
"strings"
"testing"
pb "github.com/protocolbuffers/protobuf/examples/go/tutorialpb"
)
func TestWritePersonWritesPerson(t *testing.T) {
buf := new(bytes.Buffer)
// [START populate_proto]
p := pb.Person{
Id: 1234,
Name: "John Doe",
Email: "jdoe@example.com",
Phones: []*pb.Person_PhoneNumber{
{Number: "555-4321", Type: pb.Person_HOME},
},
}
// [END populate_proto]
writePerson(buf, &p)
got := buf.String()
want := `Person ID: 1234
Name: John Doe
E-mail address: jdoe@example.com
Home phone #: 555-4321
`
if got != want {
t.Errorf("writePerson(%s) =>\n\t%q, want %q", p.String(), got, want)
}
}
func TestListPeopleWritesList(t *testing.T) {
buf := new(bytes.Buffer)
in := pb.AddressBook{People: []*pb.Person{
{
Name: "John Doe",
Id: 101,
Email: "john@example.com",
},
{
Name: "Jane Doe",
Id: 102,
},
{
Name: "Jack Doe",
Id: 201,
Email: "jack@example.com",
Phones: []*pb.Person_PhoneNumber{
{Number: "555-555-5555", Type: pb.Person_WORK},
},
},
{
Name: "Jack Buck",
Id: 301,
Email: "buck@example.com",
Phones: []*pb.Person_PhoneNumber{
{Number: "555-555-0000", Type: pb.Person_HOME},
{Number: "555-555-0001", Type: pb.Person_MOBILE},
{Number: "555-555-0002", Type: pb.Person_WORK},
},
},
{
Name: "Janet Doe",
Id: 1001,
Email: "janet@example.com",
Phones: []*pb.Person_PhoneNumber{
{Number: "555-777-0000"},
{Number: "555-777-0001", Type: pb.Person_HOME},
},
},
}}
listPeople(buf, &in)
want := strings.Split(`Person ID: 101
Name: John Doe
E-mail address: john@example.com
Person ID: 102
Name: Jane Doe
Person ID: 201
Name: Jack Doe
E-mail address: jack@example.com
Work phone #: 555-555-5555
Person ID: 301
Name: Jack Buck
E-mail address: buck@example.com
Home phone #: 555-555-0000
Mobile phone #: 555-555-0001
Work phone #: 555-555-0002
Person ID: 1001
Name: Janet Doe
E-mail address: janet@example.com
Mobile phone #: 555-777-0000
Home phone #: 555-777-0001
`, "\n")
got := strings.Split(buf.String(), "\n")
if len(got) != len(want) {
t.Errorf(
"listPeople(%s) =>\n\t%q has %d lines, want %d",
in.String(),
buf.String(),
len(got),
len(want))
}
lines := len(got)
if lines > len(want) {
lines = len(want)
}
for i := 0; i < lines; i++ {
if got[i] != want[i] {
t.Errorf(
"listPeople(%s) =>\n\tline %d %q, want %q",
in.String(),
i,
got[i],
want[i])
}
}
}

View File

@@ -0,0 +1,5 @@
module github.com/protocolbuffers/protobuf/examples/go
go 1.14
require google.golang.org/protobuf v1.27.1

View File

@@ -0,0 +1,6 @@
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=

View File

@@ -0,0 +1,79 @@
// See README.txt for information and build instructions.
#include <fstream>
#include <google/protobuf/util/time_util.h>
#include <iostream>
#include <string>
#include "addressbook.pb.h"
using namespace std;
using google::protobuf::util::TimeUtil;
// Iterates though all people in the AddressBook and prints info about them.
void ListPeople(const tutorial::AddressBook& address_book) {
for (int i = 0; i < address_book.people_size(); i++) {
const tutorial::Person& person = address_book.people(i);
cout << "Person ID: " << person.id() << endl;
cout << " Name: " << person.name() << endl;
if (person.email() != "") {
cout << " E-mail address: " << person.email() << endl;
}
for (int j = 0; j < person.phones_size(); j++) {
const tutorial::Person::PhoneNumber& phone_number = person.phones(j);
switch (phone_number.type()) {
case tutorial::Person::MOBILE:
cout << " Mobile phone #: ";
break;
case tutorial::Person::HOME:
cout << " Home phone #: ";
break;
case tutorial::Person::WORK:
cout << " Work phone #: ";
break;
default:
cout << " Unknown phone #: ";
break;
}
cout << phone_number.number() << endl;
}
if (person.has_last_updated()) {
cout << " Updated: " << TimeUtil::ToString(person.last_updated()) << endl;
}
}
}
// Main function: Reads the entire address book from a file and prints all
// the information inside.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 2) {
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
return -1;
}
tutorial::AddressBook address_book;
{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}
ListPeople(address_book);
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return 0;
}

View File

@@ -0,0 +1,47 @@
import 'dart:io';
import 'dart_tutorial/addressbook.pb.dart';
import 'dart_tutorial/addressbook.pbenum.dart';
/// Iterates though all people in the AddressBook and prints info about them.
void printAddressBook(AddressBook addressBook) {
for (var person in addressBook.people) {
print('Person ID: ${person.id}');
print(' Name: ${person.name}');
if (person.hasEmail()) {
print(' E-mail address:${person.email}');
}
for (var phoneNumber in person.phones) {
switch (phoneNumber.type) {
case Person_PhoneType.MOBILE:
print(' Mobile phone #: ');
break;
case Person_PhoneType.HOME:
print(' Home phone #: ');
break;
case Person_PhoneType.WORK:
print(' Work phone #: ');
break;
default:
print(' Unknown phone #: ');
break;
}
print(phoneNumber.number);
}
}
}
/// Reads the entire address book from a file and prints all
/// the information inside.
void main(List<String> arguments) {
if (arguments.length != 1) {
print('Usage: list_person ADDRESS_BOOK_FILE');
exit(-1);
}
// Read the existing address book.
final file = new File(arguments.first);
final addressBook = new AddressBook.fromBuffer(file.readAsBytesSync());
printAddressBook(addressBook);
}

View File

@@ -0,0 +1,40 @@
#! /usr/bin/env python
# See README.txt for information and build instructions.
from __future__ import print_function
import addressbook_pb2
import sys
# Iterates though all people in the AddressBook and prints info about them.
def ListPeople(address_book):
for person in address_book.people:
print("Person ID:", person.id)
print(" Name:", person.name)
if person.email != "":
print(" E-mail address:", person.email)
for phone_number in person.phones:
if phone_number.type == addressbook_pb2.Person.MOBILE:
print(" Mobile phone #:", end=" ")
elif phone_number.type == addressbook_pb2.Person.HOME:
print(" Home phone #:", end=" ")
elif phone_number.type == addressbook_pb2.Person.WORK:
print(" Work phone #:", end=" ")
print(phone_number.number)
# Main procedure: Reads the entire address book from a file and prints all
# the information inside.
if len(sys.argv) != 2:
print("Usage:", sys.argv[0], "ADDRESS_BOOK_FILE")
sys.exit(-1)
address_book = addressbook_pb2.AddressBook()
# Read the existing address book.
with open(sys.argv[1], "rb") as f:
address_book.ParseFromString(f.read())
ListPeople(address_book)

View File

@@ -0,0 +1,5 @@
name: addressbook
description: dartlang.org example code.
dependencies:
protobuf: