Реализация буферов протокола в Swift.
Буферы протокола являются способом кодирования структурированных данных в эффективном, но расширяемом формате. Этот проект основан на реализации буферов протокола от Google. Смотрите проект Google Protobuf для получения дополнительной информации.
1. wget https://github.com/google/protobuf/archive/v3.2.0.tar.gz
2. tar xzf v3.2.0.tar.gz
3. cd protobuf-3.2.0/
4. sudo apt-get install autoreconf automake libtool make
5. ./autogen.sh
6. ./configure CXXFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib
7. sudo make && sudo make install
cd .. && wget https://github.com/alexeyxo/protobuf-swift/archive/3.0.9.tar.gz && tar xzf 3.0.9.tar.gz && cd protobuf-swift-3.0.9
9. ./script/build.sh && swift build
1. ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
2. brew install protobuf-swift
1. ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
2. brew install automake
3. brew install libtool
4. brew install protobuf
5. git clone [email protected]:alexeyxo/protobuf-swift.git
6. ./scripts/build.sh
Добавить ./src/ProtocolBuffers/ProtocolBuffers.xcodeproj в вашем проекте.
Podfile:
use_frameworks!
pod 'ProtocolBuffers-Swift'
Cartfile:
github "alexeyxo/protobuf-swift"
protoc person.proto --swift_out= " ./ " syntax = "proto2" ;
message Person {
required int32 id = 1 ;
required string name = 2 ;
optional string email = 3 ;
} let personBuilder = Person . Builder ( )
personBuilder . id = 123
personBuilder . name = " Bob "
personBuilder . email = " [email protected] "
let person = try ! personBuilder . build ( )
print ( person )
person . data ( ) //return NSData syntax = "proto2" ;
message Perfomance
{
required int32 ints = 1 ;
required int64 ints64 = 2 ;
required double doubles = 3 ;
required float floats = 4 ;
optional string str = 5 ;
optional bytes bytes = 6 ;
optional string description = 7 ;
} var originalBuilder = ProtoPerfomance . Builder ( )
originalBuilder . setInts ( Int32 ( 32 ) )
. setInts64 ( Int64 ( 64 ) )
. setDoubles ( Double ( 12.12 ) )
. setFloats ( Float ( 123.123 ) )
. setStr ( " string " )
let original = originalBuilder . build ( ) syntax = "proto2" ;
message Foo {
optional int32 val = 1 ;
// some other fields.
}
message Bar {
optional Foo foo = 1 ;
// some other fields.
}
message Baz {
optional Bar bar = 1 ;
// some other fields.
} var builder = baz . toBuilder ( )
builder . getBarBuilder ( ) . getFooBuilder ( ) . setVal ( 10 )
baz = builder . build ( ) syntax = "proto3" ;
message MapMessageValue
{
int32 valueInMapMessage = 1 ;
}
message MessageContainsMap
{
enum EnumMapValue
{
FirstValueEnum = 0 ;
SecondValueEnum = 1 ;
}
map < int32 , int32 > map_int32_int32 = 1 ;
map < int64 , int64 > map_int64_int64 = 2 ;
map < string , string > map_string_string = 3 ;
map < string , bytes > map_string_bytes = 4 ;
map < string , MapMessageValue > map_string_message = 5 ;
map < int32 , EnumMapValue > map_int32_enum = 6 ;
} final internal class MessageContainsMap : GeneratedMessage , GeneratedMessageProtocol , Hashable {
...
private ( set ) var mapInt32Int32 : Dictionary < Int32 , Int32 > = Dictionary < Int32 , Int32 > ( )
private ( set ) var mapInt64Int64 : Dictionary < Int64 , Int64 > = Dictionary < Int64 , Int64 > ( )
private ( set ) var mapStringString : Dictionary < String , String > = Dictionary < String , String > ( )
private ( set ) var mapStringBytes : Dictionary < String , NSData > = Dictionary < String , NSData > ( )
private ( set ) var mapInt32Enum : Dictionary < Int32 , MessageContainsMap . EnumMapValue > = Dictionary < Int32 , MessageContainsMap . EnumMapValue > ( )
...
} let personBuilder = Person . builder ( )
personBuilder . id = 123
personBuilder . name = " Bob "
personBuilder . email = " [email protected] "
let person = personBuilder . build ( )
let jsonData = person . toJSON ( ) //return NSData
let jsonDictionaryObject : Dictionary < String , AnyObject > = person . encode ( )
let personFromJson = Person . fromJSON ( jsonData ) //Person var person = Person . parseFromData ( bytes ) // from NSData syntax = "proto3" ;
message SubMessage {
string str = 1 ;
}
message SampleMessage {
oneof test_oneof {
string name = 4 ;
int32 id = 5 ;
SubMessage mes = 6 ;
}
} var sm = SampleMessage . Builder ( )
sm . name = " Alex "
sm . id = 123
println ( ss . build ( ) ) //-> id: 123 syntax = "proto3" ;
message SearchResponse {
message Result {
string url = 1 ;
string title = 2 ;
repeated string snippets = 3 ;
}
repeated Result result = 1 ;
} var builderResult = SearchResponse . Result . Builder ( )
builderResult . url = " http://protobuf.axo.io "
builderResult . title = " Protocol Bufers Apple Swift "
var searchRespons = SearchResponse . builder ( )
searchRespons . result += [ builderResult . build ( ) ]
println ( searchRespons . build ( ) ) syntax = "proto2" ;
package FooBar ;
message Perfomance
{
required int32 ints = 1 ;
required int64 ints64 = 2 ;
required double doubles = 3 ;
required float floats = 4 ;
optional string str = 5 ;
optional bytes bytes = 6 ;
optional string description = 7 ;
} public extension FooBar {
...
final public class Perfomance : GeneratedMessage , GeneratedMessageProtocol {
...
}
} import "google/protobuf/descriptor.proto" ;
package google.protobuf ;
enum AccessControl {
InternalEntities = 0 ;
PublicEntities = 1 ;
}
message SwiftFileOptions {
optional string class_prefix = 1 ;
optional AccessControl entities_access_control = 2 [ default = PublicEntities ];
optional bool compile_for_framework = 3 [ default = true ];
}
message SwiftMessageOptions {
optional bool generate_error_type = 1 [ default = false ];
}
message SwiftEnumOptions {
optional bool generate_error_type = 1 [ default = false ];
}
extend google.protobuf.FileOptions {
optional SwiftFileOptions swift_file_options = 5092014 ;
}
extend google.protobuf.MessageOptions {
optional SwiftMessageOptions swift_message_options = 5092014 ;
}
extend google.protobuf.EnumOptions {
optional SwiftEnumOptions swift_enum_options = 5092015 ;
}
option (.google.protobuf.swift_file_options).compile_for_framework = false;
option (.google.protobuf.swift_file_options).entities_access_control = PublicEntities;В настоящее время компилятор Protobuf-Swift поддерживает пользовательские параметры.
Если у вас есть пользовательские параметры, вам нужно добавить:
import 'google/protobuf/swift-descriptor.proto'; В ваших файлах .proto .
Эта опция должна генерировать имена классов с префиксом.
Пример:
import 'google/protobuf/swift-descriptor.proto';
option (.google.protobuf.swift_file_options).class_prefix = "Proto";
message NameWithPrefix
{
optional string str = 1 ;
}Сгенерированный класс имеет имя:
final internal class ProtoNameWithPrefix : GeneratedMessageoption (.google.protobuf.swift_file_options).entities_access_control = PublicEntities; Все сгенерированные классы отмечены как internal по умолчанию. Если вы хотите, чтобы Mark был public , вы можете использовать опцию entities_access_control .
option (.google.protobuf.swift_file_options).entities_access_control = PublicEntities;
message MessageWithCustomOption
{
optional string str = 1 ;
} Сгенерированный класс и все области отмечены public :
final public class MessageWithCustomOption : GeneratedMessageoption (.google.protobuf.swift_enum_options).generate_error_type = true;import 'google/protobuf/swift-descriptor.proto';
enum ServiceError {
option (.google.protobuf.swift_enum_options).generate_error_type = true;
BadRequest = 0 ;
InternalServerError = 1 ;
}
message UserProfile {
message Request {
required string userId = 1 ;
}
message Response {
optional UserProfile profile = 1 ;
optional ServiceError error = 2 ;
optional Exception exception = 3 ;
}
message Exception {
option (.google.protobuf.swift_message_options).generate_error_type = true;
required int32 errorCode = 1 ;
required string errorDescription = 2 ;
}
optional string firstName = 1 ;
optional string lastName = 2 ;
optional string avatarUrl = 3 ;
} public enum ServiceError : Error , RawRepresentable , CustomDebugStringConvertible , CustomStringConvertible {
public typealias RawValue = Int32
case badRequest
case internalServerError
public init ? ( rawValue : RawValue ) {
switch rawValue {
case 0 : self = . badRequest
case 1 : self = . internalServerError
default : return nil
}
}
public var rawValue : RawValue {
switch self {
case . badRequest : return 0
case . internalServerError : return 1
}
}
public func throwException ( ) throws {
throw self
}
public var debugDescription : String { return getDescription ( ) }
public var description : String { return getDescription ( ) }
private func getDescription ( ) -> String {
switch self {
case . badRequest : return " .badRequest "
case . internalServerError : return " .internalServerError "
}
}
} func generateException ( ) throws {
let user = UserProfile . Response . Builder ( )
user . error = . internalServerError
let data = try user . build ( ) . data ( )
let userError = try UserProfile . Response . parseFrom ( data : data )
if userError . hasError {
throw userError . error //userError.error.throwException()
}
}
do {
try generateException ( )
} catch let err as ServiceError where err == . internalServerError {
XCTAssertTrue ( true )
} catch {
XCTAssertTrue ( false )
}
func throwExceptionMessage ( ) throws {
let exception = UserProfile . Exception . Builder ( )
exception . errorCode = 403
exception . errorDescription = " Bad Request "
let exc = try exception . build ( )
let data = try UserProfile . Response . Builder ( ) . setException ( exc ) . build ( ) . data ( )
let userError = try UserProfile . Response . parseFrom ( data : data )
if userError . hasException {
throw userError . exception
}
}
do {
try throwExceptionMessage ( )
} catch let err as UserProfile . Exception {
print ( err )
XCTAssertTrue ( true )
} catch {
XCTAssertTrue ( false )
}
option (.google.protobuf.swift_file_options).compile_for_framework = false; Эта опция удаляет import ProtocolBuffers строки сгенерированных файлов.
Добавлен хорошо известный тип Protos (any.proto, umpt.proto, timestamp.proto, duration.proto и т. Д.). Пользователи могут импортировать и использовать эти прото так же, как обычные прото -файлы. Поддержка дополнительной среды выполнения будет добавлена для них в будущих выпусках (в форме функций вспомогательных услуг, или их замены на языковые типы в созданных коде).
message Any {
// A URL/resource name whose content describes the type of the
// serialized message.
//
// For URLs which use the schema `http`, `https`, or no schema, the
// following restrictions and interpretations apply:
//
// * If no schema 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`).
// * An HTTP GET on the URL must yield a [google.protobuf.Type][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.)
//
// Schemas other than `http`, `https` (or the empty schema) might be
// used with implementation specific semantics.
//
// Types originating from the `google.*` package
// namespace should use `type.googleapis.com/full.type.name` (without
// schema and path). A type service will eventually become available which
// serves those URLs (projected Q2/15).
string type_url = 1 ;
// Must be valid serialized data of the above specified type.
bytes value = 2 ;
} Google . Protobuf . Any ( ) message Api {
// The fully qualified name of this api, including package name
// followed by the api's simple name.
string name = 1 ;
// The methods of this api, in unspecified order.
repeated Method methods = 2 ;
// Any metadata attached to the API.
repeated Option options = 3 ;
// A version string for this api. If specified, must have the form
// `major-version.minor-version`, as in `1.10`. If the minor version
// is omitted, it defaults to zero. If the entire version field is
// empty, the major version is derived from the package name, as
// outlined below. If the field is not empty, the version in the
// package name will be verified to be consistent with what is
// provided here.
//
// The versioning schema uses [semantic
// versioning](http://semver.org) where the major version number
// indicates a breaking change and the minor version an additive,
// non-breaking change. Both version numbers are signals to users
// what to expect from different versions, and should be carefully
// chosen based on the product plan.
//
// The major version is also reflected in the package name of the
// API, which must end in `v<major-version>`, as in
// `google.feature.v1`. For major versions 0 and 1, the suffix can
// be omitted. Zero major versions must only be used for
// experimental, none-GA apis.
//
// See also: [design doc](http://go/api-versioning).
//
//
string version = 4 ;
// Source context for the protocol buffer service represented by this
// message.
SourceContext source_context = 5 ;
}
// Method represents a method of an api.
message Method {
// The simple name of this method.
string name = 1 ;
// A URL of the input message type.
string request_type_url = 2 ;
// If true, the request is streamed.
bool request_streaming = 3 ;
// The URL of the output message type.
string response_type_url = 4 ;
// If true, the response is streamed.
bool response_streaming = 5 ;
// Any metadata attached to the method.
repeated Option options = 6 ;
} Google . Protobuf . Api ( ) message Duration {
// Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive.
int64 seconds = 1 ;
// Signed fractions of a second at nanosecond resolution of the span
// of time. Durations less than one second are represented with a 0
// `seconds` field and a positive or negative `nanos` field. For durations
// of one second or more, a non-zero value for the `nanos` field must be
// of the same sign as the `seconds` field. Must be from -999,999,999
// to +999,999,999 inclusive.
int32 nanos = 2 ;
} Google . Protobuf . Duration ( ) message Empty {
} Google . Protobuf . Empty ( ) message FieldMask {
// The set of field mask paths.
repeated string paths = 1 ;
} Google . Protobuf . FieldMask ( ) message SourceContext {
// The path-qualified name of the .proto file that contained the associated
// protobuf element. For example: `"google/protobuf/source.proto"`.
string file_name = 1 ;
} Google . Protobuf . SourceContext ( ) message Struct {
// Map of dynamically typed values.
map < string , Value > fields = 1 ;
}
// `Value` represents a dynamically typed value which can be either
// null, a number, a string, a boolean, a recursive struct value, or a
// list of values. A producer of value is expected to set one of that
// variants, absence of any variant indicates an error.
message Value {
oneof kind {
// Represents a null value.
NullValue null_value = 1 ;
// Represents a double value.
double number_value = 2 ;
// Represents a string value.
string string_value = 3 ;
// Represents a boolean value.
bool bool_value = 4 ;
// Represents a structured value.
Struct struct_value = 5 ;
// Represents a repeated `Value`.
ListValue list_value = 6 ;
}
}
// `ListValue` is a wrapper around a repeated field of values.
message ListValue {
// Repeated field of dynamically typed values.
repeated Value values = 1 ;
}
// `NullValue` is a singleton enumeration to represent the null
// value for the `Value` type union.
enum NullValue {
// Null value.
NULL_VALUE = 0 ;
} Google . Protobuf . Struct ( ) message Timestamp {
// Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive.
int64 seconds = 1 ;
// Non-negative fractions of a second at nanosecond resolution. Negative
// second values with fractions must still have non-negative nanos values
// that count forward in time. Must be from 0 to 999,999,999
// inclusive.
int32 nanos = 2 ;
} Google . Protobuf . Timestamp ( ) message Type {
// The fully qualified message name.
string name = 1 ;
// The list of fields.
repeated Field fields = 2 ;
// The list of oneof definitions.
// The list of oneofs declared in this Type
repeated string oneofs = 3 ;
// The proto options.
repeated Option options = 4 ;
// The source context.
SourceContext source_context = 5 ;
}
// Field represents a single field of a message type.
message Field {
// Kind represents a basic field type.
enum Kind {
// Field type unknown.
TYPE_UNKNOWN = 0 ;
// Field type double.
TYPE_DOUBLE = 1 ;
// Field type float.
TYPE_FLOAT = 2 ;
// Field type int64.
TYPE_INT64 = 3 ;
// Field type uint64.
TYPE_UINT64 = 4 ;
// Field type int32.
TYPE_INT32 = 5 ;
// Field type fixed64.
TYPE_FIXED64 = 6 ;
// Field type fixed32.
TYPE_FIXED32 = 7 ;
// Field type bool.
TYPE_BOOL = 8 ;
// Field type string.
TYPE_STRING = 9 ;
// Field type message.
TYPE_MESSAGE = 11 ;
// Field type bytes.
TYPE_BYTES = 12 ;
// Field type uint32.
TYPE_UINT32 = 13 ;
// Field type enum.
TYPE_ENUM = 14 ;
// Field type sfixed32.
TYPE_SFIXED32 = 15 ;
// Field type sfixed64.
TYPE_SFIXED64 = 16 ;
// Field type sint32.
TYPE_SINT32 = 17 ;
// Field type sint64.
TYPE_SINT64 = 18 ;
}
// Cardinality represents whether a field is optional, required, or
// repeated.
enum Cardinality {
// The field cardinality is unknown. Typically an error condition.
CARDINALITY_UNKNOWN = 0 ;
// For optional fields.
CARDINALITY_OPTIONAL = 1 ;
// For required fields. Not used for proto3.
CARDINALITY_REQUIRED = 2 ;
// For repeated fields.
CARDINALITY_REPEATED = 3 ;
}
// The field kind.
Kind kind = 1 ;
// The field cardinality, i.e. optional/required/repeated.
Cardinality cardinality = 2 ;
// The proto field number.
int32 number = 3 ;
// The field name.
string name = 4 ;
// The type URL (without the scheme) when the type is MESSAGE or ENUM,
// such as `type.googleapis.com/google.protobuf.Empty`.
string type_url = 6 ;
// Index in Type.oneofs. Starts at 1. Zero means no oneof mapping.
int32 oneof_index = 7 ;
// Whether to use alternative packed wire representation.
bool packed = 8 ;
// The proto options.
repeated Option options = 9 ;
}
// Enum type definition.
message Enum {
// Enum type name.
string name = 1 ;
// Enum value definitions.
repeated EnumValue enumvalue = 2 ;
// Proto options for the enum type.
repeated Option options = 3 ;
// The source context.
SourceContext source_context = 4 ;
}
// Enum value definition.
message EnumValue {
// Enum value name.
string name = 1 ;
// Enum value number.
int32 number = 2 ;
// Proto options for the enum value.
repeated Option options = 3 ;
}
// Proto option attached to messages/fields/enums etc.
message Option {
// Proto option name.
string name = 1 ;
// Proto option value.
Any value = 2 ;
} Google . Protobuf . Type ( )
... // Wrapper message for double.
message DoubleValue {
// The double value.
double value = 1 ;
}
// Wrapper message for float.
message FloatValue {
// The float value.
float value = 1 ;
}
// Wrapper message for int64.
message Int64Value {
// The int64 value.
int64 value = 1 ;
}
// Wrapper message for uint64.
message UInt64Value {
// The uint64 value.
uint64 value = 1 ;
}
// Wrapper message for int32.
message Int32Value {
// The int32 value.
int32 value = 1 ;
}
// Wrapper message for uint32.
message UInt32Value {
// The uint32 value.
uint32 value = 1 ;
}
// Wrapper message for bool.
message BoolValue {
// The bool value.
bool value = 1 ;
}
// Wrapper message for string.
message StringValue {
// The string value.
string value = 1 ;
}
// Wrapper message for bytes.
message BytesValue {
// The bytes value.
bytes value = 1 ;
} Google . Protobuf . StringValue ( )Разработчик - Алексей Хохлов
Буферы протокола Google - Сайрус Наджмабади, Сергей Мартинов, Кентон Варда, Санджай Гемават, Джефф Дин и другие