Add LND test wallet

This commit is contained in:
adrianaepure
2023-06-08 09:36:06 +03:00
commit 1313d727cf
251 changed files with 57518 additions and 0 deletions

1
Lndmobile.framework/Headers Symbolic link
View File

@ -0,0 +1 @@
Versions/Current/Headers

View File

@ -0,0 +1 @@
Versions/Current/Lndmobile

1
Lndmobile.framework/Modules Symbolic link
View File

@ -0,0 +1 @@
Versions/Current/Modules

View File

@ -0,0 +1 @@
Versions/Current/Resources

View File

@ -0,0 +1,13 @@
// Objective-C API for talking to the following Go packages
//
// github.com/lightningnetwork/lnd/mobile
//
// File is generated by gomobile bind. Do not edit.
#ifndef __Lndmobile_FRAMEWORK_H__
#define __Lndmobile_FRAMEWORK_H__
#include "Lndmobile.objc.h"
#include "Universe.objc.h"
#endif

View File

@ -0,0 +1,839 @@
// Objective-C API for talking to github.com/lightningnetwork/lnd/mobile Go package.
// gobind -lang=objc github.com/lightningnetwork/lnd/mobile
//
// File is generated by gobind. Do not edit.
#ifndef __Lndmobile_H__
#define __Lndmobile_H__
@import Foundation;
#include "ref.h"
#include "Universe.objc.h"
@protocol LndmobileCallback;
@class LndmobileCallback;
@protocol LndmobileRecvStream;
@class LndmobileRecvStream;
@protocol LndmobileSendStream;
@class LndmobileSendStream;
@protocol LndmobileCallback <NSObject>
- (void)onError:(NSError* _Nullable)p0;
- (void)onResponse:(NSData* _Nullable)p0;
@end
@protocol LndmobileRecvStream <NSObject>
- (void)onError:(NSError* _Nullable)p0;
- (void)onResponse:(NSData* _Nullable)p0;
@end
@protocol LndmobileSendStream <NSObject>
- (BOOL)send:(NSData* _Nullable)p0 error:(NSError* _Nullable* _Nullable)error;
- (BOOL)stop:(NSError* _Nullable* _Nullable)error;
@end
/**
* AbandonChannel removes all channel state from the database except for a
close summary. This method can be used to get rid of permanently unusable
channels due to bugs fixed in newer versions of lnd. This method can also be
used to remove externally funded channels where the funding transaction was
never broadcast. Only available for non-externally funded channels in dev
build.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileAbandonChannel(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* AddInvoice attempts to add a new invoice to the invoice database. Any
duplicated invoices are rejected, therefore all invoices *must* have a
unique payment preimage.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileAddInvoice(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* BakeMacaroon allows the creation of a new macaroon with custom read and
write permissions. No first-party caveats are added since this can be done
offline.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileBakeMacaroon(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ChangePassword changes the password of the encrypted wallet. This will
automatically unlock the wallet database if successful.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileChangePassword(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ChannelAcceptor dispatches a bi-directional streaming RPC in which
OpenChannel requests are sent to the client and the client responds with
a boolean that tells LND whether or not to accept the channel. This allows
node operators to specify their own criteria for accepting inbound channels
through a single persistent connection.
NOTE: This method produces a stream of responses, and the receive stream can
be called zero or more times. After EOF error is returned, no more responses
will be produced. The send stream can accept zero or more requests before it
is closed.
*/
FOUNDATION_EXPORT id<LndmobileSendStream> _Nullable LndmobileChannelAcceptor(id<LndmobileRecvStream> _Nullable rStream, NSError* _Nullable* _Nullable error);
/**
* ChannelBalance returns the total funds available across all open channels
in satoshis.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileChannelBalance(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* CloseChannel attempts to close an active channel identified by its channel
outpoint (ChannelPoint). The actions of this method can additionally be
augmented to attempt a force close after a timeout period in the case of an
inactive peer. If a non-force close (cooperative closure) is requested,
then the user can specify either a target number of blocks until the
closure transaction is confirmed, or a manual fee rate. If neither are
specified, then a default lax, block confirmation target is used.
NOTE: This method produces a stream of responses, and the receive stream can
be called zero or more times. After EOF error is returned, no more responses
will be produced.
*/
FOUNDATION_EXPORT void LndmobileCloseChannel(NSData* _Nullable msg, id<LndmobileRecvStream> _Nullable rStream);
/**
* ClosedChannels returns a description of all the closed channels that
this node was a participant in.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileClosedChannels(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ConnectPeer attempts to establish a connection to a remote peer. This is at
the networking level, and is used for communication between nodes. This is
distinct from establishing a channel with a peer.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileConnectPeer(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* DebugLevel allows a caller to programmatically set the logging verbosity of
lnd. The logging can be targeted according to a coarse daemon-wide logging
level, or in a granular fashion to specify the logging for a target
sub-system.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileDebugLevel(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* DecodePayReq takes an encoded payment request string and attempts to decode
it, returning a full description of the conditions encoded within the
payment request.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileDecodePayReq(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* DeleteAllPayments deletes all outgoing payments from DB.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileDeleteAllPayments(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* DescribeGraph returns a description of the latest graph state from the
point of view of the node. The graph information is partitioned into two
components: all the nodes/vertexes, and all the edges that connect the
vertexes themselves. As this is a directed graph, the edges also contain
the node directional specific routing policy which includes: the time lock
delta, fee information, etc.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileDescribeGraph(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* DisconnectPeer attempts to disconnect one peer from another identified by a
given pubKey. In the case that we currently have a pending or active channel
with the target peer, then this action will be not be allowed.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileDisconnectPeer(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* EstimateFee asks the chain backend to estimate the fee rate and total fees
for a transaction that pays to multiple specified outputs.
When using REST, the `AddrToAmount` map type can be set by appending
`&AddrToAmount[<address>]=<amount_to_send>` to the URL. Unfortunately this
map type doesn't appear in the REST API documentation because of a bug in
the grpc-gateway library.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileEstimateFee(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ExportAllChannelBackups returns static channel backups for all existing
channels known to lnd. A set of regular singular static channel backups for
each channel are returned. Additionally, a multi-channel backup is returned
as well, which contains a single encrypted blob containing the backups of
each channel.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileExportAllChannelBackups(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ExportChannelBackup attempts to return an encrypted static channel backup
for the target channel identified by it channel point. The backup is
encrypted with a key generated from the aezeed seed of the user. The
returned backup can either be restored using the RestoreChannelBackup
method once lnd is running, or via the InitWallet and UnlockWallet methods
from the WalletUnlocker service.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileExportChannelBackup(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* FeeReport allows the caller to obtain a report detailing the current fee
schedule enforced by the node globally for each channel.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileFeeReport(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ForwardingHistory allows the caller to query the htlcswitch for a record of
all HTLCs forwarded within the target time range, and integer offset
within that time range. If no time-range is specified, then the first chunk
of the past 24 hrs of forwarding history are returned.
A list of forwarding events are returned. The size of each forwarding event
is 40 bytes, and the max message size able to be returned in gRPC is 4 MiB.
As a result each message can only contain 50k entries. Each response has
the index offset of the last entry. The index offset can be provided to the
request to allow the caller to skip a series of records.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileForwardingHistory(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* FundingStateStep is an advanced funding related call that allows the caller
to either execute some preparatory steps for a funding workflow, or
manually progress a funding workflow. The primary way a funding flow is
identified is via its pending channel ID. As an example, this method can be
used to specify that we're expecting a funding flow for a particular
pending channel ID, for which we need to use specific parameters.
Alternatively, this can be used to interactively drive PSBT signing for
funding for partially complete funding transactions.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileFundingStateStep(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* GenSeed is the first method that should be used to instantiate a new lnd
instance. This method allows a caller to generate a new aezeed cipher seed
given an optional passphrase. If provided, the passphrase will be necessary
to decrypt the cipherseed to expose the internal wallet seed.
Once the cipherseed is obtained and verified by the user, the InitWallet
method should be used to commit the newly generated seed, and create the
wallet.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileGenSeed(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* GetChanInfo returns the latest authenticated network announcement for the
given channel identified by its channel ID: an 8-byte integer which
uniquely identifies the location of transaction's funding output within the
blockchain.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileGetChanInfo(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* GetInfo returns general information concerning the lightning node including
it's identity pubkey, alias, the chains it is connected to, and information
concerning the number of open+pending channels.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileGetInfo(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* GetNetworkInfo returns some basic stats about the known channel graph from
the point of view of the node.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileGetNetworkInfo(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* GetNodeInfo returns the latest advertised, aggregated, and authenticated
channel information for the specified node identified by its public key.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileGetNodeInfo(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* GetNodeMetrics returns node metrics calculated from the graph. Currently
the only supported metric is betweenness centrality of individual nodes.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileGetNodeMetrics(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* GetRecoveryInfo returns information concerning the recovery mode including
whether it's in a recovery mode, whether the recovery is finished, and the
progress made so far.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileGetRecoveryInfo(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* GetTransactions returns a list describing all the known transactions
relevant to the wallet.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileGetTransactions(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* InitWallet is used when lnd is starting up for the first time to fully
initialize the daemon and its internal wallet. At the very least a wallet
password must be provided. This will be used to encrypt sensitive material
on disk.
In the case of a recovery scenario, the user can also specify their aezeed
mnemonic and passphrase. If set, then the daemon will use this prior state
to initialize its internal wallet.
Alternatively, this can be used along with the GenSeed RPC to obtain a
seed, then present it to the user. Once it has been verified by the user,
the seed can be fed into this RPC in order to commit the new wallet.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileInitWallet(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ListChannels returns a description of all the open channels that this node
is a participant in.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileListChannels(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ListInvoices returns a list of all the invoices currently stored within the
database. Any active debug invoices are ignored. It has full support for
paginated responses, allowing users to query for specific invoices through
their add_index. This can be done by using either the first_index_offset or
last_index_offset fields included in the response as the index_offset of the
next request. By default, the first 100 invoices created will be returned.
Backwards pagination is also supported through the Reversed flag.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileListInvoices(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ListPayments returns a list of all outgoing payments.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileListPayments(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ListPeers returns a verbose listing of all currently active peers.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileListPeers(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ListPermissions lists all RPC method URIs and their required macaroon
permissions to access them.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileListPermissions(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileListUnspent(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* LookupInvoice attempts to look up an invoice according to its payment hash.
The passed payment hash *must* be exactly 32 bytes, if not, an error is
returned.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileLookupInvoice(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* ModifyStatus is used to modify the status of the autopilot agent, like
enabling or disabling it.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileModifyStatus(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* NewAddress creates a new address under control of the local wallet.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileNewAddress(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* OpenChannel attempts to open a singly funded channel specified in the
request to a remote peer. Users are able to specify a target number of
blocks that the funding transaction should be confirmed in, or a manual fee
rate to us for the funding transaction. If neither are specified, then a
lax block confirmation target is used. Each OpenStatusUpdate will return
the pending channel ID of the in-progress channel. Depending on the
arguments specified in the OpenChannelRequest, this pending channel ID can
then be used to manually progress the channel funding flow.
NOTE: This method produces a stream of responses, and the receive stream can
be called zero or more times. After EOF error is returned, no more responses
will be produced.
*/
FOUNDATION_EXPORT void LndmobileOpenChannel(NSData* _Nullable msg, id<LndmobileRecvStream> _Nullable rStream);
/**
* OpenChannelSync is a synchronous version of the OpenChannel RPC call. This
call is meant to be consumed by clients to the REST proxy. As with all
other sync calls, all byte slices are intended to be populated as hex
encoded strings.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileOpenChannelSync(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* PendingChannels returns a list of all the channels that are currently
considered "pending". A channel is pending if it has finished the funding
workflow and is waiting for confirmations for the funding txn, or is in the
process of closure, either initiated cooperatively or non-cooperatively.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobilePendingChannels(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* QueryRoutes attempts to query the daemon's Channel Router for a possible
route to a target destination capable of carrying a specific amount of
satoshis. The returned route contains the full details required to craft and
send an HTLC, also including the necessary information that should be
present within the Sphinx packet encapsulated within the HTLC.
When using REST, the `dest_custom_records` map type can be set by appending
`&dest_custom_records[<record_number>]=<record_data_base64_url_encoded>`
to the URL. Unfortunately this map type doesn't appear in the REST API
documentation because of a bug in the grpc-gateway library.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileQueryRoutes(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* QueryScores queries all available autopilot heuristics, in addition to any
active combination of these heruristics, for the scores they would give to
the given nodes.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileQueryScores(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* RestoreChannelBackups accepts a set of singular channel backups, or a
single encrypted multi-chan backup and attempts to recover any funds
remaining within the channel. If we are able to unpack the backup, then the
new channel will be shown under listchannels, as well as pending channels.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileRestoreChannelBackups(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* SendCoins executes a request to send coins to a particular address. Unlike
SendMany, this RPC call only allows creating a single output at a time. If
neither target_conf, or sat_per_byte are set, then the internal wallet will
consult its fee model to determine a fee for the default confirmation
target.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileSendCoins(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* SendMany handles a request for a transaction that creates multiple specified
outputs in parallel. If neither target_conf, or sat_per_byte are set, then
the internal wallet will consult its fee model to determine a fee for the
default confirmation target.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileSendMany(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* NOTE: This method produces a stream of responses, and the receive stream can
be called zero or more times. After EOF error is returned, no more responses
will be produced. The send stream can accept zero or more requests before it
is closed.
*/
FOUNDATION_EXPORT id<LndmobileSendStream> _Nullable LndmobileSendPayment(id<LndmobileRecvStream> _Nullable rStream, NSError* _Nullable* _Nullable error);
/**
* SendPaymentSync is the synchronous non-streaming version of SendPayment.
This RPC is intended to be consumed by clients of the REST proxy.
Additionally, this RPC expects the destination's public key and the payment
hash (if any) to be encoded as hex strings.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileSendPaymentSync(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* NOTE: This method produces a stream of responses, and the receive stream can
be called zero or more times. After EOF error is returned, no more responses
will be produced. The send stream can accept zero or more requests before it
is closed.
*/
FOUNDATION_EXPORT id<LndmobileSendStream> _Nullable LndmobileSendToRoute(id<LndmobileRecvStream> _Nullable rStream, NSError* _Nullable* _Nullable error);
/**
* SendToRouteSync is a synchronous version of SendToRoute. It Will block
until the payment either fails or succeeds.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileSendToRouteSync(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* SetScores attempts to set the scores used by the running autopilot agent,
if the external scoring heuristic is enabled.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileSetScores(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* SignMessage signs a message with this node's private key. The returned
signature string is `zbase32` encoded and pubkey recoverable, meaning that
only the message digest and signature are needed for verification.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileSignMessage(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* Start starts lnd in a new goroutine.
extraArgs can be used to pass command line arguments to lnd that will
override what is found in the config file. Example:
extraArgs = "--bitcoin.testnet --lnddir=\"/tmp/folder name/\" --profile=5050"
The unlockerReady callback is called when the WalletUnlocker service is
ready, and rpcReady is called after the wallet has been unlocked and lnd is
ready to accept RPC calls.
NOTE: On mobile platforms the '--lnddir` argument should be set to the
current app directory in order to ensure lnd has the permissions needed to
write to it.
*/
FOUNDATION_EXPORT void LndmobileStart(NSString* _Nullable extraArgs, id<LndmobileCallback> _Nullable unlockerReady, id<LndmobileCallback> _Nullable rpcReady);
/**
* Status returns whether the daemon's autopilot agent is active.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileStatus(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* StopDaemon will send a shutdown request to the interrupt handler, triggering
a graceful shutdown of the daemon.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileStopDaemon(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* SubscribeChannelBackups allows a client to sub-subscribe to the most up to
date information concerning the state of all channel backups. Each time a
new channel is added, we return the new set of channels, along with a
multi-chan backup containing the backup info for all channels. Each time a
channel is closed, we send a new update, which contains new new chan back
ups, but the updated set of encrypted multi-chan backups with the closed
channel(s) removed.
NOTE: This method produces a stream of responses, and the receive stream can
be called zero or more times. After EOF error is returned, no more responses
will be produced.
*/
FOUNDATION_EXPORT void LndmobileSubscribeChannelBackups(NSData* _Nullable msg, id<LndmobileRecvStream> _Nullable rStream);
/**
* SubscribeChannelEvents creates a uni-directional stream from the server to
the client in which any updates relevant to the state of the channels are
sent over. Events include new active channels, inactive channels, and closed
channels.
NOTE: This method produces a stream of responses, and the receive stream can
be called zero or more times. After EOF error is returned, no more responses
will be produced.
*/
FOUNDATION_EXPORT void LndmobileSubscribeChannelEvents(NSData* _Nullable msg, id<LndmobileRecvStream> _Nullable rStream);
/**
* SubscribeChannelGraph launches a streaming RPC that allows the caller to
receive notifications upon any changes to the channel graph topology from
the point of view of the responding node. Events notified include: new
nodes coming online, nodes updating their authenticated attributes, new
channels being advertised, updates in the routing policy for a directional
channel edge, and when channels are closed on-chain.
NOTE: This method produces a stream of responses, and the receive stream can
be called zero or more times. After EOF error is returned, no more responses
will be produced.
*/
FOUNDATION_EXPORT void LndmobileSubscribeChannelGraph(NSData* _Nullable msg, id<LndmobileRecvStream> _Nullable rStream);
/**
* SubscribeInvoices returns a uni-directional stream (server -> client) for
notifying the client of newly added/settled invoices. The caller can
optionally specify the add_index and/or the settle_index. If the add_index
is specified, then we'll first start by sending add invoice events for all
invoices with an add_index greater than the specified value. If the
settle_index is specified, the next, we'll send out all settle events for
invoices with a settle_index greater than the specified value. One or both
of these fields can be set. If no fields are set, then we'll only send out
the latest add/settle events.
NOTE: This method produces a stream of responses, and the receive stream can
be called zero or more times. After EOF error is returned, no more responses
will be produced.
*/
FOUNDATION_EXPORT void LndmobileSubscribeInvoices(NSData* _Nullable msg, id<LndmobileRecvStream> _Nullable rStream);
/**
* SubscribePeerEvents creates a uni-directional stream from the server to
the client in which any events relevant to the state of peers are sent
over. Events include peers going online and offline.
NOTE: This method produces a stream of responses, and the receive stream can
be called zero or more times. After EOF error is returned, no more responses
will be produced.
*/
FOUNDATION_EXPORT void LndmobileSubscribePeerEvents(NSData* _Nullable msg, id<LndmobileRecvStream> _Nullable rStream);
/**
* SubscribeTransactions creates a uni-directional stream from the server to
the client in which any newly discovered transactions relevant to the
wallet are sent over.
NOTE: This method produces a stream of responses, and the receive stream can
be called zero or more times. After EOF error is returned, no more responses
will be produced.
*/
FOUNDATION_EXPORT void LndmobileSubscribeTransactions(NSData* _Nullable msg, id<LndmobileRecvStream> _Nullable rStream);
/**
* UnlockWallet is used at startup of lnd to provide a password to unlock
the wallet database.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileUnlockWallet(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* UpdateChannelPolicy allows the caller to update the fee schedule and
channel policies for all channels globally, or a particular channel.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileUpdateChannelPolicy(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* VerifyChanBackup allows a caller to verify the integrity of a channel backup
snapshot. This method will accept either a packed Single or a packed Multi.
Specifying both will result in an error.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileVerifyChanBackup(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* VerifyMessage verifies a signature over a msg. The signature must be
zbase32 encoded and signed by an active node in the resident node's
channel database. In addition to returning the validity of the signature,
VerifyMessage also returns the recovered pubkey from the signature.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileVerifyMessage(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
/**
* WalletBalance returns total unspent outputs(confirmed and unconfirmed), all
confirmed unspent outputs and all unconfirmed unspent outputs under control
of the wallet.
NOTE: This method produces a single result or error, and the callback will
be called only once.
*/
FOUNDATION_EXPORT void LndmobileWalletBalance(NSData* _Nullable msg, id<LndmobileCallback> _Nullable callback);
@class LndmobileCallback;
@class LndmobileRecvStream;
@class LndmobileSendStream;
/**
* Callback is an interface that is passed in by callers of the library, and
specifies where the responses should be delivered.
*/
@interface LndmobileCallback : NSObject <goSeqRefInterface, LndmobileCallback> {
}
@property(strong, readonly) _Nonnull id _ref;
- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
/**
* OnError is called by the library if any error is encountered during
the execution of the RPC call.
*/
- (void)onError:(NSError* _Nullable)p0;
/**
* OnResponse is called by the library when a response from the daemon
for the associated RPC call is received. The reponse is a serialized
protobuf for the expected response, and must be deserialized by the
caller.
*/
- (void)onResponse:(NSData* _Nullable)p0;
@end
/**
* RecvStream is an interface that is passed in by callers of the library, and
specifies where the streaming responses should be delivered.
*/
@interface LndmobileRecvStream : NSObject <goSeqRefInterface, LndmobileRecvStream> {
}
@property(strong, readonly) _Nonnull id _ref;
- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
/**
* OnError is called by the library if any error is encountered during
the execution of the RPC call, or if the response stream ends. No
more stream responses will be received after this.
*/
- (void)onError:(NSError* _Nullable)p0;
/**
* OnResponse is called by the library when a new stream response from
the daemon for the associated RPC call is available. The reponse is
a serialized protobuf for the expected response, and must be
deserialized by the caller.
*/
- (void)onResponse:(NSData* _Nullable)p0;
@end
/**
* SendStream is an interface that the caller of the library can use to send
requests to the server during the execution of a bidirectional streaming RPC
call, or stop the stream.
*/
@interface LndmobileSendStream : NSObject <goSeqRefInterface, LndmobileSendStream> {
}
@property(strong, readonly) _Nonnull id _ref;
- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
/**
* Send sends the serialized protobuf request to the server.
*/
- (BOOL)send:(NSData* _Nullable)p0 error:(NSError* _Nullable* _Nullable)error;
/**
* Stop closes the bidirecrional connection.
*/
- (BOOL)stop:(NSError* _Nullable* _Nullable)error;
@end
#endif

View File

@ -0,0 +1,29 @@
// Objective-C API for talking to Go package.
// gobind -lang=objc
//
// File is generated by gobind. Do not edit.
#ifndef __Universe_H__
#define __Universe_H__
@import Foundation;
#include "ref.h"
@protocol Universeerror;
@class Universeerror;
@protocol Universeerror <NSObject>
- (NSString* _Nonnull)error;
@end
@class Universeerror;
@interface Universeerror : NSError <goSeqRefInterface, Universeerror> {
}
@property(strong, readonly) _Nonnull id _ref;
- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
- (NSString* _Nonnull)error;
@end
#endif

View File

@ -0,0 +1,35 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#ifndef __GO_REF_HDR__
#define __GO_REF_HDR__
#include <Foundation/Foundation.h>
// GoSeqRef is an object tagged with an integer for passing back and
// forth across the language boundary. A GoSeqRef may represent either
// an instance of a Go object, or an Objective-C object passed to Go.
// The explicit allocation of a GoSeqRef is used to pin a Go object
// when it is passed to Objective-C. The Go seq package maintains a
// reference to the Go object in a map keyed by the refnum along with
// a reference count. When the reference count reaches zero, the Go
// seq package will clear the corresponding entry in the map.
@interface GoSeqRef : NSObject {
}
@property(readonly) int32_t refnum;
@property(strong) id obj; // NULL when representing a Go object.
// new GoSeqRef object to proxy a Go object. The refnum must be
// provided from Go side.
- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj;
- (int32_t)incNum;
@end
@protocol goSeqRefInterface
-(GoSeqRef*) _ref;
@end
#endif

Binary file not shown.

View File

@ -0,0 +1,8 @@
framework module "Lndmobile" {
header "ref.h"
header "Lndmobile.objc.h"
header "Universe.objc.h"
header "Lndmobile.h"
export *
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>

View File

@ -0,0 +1 @@
A

20
Podfile Normal file
View File

@ -0,0 +1,20 @@
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'wallet' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for wallet
pod 'SwiftProtobuf', '~> 1.0'
pod 'QR-Code-Scanner-iOS'
target 'walletTests' do
inherit! :search_paths
# Pods for testing
end
target 'walletUITests' do
# Pods for testing
end
end

20
Podfile.lock Normal file
View File

@ -0,0 +1,20 @@
PODS:
- QR-Code-Scanner-iOS (1.0.0)
- SwiftProtobuf (1.12.0)
DEPENDENCIES:
- QR-Code-Scanner-iOS
- SwiftProtobuf (~> 1.0)
SPEC REPOS:
trunk:
- QR-Code-Scanner-iOS
- SwiftProtobuf
SPEC CHECKSUMS:
QR-Code-Scanner-iOS: 6633d5157a50467d66ab357af2432b576c702e5e
SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699
PODFILE CHECKSUM: d7310fa0d2b536b55397de242eb9357089f5f87c
COCOAPODS: 1.11.3

20
Pods/Manifest.lock generated Normal file
View File

@ -0,0 +1,20 @@
PODS:
- QR-Code-Scanner-iOS (1.0.0)
- SwiftProtobuf (1.12.0)
DEPENDENCIES:
- QR-Code-Scanner-iOS
- SwiftProtobuf (~> 1.0)
SPEC REPOS:
trunk:
- QR-Code-Scanner-iOS
- SwiftProtobuf
SPEC CHECKSUMS:
QR-Code-Scanner-iOS: 6633d5157a50467d66ab357af2432b576c702e5e
SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699
PODFILE CHECKSUM: d7310fa0d2b536b55397de242eb9357089f5f87c
COCOAPODS: 1.11.3

1523
Pods/Pods.xcodeproj/project.pbxproj generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "693D2B0034E6B7BD37FCF5DEA7D2B0F9"
BuildableName = "Pods_wallet_walletUITests.framework"
BlueprintName = "Pods-wallet-walletUITests"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4179979D0E7E44B4D103FAD5DF24E7E8"
BuildableName = "Pods_wallet.framework"
BlueprintName = "Pods-wallet"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "E41B0A6CFA9B0917167875ECF1B1A50D"
BuildableName = "Pods_walletTests.framework"
BlueprintName = "Pods-walletTests"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "03F8264CAE2EC0684FD64871C2FF793E"
BuildableName = "QRCodeScanner.framework"
BlueprintName = "QR-Code-Scanner-iOS"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1240"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A5F702E0DA383BC1479572581615A916"
BuildableName = "SwiftProtobuf.framework"
BlueprintName = "SwiftProtobuf"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>Pods-wallet-walletUITests.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>Pods-wallet.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>Pods-walletTests.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>2</integer>
</dict>
<key>QR-Code-Scanner-iOS.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>3</integer>
</dict>
<key>SwiftProtobuf.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>4</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict/>
</dict>
</plist>

19
Pods/QR-Code-Scanner-iOS/LICENSE generated Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2020 Applied Recognition, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="y2r-2W-Kfy">
<device id="retina4_0" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16086"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Scan Code-->
<scene sceneID="I2H-Ea-9of">
<objects>
<viewController storyboardIdentifier="scanCode" id="y2r-2W-Kfy" customClass="QRCodeScanViewController" customModule="QR_Code_Scanner" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="7Dr-tT-ym7">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="dHG-WP-6So">
<rect key="frame" x="0.0" y="0.0" width="320" height="284"/>
<color key="backgroundColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Please scan the QR code on your computer's screen." textAlignment="center" lineBreakMode="wordWrap" numberOfLines="4" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aFZ-zX-6H0">
<rect key="frame" x="24" y="444" width="272" height="100"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="100" id="dau-SG-XQW"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="256" id="m0W-NA-pcB"/>
<constraint firstAttribute="height" constant="100" id="sUP-Zr-vJJ"/>
<constraint firstAttribute="width" constant="272" id="wss-GD-Qsm"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="1000" image="qr_code" translatesAutoresizingMaskIntoConstraints="NO" id="idD-yC-9NX">
<rect key="frame" x="96" y="316" width="128" height="128"/>
<constraints>
<constraint firstAttribute="height" constant="128" id="3zz-o7-Irj"/>
<constraint firstAttribute="width" constant="128" id="inb-Nw-PSU"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="HcW-ma-4Y9" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="aFZ-zX-6H0" secondAttribute="bottom" constant="24" id="3Gx-Mz-RjT"/>
<constraint firstItem="aFZ-zX-6H0" firstAttribute="top" secondItem="idD-yC-9NX" secondAttribute="bottom" id="4d2-CW-bq6"/>
<constraint firstItem="dHG-WP-6So" firstAttribute="height" secondItem="7Dr-tT-ym7" secondAttribute="height" multiplier="0.5" id="6D2-cL-pfV"/>
<constraint firstItem="aFZ-zX-6H0" firstAttribute="centerY" secondItem="HcW-ma-4Y9" secondAttribute="centerY" priority="999" constant="200" id="7vv-ud-cQ4"/>
<constraint firstItem="dHG-WP-6So" firstAttribute="leading" secondItem="HcW-ma-4Y9" secondAttribute="leading" id="Cgk-Md-0az"/>
<constraint firstItem="idD-yC-9NX" firstAttribute="centerX" secondItem="7Dr-tT-ym7" secondAttribute="centerX" id="KHv-xR-1AC"/>
<constraint firstItem="dHG-WP-6So" firstAttribute="top" secondItem="7Dr-tT-ym7" secondAttribute="top" id="ZH3-TS-kWK"/>
<constraint firstItem="dHG-WP-6So" firstAttribute="trailing" secondItem="HcW-ma-4Y9" secondAttribute="trailing" id="cy7-ek-IRs"/>
<constraint firstItem="aFZ-zX-6H0" firstAttribute="centerX" secondItem="7Dr-tT-ym7" secondAttribute="centerX" id="dDa-0M-NuA"/>
</constraints>
<viewLayoutGuide key="safeArea" id="HcW-ma-4Y9"/>
</view>
<navigationItem key="navigationItem" title="Scan Code" id="d0Z-d3-Eu5"/>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<connections>
<outlet property="cameraView" destination="dHG-WP-6So" id="UUo-WY-Ziq"/>
<outlet property="promptLabel" destination="aFZ-zX-6H0" id="Wp8-wK-c3f"/>
<segue destination="ksr-ra-by9" kind="show" identifier="denied" id="hci-Jh-Lpx"/>
<segue destination="JmV-9f-Gyt" kind="show" identifier="restricted" id="N0x-0E-lxh"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="lxj-g1-dsq" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="886.875" y="27.464788732394368"/>
</scene>
<!--Camera Access Denied View Controller-->
<scene sceneID="gyq-DK-avj">
<objects>
<viewController id="ksr-ra-by9" customClass="CameraAccessDeniedViewController" customModule="QR_Code_Scanner" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="anx-7h-CQ8">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Camera access denied. Please go to settings and enable camera." textAlignment="center" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ivo-nD-I5y">
<rect key="frame" x="24" y="444" width="272" height="100"/>
<constraints>
<constraint firstAttribute="width" constant="272" id="R3x-dE-PeA"/>
<constraint firstAttribute="height" constant="100" id="koy-m2-Odt"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RIk-vx-R8e">
<rect key="frame" x="81.5" y="276" width="157" height="60"/>
<color key="backgroundColor" red="0.21176470589999999" green="0.68627450980000004" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="60" id="UgE-k4-NXY"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="24"/>
<inset key="contentEdgeInsets" minX="20" minY="0.0" maxX="20" maxY="0.0"/>
<state key="normal" title="SETTINGS">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
<integer key="value" value="20"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="openSettings" destination="ksr-ra-by9" eventType="touchUpInside" id="b3c-NX-isc"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="RIk-vx-R8e" firstAttribute="centerY" secondItem="Nn2-2b-I7a" secondAttribute="centerY" id="6xx-R6-0l2"/>
<constraint firstItem="ivo-nD-I5y" firstAttribute="centerX" secondItem="anx-7h-CQ8" secondAttribute="centerX" id="91s-0E-NIN"/>
<constraint firstItem="ivo-nD-I5y" firstAttribute="centerY" secondItem="Nn2-2b-I7a" secondAttribute="centerY" priority="999" constant="200" id="JCs-2s-LNF"/>
<constraint firstItem="RIk-vx-R8e" firstAttribute="centerX" secondItem="Nn2-2b-I7a" secondAttribute="centerX" id="JJQ-e4-tMz"/>
<constraint firstItem="Nn2-2b-I7a" firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="ivo-nD-I5y" secondAttribute="bottom" constant="24" id="QdZ-8V-aTQ"/>
</constraints>
<viewLayoutGuide key="safeArea" id="Nn2-2b-I7a"/>
</view>
<connections>
<outlet property="label" destination="ivo-nD-I5y" id="oS7-BJ-FpM"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="DcX-Tj-tVf" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1748" y="-128"/>
</scene>
<!--View Controller-->
<scene sceneID="2JM-NP-OiX">
<objects>
<viewController id="JmV-9f-Gyt" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="LIk-Xe-Kkl">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Camera access on your device is restricted. Please contact the system administrator." textAlignment="center" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NV9-3Y-dJa">
<rect key="frame" x="16" y="253.5" width="288" height="61"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="NV9-3Y-dJa" firstAttribute="centerY" secondItem="LIk-Xe-Kkl" secondAttribute="centerY" id="9MO-I6-xou"/>
<constraint firstItem="NV9-3Y-dJa" firstAttribute="trailing" secondItem="LIk-Xe-Kkl" secondAttribute="trailingMargin" id="MeX-Ws-kZV"/>
<constraint firstItem="NV9-3Y-dJa" firstAttribute="leading" secondItem="LIk-Xe-Kkl" secondAttribute="leadingMargin" id="gQu-7O-TO6"/>
</constraints>
<viewLayoutGuide key="safeArea" id="jdU-SE-06w"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="LYY-O2-PHk" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1748" y="598"/>
</scene>
</scenes>
<resources>
<image name="qr_code" width="272" height="272"/>
</resources>
</document>

View File

@ -0,0 +1,27 @@
//
// CameraAccessDeniedViewController.swift
//
// Created by Jakub Dolejs on 28/03/2018.
// Copyright © 2018 Applied Recognition Inc. All rights reserved.
//
import UIKit
class CameraAccessDeniedViewController: UIViewController {
@IBOutlet var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
if let appName = Bundle.main.infoDictionary?[kCFBundleNameKey as String] as? String {
label.text = String(format: "Camera access denied. Please go to settings and enable camera for %@.", appName)
}
}
@IBAction func openSettings() {
if let settingsURL = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
}
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "qr_code.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "qr_code@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "qr_code@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

View File

@ -0,0 +1,186 @@
//
// QRCodeScanViewController.swift
// BFL Authenticator
//
// Created by Jakub Dolejs on 28/03/2018.
// Copyright © 2018 Applied Recognition Inc. All rights reserved.
//
import UIKit
import AVFoundation
public class QRCodeScanViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
public weak var delegate: QRCodeScanViewControllerDelegate?
public var prompt: String?
public static func create() -> QRCodeScanViewController {
let storyboard = UIStoryboard(name: "QRCode", bundle: Bundle(for: QRCodeScanViewController.self))
return storyboard.instantiateInitialViewController() as! QRCodeScanViewController
}
private override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
@IBOutlet var cameraView: UIView!
@IBOutlet var promptLabel: UILabel!
var captureSession: AVCaptureSession!
lazy var barcodeScanQueue: DispatchQueue = {
let queue = DispatchQueue.init(label: "com.appliedrec.qrcodescan")
return queue
}()
var avCaptureVideoOrientation: AVCaptureVideoOrientation {
switch UIApplication.shared.statusBarOrientation {
case .portraitUpsideDown:
return AVCaptureVideoOrientation.portraitUpsideDown
case .landscapeRight:
return AVCaptureVideoOrientation.landscapeRight
case .landscapeLeft:
return AVCaptureVideoOrientation.landscapeLeft
default:
return AVCaptureVideoOrientation.portrait
}
}
public override func viewDidLoad() {
super.viewDidLoad()
if let prompt = self.prompt {
self.promptLabel.text = prompt
}
}
public override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
startCamera()
}
func startCamera() {
let status = AVCaptureDevice.authorizationStatus(for: .video)
switch status {
case .authorized:
self.startScan()
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { granted in
if granted {
self.startScan()
} else {
self.showCameraAccessDenied()
}
}
case .denied:
self.showCameraAccessDenied()
case .restricted:
self.showCameraAccessRestricted()
@unknown default:
fatalError()
}
}
public override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.stopCamera()
}
@IBAction func restartQRCodeScan(_ segue: UIStoryboardSegue) {
}
func showCameraAccessDenied() {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "denied", sender: nil)
}
}
func showCameraAccessRestricted() {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "restricted", sender: nil)
}
}
private func startScan() {
self.barcodeScanQueue.async {
self.captureSession = AVCaptureSession()
guard let camera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else {
return
}
guard let videoInput = try? AVCaptureDeviceInput(device: camera) else {
return
}
do {
try camera.lockForConfiguration()
if camera.isAutoFocusRangeRestrictionSupported {
camera.autoFocusRangeRestriction = .near
}
if camera.isFocusModeSupported(AVCaptureDevice.FocusMode.continuousAutoFocus) {
camera.focusMode = .continuousAutoFocus
} else if camera.isFocusModeSupported(AVCaptureDevice.FocusMode.autoFocus) {
camera.focusMode = .autoFocus
}
if camera.isFocusPointOfInterestSupported {
camera.focusPointOfInterest = CGPoint(x: 0.5, y: 0.5)
}
camera.unlockForConfiguration()
} catch {
}
if self.captureSession.canAddInput(videoInput) {
self.captureSession.addInput(videoInput)
}
let barcodeOutput = AVCaptureMetadataOutput()
barcodeOutput.setMetadataObjectsDelegate(self, queue: self.barcodeScanQueue)
if self.captureSession.canAddOutput(barcodeOutput) {
self.captureSession.addOutput(barcodeOutput)
if barcodeOutput.availableMetadataObjectTypes.contains(where: { (val) -> Bool in return val == AVMetadataObject.ObjectType.qr }) {
barcodeOutput.metadataObjectTypes = [.qr]
}
}
self.captureSession.startRunning()
DispatchQueue.main.async {
let previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
previewLayer.frame = self.cameraView.bounds
if previewLayer.connection != nil && previewLayer.connection!.isVideoOrientationSupported {
previewLayer.connection!.videoOrientation = self.avCaptureVideoOrientation
}
self.cameraView.layer.masksToBounds = true
while let sub = self.cameraView.layer.sublayers?.first {
sub.removeFromSuperlayer()
}
self.cameraView.layer.addSublayer(previewLayer)
}
}
}
func stopCamera() {
self.barcodeScanQueue.async {
if self.captureSession != nil {
self.captureSession.stopRunning()
self.captureSession = nil
}
}
}
public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
if let codeValue = (metadataObjects.first(where: { $0 is AVMetadataMachineReadableCodeObject && $0.type == AVMetadataObject.ObjectType.qr }) as? AVMetadataMachineReadableCodeObject)?.stringValue {
self.stopCamera()
DispatchQueue.main.async {
self.delegate?.qrCodeScanViewController(self, didScanQRCode: codeValue)
self.delegate = nil
}
}
}
}
public protocol QRCodeScanViewControllerDelegate: class {
func qrCodeScanViewController(_ viewController: QRCodeScanViewController, didScanQRCode value: String)
}

54
Pods/QR-Code-Scanner-iOS/README.md generated Normal file
View File

@ -0,0 +1,54 @@
# QR Code Scanner for iOS
Scans QR codes using the device's camera and returns a string value.
## Installation
1. Install [CocoaPods](https://cocoapods.org).
2. Add the following dependency in your **Podspec** file:
~~~ruby
pod 'QR-Code-Scanner-iOS', '~> 1.0'
~~~
3. Run `pod install`.
## Usage
~~~swift
import UIKit
import QRCodeScanner
class MyViewController: UIViewController, QRCodeScanViewControllerDelegate {
/// Start the QR code scan
func scanQRCode() {
// Create an instance of QRCodeScanViewController
let viewController = QRCodeScanViewController.create()
// Set itself as delegate
viewController.delegate = self
// Present the view controller
self.present(viewController, animated: true)
}
// MARK: QRCodeScanViewControllerDelegate
/// Called when the camera scans a QR code
/// - Parameters:
/// - viewController: View controller that scanned the QR code
/// - value: String encoded in the QR code
func qrCodeScanViewController(_ viewController: QRCodeScanViewController, didScanQRCode value: String) {
// Dismiss the view controller
viewController.dismiss(animated: true) {
// Show an alert with the scanned value
let alert = UIAlertController(title: "Scanned value", message: value, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true)
}
}
}
~~~

211
Pods/SwiftProtobuf/LICENSE.txt generated Normal file
View File

@ -0,0 +1,211 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
## Runtime Library Exception to the Apache 2.0 License: ##
As an exception, if you use this Software to compile your source code and
portions of this Software are embedded into the binary product as a result,
you may redistribute such product without providing attribution as would
otherwise be required by Sections 4(a), 4(b) and 4(d) of the License.

303
Pods/SwiftProtobuf/README.md generated Normal file
View File

@ -0,0 +1,303 @@
<img src="https://swift.org/assets/images/swift.svg" alt="Swift logo" height="70" >
# Swift Protobuf
**Welcome to Swift Protobuf!**
[Apple's Swift programming language](https://swift.org/) is a perfect
complement to [Google's Protocol
Buffer](https://developers.google.com/protocol-buffers/) ("protobuf") serialization
technology.
They both emphasize high performance and programmer safety.
This project provides both the command-line program that adds Swift
code generation to Google's `protoc` and the runtime library that is
necessary for using the generated code.
After using the protoc plugin to generate Swift code from your .proto
files, you will need to add this library to your project.
[![Build and Test](https://github.com/apple/swift-protobuf/workflows/Build%20and%20Test/badge.svg)](https://github.com/apple/swift-protobuf/actions?query=workflow%3A%22Build+and+Test%22)
[![Check Upstream Protos](https://github.com/apple/swift-protobuf/workflows/Check%20Upstream%20Proto%20Files/badge.svg)](https://github.com/apple/swift-protobuf/actions?query=workflow%3A%22Check+Upstream+Proto+Files%22)
[![Run Conformance Tests](https://github.com/apple/swift-protobuf/workflows/Run%20Conformance%20Tests/badge.svg)](https://github.com/apple/swift-protobuf/actions?query=workflow%3A%22Run+Conformance+Tests%22)
# Features of SwiftProtobuf
SwiftProtobuf offers many advantages over alternative serialization
systems:
* Safety: The protobuf code-generation system avoids the
errors that are common with hand-built serialization code.
* Correctness: SwiftProtobuf passes both its own extensive
test suite and Google's full conformance test for protobuf
correctness.
* Schema-driven: Defining your data structures in a separate
`.proto` schema file clearly documents your communications
conventions.
* Idiomatic: SwiftProtobuf takes full advantage of the Swift language.
In particular, all generated types provide full Swift copy-on-write
value semantics.
* Efficient binary serialization: The `.serializedData()`
method returns a `Data` with a compact binary form of your data.
You can deserialize the data using the `init(serializedData:)`
initializer.
* Standard JSON serialization: The `.jsonUTF8Data()` method returns a JSON
form of your data that can be parsed with the `init(jsonUTF8Data:)`
initializer.
* Hashable, Equatable: The generated struct can be put into a
`Set<>` or `Dictionary<>`.
* Performant: The binary and JSON serializers have been
extensively optimized.
* Extensible: You can add your own Swift extensions to any
of the generated types.
Best of all, you can take the same `.proto` file and generate
Java, C++, Python, or Objective-C for use on other platforms. The
generated code for those languages will use the exact same
serialization and deserialization conventions as SwiftProtobuf, making
it easy to exchange serialized data in binary or JSON forms, with no
additional effort on your part.
# Documentation
More information is available in the associated documentation:
* [Google's protobuf documentation](https://developers.google.com/protocol-buffers/)
provides general information about protocol buffers, the protoc compiler,
and how to use protocol buffers with C++, Java, and other languages.
* [PLUGIN.md](Documentation/PLUGIN.md) documents the `protoc-gen-swift`
plugin that adds Swift support to the `protoc` program
* [API.md](Documentation/API.md) documents how to use the generated code.
This is recommended reading for anyone using SwiftProtobuf in their
project.
* [cocoadocs.org](http://cocoadocs.org/docsets/SwiftProtobuf/) has the generated
API documentation
* [INTERNALS.md](Documentation/INTERNALS.md) documents the internal structure
of the generated code and the library. This
should only be needed by folks interested in working on SwiftProtobuf
itself.
* [STYLE_GUIDELINES.md](Documentation/STYLE_GUIDELINES.md) documents the style
guidelines we have adopted in our codebase if you are interested in
contributing
# Getting Started
If you've worked with Protocol Buffers before, adding Swift support is very
simple: you just need to build the `protoc-gen-swift` program and copy it into
your PATH.
The `protoc` program will find and use it automatically, allowing you
to build Swift sources for your proto files.
You will also, of course, need to add the SwiftProtobuf runtime library to
your project as explained below.
## System Requirements
To use Swift with Protocol buffers, you'll need:
* A Swift 4.2 or later compiler (Xcode 10.0 or later). Support is included
for the Swift Package Manager; or using the included Xcode project. The Swift
protobuf project is being developed and tested against the latest release
version of Swift available from [Swift.org](https://swift.org)
* Google's protoc compiler. The Swift protoc plugin is being actively
developed and tested against the latest protobuf sources.
The SwiftProtobuf tests need a version of protoc which supports the
`swift_prefix` option (introduced in protoc 3.2.0).
It may work with earlier versions of protoc.
You can get recent versions from
[Google's github repository](https://github.com/protocolbuffers/protobuf).
## Building and Installing the Code Generator Plugin
To translate `.proto` files into Swift, you will need both Google's
protoc compiler and the SwiftProtobuf code generator plugin.
Building the plugin should be simple on any supported Swift platform:
```
$ git clone https://github.com/apple/swift-protobuf.git
$ cd swift-protobuf
```
Pick what released version of SwiftProtobuf you are going to use. You can get
a list of tags with:
```
$ git tag -l
```
Once you pick the version you will use, set your local state to match, and
build the protoc plugin:
```
$ git checkout tags/[tag_name]
$ swift build -c release
```
This will create a binary called `protoc-gen-swift` in the `.build/release`
directory.
To install, just copy this one executable into a directory that is
part of your `PATH` environment variable.
NOTE: The Swift runtime support is now included with macOS. If you are
using old Xcode versions or are on older system versions, you might need
to use also use `--static-swift-stdlib` with `swift build`.
### Alternatively install via Homebrew
If you prefer using [Homebrew](https://brew.sh):
```
$ brew install swift-protobuf
```
This will install `protoc` compiler and Swift code generator plugin.
## Converting .proto files into Swift
To generate Swift output for your .proto files, you run the `protoc` command as
usual, using the `--swift_out=<directory>` option:
```
$ protoc --swift_out=. my.proto
```
The `protoc` program will automatically look for `protoc-gen-swift` in your
`PATH` and use it.
Each `.proto` input file will get translated to a corresponding `.pb.swift`
file in the output directory.
More information about building and using `protoc-gen-swift` can be found
in the [detailed Plugin documentation](Documentation/PLUGIN.md).
## Adding the SwiftProtobuf library to your project...
To use the generated code, you need to include the `SwiftProtobuf` library
module in your project. How you do this will vary depending on how
you're building your project. Note that in all cases, we strongly recommend
that you use the version of the SwiftProtobuf library that corresponds to
the version of `protoc-gen-swift` you used to generate the code.
### ...using `swift build`
After copying the `.pb.swift` files into your project, you will need to add the
[SwiftProtobuf library](https://github.com/apple/swift-protobuf) to your
project to support the generated code.
If you are using the Swift Package Manager, add a dependency to your
`Package.swift` file and import the `SwiftProtobuf` library into the desired
targets. Adjust the `"1.6.0"` here to match the `[tag_name]` you used to build
the plugin above:
```swift
dependencies: [
.package(name: "SwiftProtobuf", url: "https://github.com/apple/swift-protobuf.git", from: "1.6.0"),
],
targets: [
.target(name: "MyTarget", dependencies: ["SwiftProtobuf"]),
]
```
### ...using Xcode
If you are using Xcode, then you should:
* Add the `.pb.swift` source files generated from your protos directly to your
project
* Add the appropriate `SwiftProtobuf_<platform>` target from the Xcode project
in this package to your project.
### ...using CocoaPods
If you're using CocoaPods, add this to your `Podfile` adjusting the `:tag` to
match the `[tag_name]` you used to build the plugin above:
```ruby
pod 'SwiftProtobuf', '~> 1.0'
```
And run `pod install`.
NOTE: CocoaPods 1.7 or newer is required.
### ...using Carthage
If you're using Carthage, add this to your `Cartfile` but adjust the tag to match the `[tag_name]` you used to build the plugin above:
```ruby
github "apple/swift-protobuf" ~> 1.0
```
Run `carthage update` and drag `SwiftProtobuf.framework` into your Xcode.project.
# Quick Start
Once you have installed the code generator, used it to
generate Swift code from your `.proto` file, and
added the SwiftProtobuf library to your project, you can
just use the generated types as you would any other Swift
struct.
For example, you might start with the following very simple
proto file:
```protobuf
syntax = "proto3";
message BookInfo {
int64 id = 1;
string title = 2;
string author = 3;
}
```
Then generate Swift code using:
```
$ protoc --swift_out=. DataModel.proto
```
The generated code will expose a Swift property for
each of the proto fields as well as a selection
of serialization and deserialization capabilities:
```swift
// Create a BookInfo object and populate it:
var info = BookInfo()
info.id = 1734
info.title = "Really Interesting Book"
info.author = "Jane Smith"
// As above, but generating a read-only value:
let info2 = BookInfo.with {
$0.id = 1735
$0.title = "Even More Interesting"
$0.author = "Jane Q. Smith"
}
// Serialize to binary protobuf format:
let binaryData: Data = try info.serializedData()
// Deserialize a received Data object from `binaryData`
let decodedInfo = try BookInfo(serializedData: binaryData)
// Serialize to JSON format as a Data object
let jsonData: Data = try info.jsonUTF8Data()
// Deserialize from JSON format from `jsonData`
let receivedFromJSON = try BookInfo(jsonUTF8Data: jsonData)
```
You can find more information in the detailed
[API Documentation](Documentation/API.md).
## Report any issues
If you run into problems, please send us a detailed report.
At a minimum, please include:
* The specific operating system and version (for example, "macOS 10.12.1" or
"Ubuntu 16.10")
* The version of Swift you have installed (from `swift --version`)
* The version of the protoc compiler you are working with from
`protoc --version`
* The specific version of this source code (you can use `git log -1` to get the
latest commit ID)
* Any local changes you may have

View File

@ -0,0 +1,476 @@
// Sources/SwiftProtobuf/AnyMessageStorage.swift - Custom stroage for Any WKT
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Hand written storage class for Google_Protobuf_Any to support on demand
/// transforms between the formats.
///
// -----------------------------------------------------------------------------
import Foundation
#if !swift(>=4.2)
private let i_2166136261 = Int(bitPattern: 2166136261)
private let i_16777619 = Int(16777619)
#endif
fileprivate func serializeAnyJSON(
for message: Message,
typeURL: String,
options: JSONEncodingOptions
) throws -> String {
var visitor = try JSONEncodingVisitor(type: type(of: message), options: options)
visitor.startObject(message: message)
visitor.encodeField(name: "@type", stringValue: typeURL)
if let m = message as? _CustomJSONCodable {
let value = try m.encodedJSONString(options: options)
visitor.encodeField(name: "value", jsonText: value)
} else {
try message.traverse(visitor: &visitor)
}
visitor.endObject()
return visitor.stringResult
}
fileprivate func emitVerboseTextForm(visitor: inout TextFormatEncodingVisitor, message: Message, typeURL: String) {
let url: String
if typeURL.isEmpty {
url = buildTypeURL(forMessage: message, typePrefix: defaultAnyTypeURLPrefix)
} else {
url = typeURL
}
visitor.visitAnyVerbose(value: message, typeURL: url)
}
fileprivate func asJSONObject(body: Data) -> Data {
let asciiOpenCurlyBracket = UInt8(ascii: "{")
let asciiCloseCurlyBracket = UInt8(ascii: "}")
var result = Data([asciiOpenCurlyBracket])
result.append(body)
result.append(asciiCloseCurlyBracket)
return result
}
fileprivate func unpack(contentJSON: Data,
extensions: ExtensionMap,
options: JSONDecodingOptions,
as messageType: Message.Type) throws -> Message {
guard messageType is _CustomJSONCodable.Type else {
let contentJSONAsObject = asJSONObject(body: contentJSON)
return try messageType.init(jsonUTF8Data: contentJSONAsObject, extensions: extensions, options: options)
}
var value = String()
try contentJSON.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
if body.count > 0 {
var scanner = JSONScanner(source: body, options: options, extensions: extensions)
let key = try scanner.nextQuotedString()
if key != "value" {
// The only thing within a WKT should be "value".
throw AnyUnpackError.malformedWellKnownTypeJSON
}
try scanner.skipRequiredColon() // Can't fail
value = try scanner.skip()
if !scanner.complete {
// If that wasn't the end, then there was another key,
// and WKTs should only have the one.
throw AnyUnpackError.malformedWellKnownTypeJSON
}
}
}
return try messageType.init(jsonString: value, extensions: extensions, options: options)
}
internal class AnyMessageStorage {
// The two properties generated Google_Protobuf_Any will reference.
var _typeURL = String()
var _value: Data {
// Remapped to the internal `state`.
get {
switch state {
case .binary(let value):
return value
case .message(let message):
do {
return try message.serializedData(partial: true)
} catch {
return Data()
}
case .contentJSON(let contentJSON, let options):
guard let messageType = Google_Protobuf_Any.messageType(forTypeURL: _typeURL) else {
return Data()
}
do {
let m = try unpack(contentJSON: contentJSON,
extensions: SimpleExtensionMap(),
options: options,
as: messageType)
return try m.serializedData(partial: true)
} catch {
return Data()
}
}
}
set {
state = .binary(newValue)
}
}
enum InternalState {
// a serialized binary
// Note: Unlike contentJSON below, binary does not bother to capture the
// decoding options. This is because the actual binary format is the binary
// blob, i.e. - when decoding from binary, the spec doesn't include decoding
// the binary blob, it is pass through. Instead there is a public api for
// unpacking that takes new options when a developer decides to decode it.
case binary(Data)
// a message
case message(Message)
// parsed JSON with the @type removed and the decoding options.
case contentJSON(Data, JSONDecodingOptions)
}
var state: InternalState = .binary(Data())
static let defaultInstance = AnyMessageStorage()
private init() {}
init(copying source: AnyMessageStorage) {
_typeURL = source._typeURL
state = source.state
}
func isA<M: Message>(_ type: M.Type) -> Bool {
if _typeURL.isEmpty {
return false
}
let encodedType = typeName(fromURL: _typeURL)
return encodedType == M.protoMessageName
}
// This is only ever called with the expectation that target will be fully
// replaced during the unpacking and never as a merge.
func unpackTo<M: Message>(
target: inout M,
extensions: ExtensionMap?,
options: BinaryDecodingOptions
) throws {
guard isA(M.self) else {
throw AnyUnpackError.typeMismatch
}
switch state {
case .binary(let data):
target = try M(serializedData: data, extensions: extensions, partial: true, options: options)
case .message(let msg):
if let message = msg as? M {
// Already right type, copy it over.
target = message
} else {
// Different type, serialize and parse.
let data = try msg.serializedData(partial: true)
target = try M(serializedData: data, extensions: extensions, partial: true)
}
case .contentJSON(let contentJSON, let options):
target = try unpack(contentJSON: contentJSON,
extensions: extensions ?? SimpleExtensionMap(),
options: options,
as: M.self) as! M
}
}
// Called before the message is traversed to do any error preflights.
// Since traverse() will use _value, this is our chance to throw
// when _value can't.
func preTraverse() throws {
switch state {
case .binary:
// Nothing to be checked.
break
case .message:
// When set from a developer provided message, partial support
// is done. Any message that comes in from another format isn't
// checked, and transcoding the isInitialized requirement is
// never inserted.
break
case .contentJSON(let contentJSON, let options):
// contentJSON requires we have the type available for decoding
guard let messageType = Google_Protobuf_Any.messageType(forTypeURL: _typeURL) else {
throw BinaryEncodingError.anyTranscodeFailure
}
do {
// Decodes the full JSON and then discard the result.
// The regular traversal will decode this again by querying the
// `value` field, but that has no way to fail. As a result,
// we need this to accurately handle decode errors.
_ = try unpack(contentJSON: contentJSON,
extensions: SimpleExtensionMap(),
options: options,
as: messageType)
} catch {
throw BinaryEncodingError.anyTranscodeFailure
}
}
}
}
/// Custom handling for Text format.
extension AnyMessageStorage {
func decodeTextFormat(typeURL url: String, decoder: inout TextFormatDecoder) throws {
// Decoding the verbose form requires knowing the type.
_typeURL = url
guard let messageType = Google_Protobuf_Any.messageType(forTypeURL: url) else {
// The type wasn't registered, can't parse it.
throw TextFormatDecodingError.malformedText
}
let terminator = try decoder.scanner.skipObjectStart()
var subDecoder = try TextFormatDecoder(messageType: messageType, scanner: decoder.scanner, terminator: terminator)
if messageType == Google_Protobuf_Any.self {
var any = Google_Protobuf_Any()
try any.decodeTextFormat(decoder: &subDecoder)
state = .message(any)
} else {
var m = messageType.init()
try m.decodeMessage(decoder: &subDecoder)
state = .message(m)
}
decoder.scanner = subDecoder.scanner
if try decoder.nextFieldNumber() != nil {
// Verbose any can never have additional keys.
throw TextFormatDecodingError.malformedText
}
}
// Specialized traverse for writing out a Text form of the Any.
// This prefers the more-legible "verbose" format if it can
// use it, otherwise will fall back to simpler forms.
internal func textTraverse(visitor: inout TextFormatEncodingVisitor) {
switch state {
case .binary(let valueData):
if let messageType = Google_Protobuf_Any.messageType(forTypeURL: _typeURL) {
// If we can decode it, we can write the readable verbose form:
do {
let m = try messageType.init(serializedData: valueData, partial: true)
emitVerboseTextForm(visitor: &visitor, message: m, typeURL: _typeURL)
return
} catch {
// Fall through to just print the type and raw binary data
}
}
if !_typeURL.isEmpty {
try! visitor.visitSingularStringField(value: _typeURL, fieldNumber: 1)
}
if !valueData.isEmpty {
try! visitor.visitSingularBytesField(value: valueData, fieldNumber: 2)
}
case .message(let msg):
emitVerboseTextForm(visitor: &visitor, message: msg, typeURL: _typeURL)
case .contentJSON(let contentJSON, let options):
// If we can decode it, we can write the readable verbose form:
if let messageType = Google_Protobuf_Any.messageType(forTypeURL: _typeURL) {
do {
let m = try unpack(contentJSON: contentJSON,
extensions: SimpleExtensionMap(),
options: options,
as: messageType)
emitVerboseTextForm(visitor: &visitor, message: m, typeURL: _typeURL)
return
} catch {
// Fall through to just print the raw JSON data
}
}
if !_typeURL.isEmpty {
try! visitor.visitSingularStringField(value: _typeURL, fieldNumber: 1)
}
// Build a readable form of the JSON:
let contentJSONAsObject = asJSONObject(body: contentJSON)
visitor.visitAnyJSONDataField(value: contentJSONAsObject)
}
}
}
/// The obvious goal for Hashable/Equatable conformance would be for
/// hash and equality to behave as if we always decoded the inner
/// object and hashed or compared that. Unfortunately, Any typically
/// stores serialized contents and we don't always have the ability to
/// deserialize it. Since none of our supported serializations are
/// fully deterministic, we can't even ensure that equality will
/// behave this way when the Any contents are in the same
/// serialization.
///
/// As a result, we can only really perform a "best effort" equality
/// test. Of course, regardless of the above, we must guarantee that
/// hashValue is compatible with equality.
extension AnyMessageStorage {
#if swift(>=4.2)
// Can't use _valueData for a few reasons:
// 1. Since decode is done on demand, two objects could be equal
// but created differently (one from JSON, one for Message, etc.),
// and the hash values have to be equal even if we don't have data
// yet.
// 2. map<> serialization order is undefined. At the time of writing
// the Swift, Objective-C, and Go runtimes all tend to have random
// orders, so the messages could be identical, but in binary form
// they could differ.
public func hash(into hasher: inout Hasher) {
if !_typeURL.isEmpty {
hasher.combine(_typeURL)
}
}
#else // swift(>=4.2)
var hashValue: Int {
var hash: Int = i_2166136261
if !_typeURL.isEmpty {
hash = (hash &* i_16777619) ^ _typeURL.hashValue
}
return hash
}
#endif // swift(>=4.2)
func isEqualTo(other: AnyMessageStorage) -> Bool {
if (_typeURL != other._typeURL) {
return false
}
// Since the library does lazy Any decode, equality is a very hard problem.
// It things exactly match, that's pretty easy, otherwise, one ends up having
// to error on saying they aren't equal.
//
// The best option would be to have Message forms and compare those, as that
// removes issues like map<> serialization order, some other protocol buffer
// implementation details/bugs around serialized form order, etc.; but that
// would also greatly slow down equality tests.
//
// Do our best to compare what is present have...
// If both have messages, check if they are the same.
if case .message(let myMsg) = state, case .message(let otherMsg) = other.state, type(of: myMsg) == type(of: otherMsg) {
// Since the messages are known to be same type, we can claim both equal and
// not equal based on the equality comparison.
return myMsg.isEqualTo(message: otherMsg)
}
// If both have serialized data, and they exactly match; the messages are equal.
// Because there could be map in the message, the fact that the data isn't the
// same doesn't always mean the messages aren't equal. Likewise, the binary could
// have been created by a library that doesn't order the fields, or the binary was
// created using the appending ability in of the binary format.
if case .binary(let myValue) = state, case .binary(let otherValue) = other.state, myValue == otherValue {
return true
}
// If both have contentJSON, and they exactly match; the messages are equal.
// Because there could be map in the message (or the JSON could just be in a different
// order), the fact that the JSON isn't the same doesn't always mean the messages
// aren't equal.
if case .contentJSON(let myJSON, _) = state,
case .contentJSON(let otherJSON, _) = other.state,
myJSON == otherJSON {
return true
}
// Out of options. To do more compares, the states conversions would have to be
// done to do comparisions; and since equality can be used somewhat removed from
// a developer (if they put protos in a Set, use them as keys to a Dictionary, etc),
// the conversion cost might be to high for those uses. Give up and say they aren't equal.
return false
}
}
// _CustomJSONCodable support for Google_Protobuf_Any
extension AnyMessageStorage {
// Override the traversal-based JSON encoding
// This builds an Any JSON representation from one of:
// * The message we were initialized with,
// * The JSON fields we last deserialized, or
// * The protobuf field we were deserialized from.
// The last case requires locating the type, deserializing
// into an object, then reserializing back to JSON.
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
switch state {
case .binary(let valueData):
// Transcode by decoding the binary data to a message object
// and then recode back into JSON.
guard let messageType = Google_Protobuf_Any.messageType(forTypeURL: _typeURL) else {
// If we don't have the type available, we can't decode the
// binary value, so we're stuck. (The Google spec does not
// provide a way to just package the binary value for someone
// else to decode later.)
throw JSONEncodingError.anyTranscodeFailure
}
let m = try messageType.init(serializedData: valueData, partial: true)
return try serializeAnyJSON(for: m, typeURL: _typeURL, options: options)
case .message(let msg):
// We should have been initialized with a typeURL, but
// ensure it wasn't cleared.
let url = !_typeURL.isEmpty ? _typeURL : buildTypeURL(forMessage: msg, typePrefix: defaultAnyTypeURLPrefix)
return try serializeAnyJSON(for: msg, typeURL: url, options: options)
case .contentJSON(let contentJSON, _):
var jsonEncoder = JSONEncoder()
jsonEncoder.startObject()
jsonEncoder.startField(name: "@type")
jsonEncoder.putStringValue(value: _typeURL)
if !contentJSON.isEmpty {
jsonEncoder.append(staticText: ",")
// NOTE: This doesn't really take `options` into account since it is
// just reflecting out what was taken in originally.
jsonEncoder.append(utf8Data: contentJSON)
}
jsonEncoder.endObject()
return jsonEncoder.stringResult
}
}
// TODO: If the type is well-known or has already been registered,
// we should consider decoding eagerly. Eager decoding would
// catch certain errors earlier (good) but would probably be
// a performance hit if the Any contents were never accessed (bad).
// Of course, we can't always decode eagerly (we don't always have the
// message type available), so the deferred logic here is still needed.
func decodeJSON(from decoder: inout JSONDecoder) throws {
try decoder.scanner.skipRequiredObjectStart()
// Reset state
_typeURL = String()
state = .binary(Data())
if decoder.scanner.skipOptionalObjectEnd() {
return
}
var jsonEncoder = JSONEncoder()
while true {
let key = try decoder.scanner.nextQuotedString()
try decoder.scanner.skipRequiredColon()
if key == "@type" {
_typeURL = try decoder.scanner.nextQuotedString()
} else {
jsonEncoder.startField(name: key)
let keyValueJSON = try decoder.scanner.skip()
jsonEncoder.append(text: keyValueJSON)
}
if decoder.scanner.skipOptionalObjectEnd() {
// Capture the options, but set the messageDepthLimit to be what
// was left right now, as that is the limit when the JSON is finally
// parsed.
var updatedOptions = decoder.options
updatedOptions.messageDepthLimit = decoder.scanner.recursionBudget
state = .contentJSON(jsonEncoder.dataResult, updatedOptions)
return
}
try decoder.scanner.skipRequiredComma()
}
}
}

View File

@ -0,0 +1,37 @@
// Sources/SwiftProtobuf/AnyUnpackError.swift - Any Unpacking Errors
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Errors that can be throw when unpacking a Google_Protobuf_Any.
///
// -----------------------------------------------------------------------------
/// Describes errors that can occur when unpacking an `Google_Protobuf_Any`
/// message.
///
/// `Google_Protobuf_Any` messages can be decoded from protobuf binary, text
/// format, or JSON. The contents are not parsed immediately; the raw data is
/// held in the `Google_Protobuf_Any` message until you `unpack()` it into a
/// message. At this time, any error can occur that might have occurred from a
/// regular decoding operation. There are also other errors that can occur due
/// to problems with the `Any` value's structure.
public enum AnyUnpackError: Error {
/// The `type_url` field in the `Google_Protobuf_Any` message did not match
/// the message type provided to the `unpack()` method.
case typeMismatch
/// Well-known types being decoded from JSON must have only two fields: the
/// `@type` field and a `value` field containing the specialized JSON coding
/// of the well-known type.
case malformedWellKnownTypeJSON
/// The `Google_Protobuf_Any` message was malformed in some other way not
/// covered by the other error cases.
case malformedAnyField
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
// Sources/SwiftProtobuf/BinaryDecodingError.swift - Protobuf binary decoding errors
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Protobuf binary format decoding errors
///
// -----------------------------------------------------------------------------
/// Describes errors that can occur when decoding a message from binary format.
public enum BinaryDecodingError: Error {
/// Extraneous data remained after decoding should have been complete.
case trailingGarbage
/// The decoder unexpectedly reached the end of the data before it was
/// expected.
case truncated
/// A string field was not encoded as valid UTF-8.
case invalidUTF8
/// The binary data was malformed in some way, such as an invalid wire format
/// or field tag.
case malformedProtobuf
/// The definition of the message or one of its nested messages has required
/// fields but the binary data did not include values for them. You must pass
/// `partial: true` during decoding if you wish to explicitly ignore missing
/// required fields.
case missingRequiredFields
/// An internal error happened while decoding. If this is ever encountered,
/// please file an issue with SwiftProtobuf with as much details as possible
/// for what happened (proto definitions, bytes being decoded (if possible)).
case internalExtensionError
/// Reached the nesting limit for messages within messages while decoding.
case messageDepthLimit
}

View File

@ -0,0 +1,39 @@
// Sources/SwiftProtobuf/BinaryDecodingOptions.swift - Binary decoding options
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Binary decoding options
///
// -----------------------------------------------------------------------------
/// Options for JSONDecoding.
public struct BinaryDecodingOptions {
/// The maximum nesting of message with messages. The default is 100.
///
/// To prevent corrupt or malicious messages from causing stack overflows,
/// this controls how deep messages can be nested within other messages
/// while parsing.
public var messageDepthLimit: Int = 100
/// Discard unknown fields while parsing. The default is false, so parsering
/// does not discard unknown fields.
///
/// The Protobuf binary format allows unknown fields to be still parsed
/// so the schema can be expanded without requiring all readers to be updated.
/// This works in part by haivng any unknown fields preserved so they can
/// be relayed on without loss. For a while the proto3 syntax definition
/// called for unknown fields to be dropped, but that lead to problems in
/// some case. The default is to follow the spec and keep them, but setting
/// this option to `true` allows a developer to strip them during a parse
/// in case they have a specific need to drop the unknown fields from the
/// object graph being created.
public var discardUnknownFields: Bool = false
public init() {}
}

View File

@ -0,0 +1,232 @@
// Sources/SwiftProtobuf/BinaryDelimited.swift - Delimited support
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Helpers to read/write message with a length prefix.
///
// -----------------------------------------------------------------------------
import Foundation
/// Helper methods for reading/writing messages with a length prefix.
public enum BinaryDelimited {
/// Additional errors for delimited message handing.
public enum Error: Swift.Error {
/// If a read/write to the stream fails, but the stream's `streamError` is nil,
/// this error will be throw instead since the stream didn't provide anything
/// more specific. A common cause for this can be failing to open the stream
/// before trying to read/write to it.
case unknownStreamError
/// While reading/writing to the stream, less than the expected bytes was
/// read/written.
case truncated
}
/// Serialize a single size-delimited message from the given stream. Delimited
/// format allows a single file or stream to contain multiple messages,
/// whereas normally writing multiple non-delimited messages to the same
/// stream would cause them to be merged. A delimited message is a varint
/// encoding the message size followed by a message of exactly that size.
///
/// - Parameters:
/// - message: The message to be written.
/// - to: The `OutputStream` to write the message to. The stream is
/// is assumed to be ready to be written to.
/// - partial: If `false` (the default), this method will check
/// `Message.isInitialized` before encoding to verify that all required
/// fields are present. If any are missing, this method throws
/// `BinaryEncodingError.missingRequiredFields`.
/// - Throws: `BinaryEncodingError` if encoding fails, throws
/// `BinaryDelimited.Error` for some writing errors, or the
/// underlying `OutputStream.streamError` for a stream error.
public static func serialize(
message: Message,
to stream: OutputStream,
partial: Bool = false
) throws {
// TODO: Revisit to avoid the extra buffering when encoding is streamed in general.
let serialized = try message.serializedData(partial: partial)
let totalSize = Varint.encodedSize(of: UInt64(serialized.count)) + serialized.count
var data = Data(count: totalSize)
data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
var encoder = BinaryEncoder(forWritingInto: baseAddress)
encoder.putBytesValue(value: serialized)
}
}
var written: Int = 0
data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
// This assumingMemoryBound is technically unsafe, but without SR-11078
// (https://bugs.swift.org/browse/SR-11087) we don't have another option.
// It should be "safe enough".
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
written = stream.write(pointer, maxLength: totalSize)
}
}
if written != totalSize {
if written == -1 {
if let streamError = stream.streamError {
throw streamError
}
throw BinaryDelimited.Error.unknownStreamError
}
throw BinaryDelimited.Error.truncated
}
}
/// Reads a single size-delimited message from the given stream. Delimited
/// format allows a single file or stream to contain multiple messages,
/// whereas normally parsing consumes the entire input. A delimited message
/// is a varint encoding the message size followed by a message of exactly
/// exactly that size.
///
/// - Parameters:
/// - messageType: The type of message to read.
/// - from: The `InputStream` to read the data from. The stream is assumed
/// to be ready to read from.
/// - extensions: An `ExtensionMap` used to look up and decode any
/// extensions in this message or messages nested within this message's
/// fields.
/// - partial: If `false` (the default), this method will check
/// `Message.isInitialized` before encoding to verify that all required
/// fields are present. If any are missing, this method throws
/// `BinaryEncodingError.missingRequiredFields`.
/// - options: The BinaryDecodingOptions to use.
/// - Returns: The message read.
/// - Throws: `BinaryDecodingError` if decoding fails, throws
/// `BinaryDelimited.Error` for some reading errors, and the
/// underlying InputStream.streamError for a stream error.
public static func parse<M: Message>(
messageType: M.Type,
from stream: InputStream,
extensions: ExtensionMap? = nil,
partial: Bool = false,
options: BinaryDecodingOptions = BinaryDecodingOptions()
) throws -> M {
var message = M()
try merge(into: &message,
from: stream,
extensions: extensions,
partial: partial,
options: options)
return message
}
/// Updates the message by reading a single size-delimited message from
/// the given stream. Delimited format allows a single file or stream to
/// contain multiple messages, whereas normally parsing consumes the entire
/// input. A delimited message is a varint encoding the message size
/// followed by a message of exactly that size.
///
/// - Note: If this method throws an error, the message may still have been
/// partially mutated by the binary data that was decoded before the error
/// occurred.
///
/// - Parameters:
/// - mergingTo: The message to merge the data into.
/// - from: The `InputStream` to read the data from. The stream is assumed
/// to be ready to read from.
/// - extensions: An `ExtensionMap` used to look up and decode any
/// extensions in this message or messages nested within this message's
/// fields.
/// - partial: If `false` (the default), this method will check
/// `Message.isInitialized` before encoding to verify that all required
/// fields are present. If any are missing, this method throws
/// `BinaryEncodingError.missingRequiredFields`.
/// - options: The BinaryDecodingOptions to use.
/// - Throws: `BinaryDecodingError` if decoding fails, throws
/// `BinaryDelimited.Error` for some reading errors, and the
/// underlying InputStream.streamError for a stream error.
public static func merge<M: Message>(
into message: inout M,
from stream: InputStream,
extensions: ExtensionMap? = nil,
partial: Bool = false,
options: BinaryDecodingOptions = BinaryDecodingOptions()
) throws {
let length = try Int(decodeVarint(stream))
if length == 0 {
// The message was all defaults, nothing to actually read.
return
}
var data = Data(count: length)
var bytesRead: Int = 0
data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
// This assumingMemoryBound is technically unsafe, but without SR-11078
// (https://bugs.swift.org/browse/SR-11087) we don't have another option.
// It should be "safe enough".
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
bytesRead = stream.read(pointer, maxLength: length)
}
}
if bytesRead != length {
if bytesRead == -1 {
if let streamError = stream.streamError {
throw streamError
}
throw BinaryDelimited.Error.unknownStreamError
}
throw BinaryDelimited.Error.truncated
}
try message.merge(serializedData: data,
extensions: extensions,
partial: partial,
options: options)
}
}
// TODO: This should go away when encoding/decoding are more stream based
// as that should provide a more direct way to do this. This is basically
// a rewrite of BinaryDecoder.decodeVarint().
internal func decodeVarint(_ stream: InputStream) throws -> UInt64 {
// Buffer to reuse within nextByte.
let readBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 1)
#if swift(>=4.1)
defer { readBuffer.deallocate() }
#else
defer { readBuffer.deallocate(capacity: 1) }
#endif
func nextByte() throws -> UInt8 {
let bytesRead = stream.read(readBuffer, maxLength: 1)
if bytesRead != 1 {
if bytesRead == -1 {
if let streamError = stream.streamError {
throw streamError
}
throw BinaryDelimited.Error.unknownStreamError
}
throw BinaryDelimited.Error.truncated
}
return readBuffer[0]
}
var value: UInt64 = 0
var shift: UInt64 = 0
while true {
let c = try nextByte()
value |= UInt64(c & 0x7f) << shift
if c & 0x80 == 0 {
return value
}
shift += 7
if shift > 63 {
throw BinaryDecodingError.malformedProtobuf
}
}
}

View File

@ -0,0 +1,155 @@
// Sources/SwiftProtobuf/BinaryEncoder.swift - Binary encoding support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Core support for protobuf binary encoding. Note that this is built
/// on the general traversal machinery.
///
// -----------------------------------------------------------------------------
import Foundation
/*
* Encoder for Binary Protocol Buffer format
*/
internal struct BinaryEncoder {
private var pointer: UnsafeMutableRawPointer
init(forWritingInto pointer: UnsafeMutableRawPointer) {
self.pointer = pointer
}
private mutating func append(_ byte: UInt8) {
pointer.storeBytes(of: byte, as: UInt8.self)
pointer = pointer.advanced(by: 1)
}
private mutating func append(contentsOf data: Data) {
data.withUnsafeBytes { dataPointer in
if let baseAddress = dataPointer.baseAddress, dataPointer.count > 0 {
pointer.copyMemory(from: baseAddress, byteCount: dataPointer.count)
pointer = pointer.advanced(by: dataPointer.count)
}
}
}
@discardableResult
private mutating func append(contentsOf bufferPointer: UnsafeRawBufferPointer) -> Int {
let count = bufferPointer.count
if let baseAddress = bufferPointer.baseAddress, count > 0 {
memcpy(pointer, baseAddress, count)
}
pointer = pointer.advanced(by: count)
return count
}
func distance(pointer: UnsafeMutableRawPointer) -> Int {
return pointer.distance(to: self.pointer)
}
mutating func appendUnknown(data: Data) {
append(contentsOf: data)
}
mutating func startField(fieldNumber: Int, wireFormat: WireFormat) {
startField(tag: FieldTag(fieldNumber: fieldNumber, wireFormat: wireFormat))
}
mutating func startField(tag: FieldTag) {
putVarInt(value: UInt64(tag.rawValue))
}
mutating func putVarInt(value: UInt64) {
var v = value
while v > 127 {
append(UInt8(v & 0x7f | 0x80))
v >>= 7
}
append(UInt8(v))
}
mutating func putVarInt(value: Int64) {
putVarInt(value: UInt64(bitPattern: value))
}
mutating func putVarInt(value: Int) {
putVarInt(value: Int64(value))
}
mutating func putZigZagVarInt(value: Int64) {
let coded = ZigZag.encoded(value)
putVarInt(value: coded)
}
mutating func putBoolValue(value: Bool) {
append(value ? 1 : 0)
}
mutating func putFixedUInt64(value: UInt64) {
var v = value.littleEndian
let n = MemoryLayout<UInt64>.size
memcpy(pointer, &v, n)
pointer = pointer.advanced(by: n)
}
mutating func putFixedUInt32(value: UInt32) {
var v = value.littleEndian
let n = MemoryLayout<UInt32>.size
memcpy(pointer, &v, n)
pointer = pointer.advanced(by: n)
}
mutating func putFloatValue(value: Float) {
let n = MemoryLayout<Float>.size
var v = value
var nativeBytes: UInt32 = 0
memcpy(&nativeBytes, &v, n)
var littleEndianBytes = nativeBytes.littleEndian
memcpy(pointer, &littleEndianBytes, n)
pointer = pointer.advanced(by: n)
}
mutating func putDoubleValue(value: Double) {
let n = MemoryLayout<Double>.size
var v = value
var nativeBytes: UInt64 = 0
memcpy(&nativeBytes, &v, n)
var littleEndianBytes = nativeBytes.littleEndian
memcpy(pointer, &littleEndianBytes, n)
pointer = pointer.advanced(by: n)
}
// Write a string field, including the leading index/tag value.
mutating func putStringValue(value: String) {
let utf8 = value.utf8
#if swift(>=5.0)
// If the String does not support an internal representation in a form
// of contiguous storage, body is not called and nil is returned.
let isAvailable = utf8.withContiguousStorageIfAvailable { (body: UnsafeBufferPointer<UInt8>) -> Int in
putVarInt(value: body.count)
return append(contentsOf: UnsafeRawBufferPointer(body))
}
#else
let isAvailable: Int? = nil
#endif
if isAvailable == nil {
let count = utf8.count
putVarInt(value: count)
for b in utf8 {
pointer.storeBytes(of: b, as: UInt8.self)
pointer = pointer.advanced(by: 1)
}
}
}
mutating func putBytesValue(value: Data) {
putVarInt(value: value.count)
append(contentsOf: value)
}
}

View File

@ -0,0 +1,27 @@
// Sources/SwiftProtobuf/BinaryEncodingError.swift - Error constants
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Enum constants that identify the particular error.
///
// -----------------------------------------------------------------------------
/// Describes errors that can occur when decoding a message from binary format.
public enum BinaryEncodingError: Error {
/// `Any` fields that were decoded from JSON cannot be re-encoded to binary
/// unless the object they hold is a well-known type or a type registered via
/// `Google_Protobuf_Any.register()`.
case anyTranscodeFailure
/// The definition of the message or one of its nested messages has required
/// fields but the message being encoded did not include values for them. You
/// must pass `partial: true` during encoding if you wish to explicitly ignore
/// missing required fields.
case missingRequiredFields
}

View File

@ -0,0 +1,473 @@
// Sources/SwiftProtobuf/BinaryEncodingSizeVisitor.swift - Binary size calculation support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Visitor used during binary encoding that precalcuates the size of a
/// serialized message.
///
// -----------------------------------------------------------------------------
import Foundation
/// Visitor that calculates the binary-encoded size of a message so that a
/// properly sized `Data` or `UInt8` array can be pre-allocated before
/// serialization.
internal struct BinaryEncodingSizeVisitor: Visitor {
/// Accumulates the required size of the message during traversal.
var serializedSize: Int = 0
init() {}
mutating func visitUnknown(bytes: Data) throws {
serializedSize += bytes.count
}
mutating func visitSingularFloatField(value: Float, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed32).encodedSize
serializedSize += tagSize + MemoryLayout<Float>.size
}
mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed64).encodedSize
serializedSize += tagSize + MemoryLayout<Double>.size
}
mutating func visitSingularInt32Field(value: Int32, fieldNumber: Int) throws {
try visitSingularInt64Field(value: Int64(value), fieldNumber: fieldNumber)
}
mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
serializedSize += tagSize + Varint.encodedSize(of: value)
}
mutating func visitSingularUInt32Field(value: UInt32, fieldNumber: Int) throws {
try visitSingularUInt64Field(value: UInt64(value), fieldNumber: fieldNumber)
}
mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
serializedSize += tagSize + Varint.encodedSize(of: value)
}
mutating func visitSingularSInt32Field(value: Int32, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
serializedSize += tagSize + Varint.encodedSize(of: ZigZag.encoded(value))
}
mutating func visitSingularSInt64Field(value: Int64, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
serializedSize += tagSize + Varint.encodedSize(of: ZigZag.encoded(value))
}
mutating func visitSingularFixed32Field(value: UInt32, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed32).encodedSize
serializedSize += tagSize + MemoryLayout<UInt32>.size
}
mutating func visitSingularFixed64Field(value: UInt64, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed64).encodedSize
serializedSize += tagSize + MemoryLayout<UInt64>.size
}
mutating func visitSingularSFixed32Field(value: Int32, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed32).encodedSize
serializedSize += tagSize + MemoryLayout<Int32>.size
}
mutating func visitSingularSFixed64Field(value: Int64, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed64).encodedSize
serializedSize += tagSize + MemoryLayout<Int64>.size
}
mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
serializedSize += tagSize + 1
}
mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let count = value.utf8.count
serializedSize += tagSize + Varint.encodedSize(of: Int64(count)) + count
}
mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let count = value.count
serializedSize += tagSize + Varint.encodedSize(of: Int64(count)) + count
}
// The default impls for visitRepeated*Field would work, but by implementing
// these directly, the calculation for the tag overhead can be optimized and
// the fixed width fields can be simple multiplication.
mutating func visitRepeatedFloatField(value: [Float], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed32).encodedSize
serializedSize += tagSize * value.count + MemoryLayout<Float>.size * value.count
}
mutating func visitRepeatedDoubleField(value: [Double], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed64).encodedSize
serializedSize += tagSize * value.count + MemoryLayout<Double>.size * value.count
}
mutating func visitRepeatedInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
serializedSize += tagSize * value.count + dataSize
}
mutating func visitRepeatedInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
serializedSize += tagSize * value.count + dataSize
}
mutating func visitRepeatedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
serializedSize += tagSize * value.count + dataSize
}
mutating func visitRepeatedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
serializedSize += tagSize * value.count + dataSize
}
mutating func visitRepeatedSInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: ZigZag.encoded($1)) }
serializedSize += tagSize * value.count + dataSize
}
mutating func visitRepeatedSInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: ZigZag.encoded($1)) }
serializedSize += tagSize * value.count + dataSize
}
mutating func visitRepeatedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed32).encodedSize
serializedSize += tagSize * value.count + MemoryLayout<UInt32>.size * value.count
}
mutating func visitRepeatedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed64).encodedSize
serializedSize += tagSize * value.count + MemoryLayout<UInt64>.size * value.count
}
mutating func visitRepeatedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed32).encodedSize
serializedSize += tagSize * value.count + MemoryLayout<Int32>.size * value.count
}
mutating func visitRepeatedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .fixed64).encodedSize
serializedSize += tagSize * value.count + MemoryLayout<Int64>.size * value.count
}
mutating func visitRepeatedBoolField(value: [Bool], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .varint).encodedSize
serializedSize += tagSize * value.count + 1 * value.count
}
mutating func visitRepeatedStringField(value: [String], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.reduce(0) {
let count = $1.utf8.count
return $0 + Varint.encodedSize(of: Int64(count)) + count
}
serializedSize += tagSize * value.count + dataSize
}
mutating func visitRepeatedBytesField(value: [Data], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.reduce(0) {
let count = $1.count
return $0 + Varint.encodedSize(of: Int64(count)) + count
}
serializedSize += tagSize * value.count + dataSize
}
// Packed field handling.
mutating func visitPackedFloatField(value: [Float], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.count * MemoryLayout<Float>.size
serializedSize += tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedDoubleField(value: [Double], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.count * MemoryLayout<Double>.size
serializedSize += tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
serializedSize +=
tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
serializedSize +=
tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedSInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: ZigZag.encoded($1)) }
serializedSize +=
tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedSInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: ZigZag.encoded($1)) }
serializedSize +=
tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
serializedSize +=
tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
serializedSize +=
tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.count * MemoryLayout<UInt32>.size
serializedSize += tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.count * MemoryLayout<UInt64>.size
serializedSize += tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.count * MemoryLayout<Int32>.size
serializedSize += tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.count * MemoryLayout<Int64>.size
serializedSize += tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitPackedBoolField(value: [Bool], fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber, wireFormat: .lengthDelimited).encodedSize
let dataSize = value.count
serializedSize += tagSize + Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitSingularEnumField<E: Enum>(value: E,
fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber,
wireFormat: .varint).encodedSize
serializedSize += tagSize
let dataSize = Varint.encodedSize(of: Int32(truncatingIfNeeded: value.rawValue))
serializedSize += dataSize
}
mutating func visitRepeatedEnumField<E: Enum>(value: [E],
fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber,
wireFormat: .varint).encodedSize
serializedSize += value.count * tagSize
let dataSize = value.reduce(0) {
$0 + Varint.encodedSize(of: Int32(truncatingIfNeeded: $1.rawValue))
}
serializedSize += dataSize
}
mutating func visitPackedEnumField<E: Enum>(value: [E],
fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber,
wireFormat: .varint).encodedSize
serializedSize += tagSize
let dataSize = value.reduce(0) {
$0 + Varint.encodedSize(of: Int32(truncatingIfNeeded: $1.rawValue))
}
serializedSize += Varint.encodedSize(of: Int64(dataSize)) + dataSize
}
mutating func visitSingularMessageField<M: Message>(value: M,
fieldNumber: Int) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber,
wireFormat: .lengthDelimited).encodedSize
let messageSize = try value.serializedDataSize()
serializedSize +=
tagSize + Varint.encodedSize(of: UInt64(messageSize)) + messageSize
}
mutating func visitRepeatedMessageField<M: Message>(value: [M],
fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber,
wireFormat: .lengthDelimited).encodedSize
serializedSize += value.count * tagSize
let dataSize = try value.reduce(0) {
let messageSize = try $1.serializedDataSize()
return $0 + Varint.encodedSize(of: UInt64(messageSize)) + messageSize
}
serializedSize += dataSize
}
mutating func visitSingularGroupField<G: Message>(value: G, fieldNumber: Int) throws {
// The wire format doesn't matter here because the encoded size of the
// integer won't change based on the low three bits.
let tagSize = FieldTag(fieldNumber: fieldNumber,
wireFormat: .startGroup).encodedSize
serializedSize += 2 * tagSize
try value.traverse(visitor: &self)
}
mutating func visitRepeatedGroupField<G: Message>(value: [G],
fieldNumber: Int) throws {
assert(!value.isEmpty)
let tagSize = FieldTag(fieldNumber: fieldNumber,
wireFormat: .startGroup).encodedSize
serializedSize += 2 * value.count * tagSize
for v in value {
try v.traverse(visitor: &self)
}
}
mutating func visitMapField<KeyType, ValueType: MapValueType>(
fieldType: _ProtobufMap<KeyType, ValueType>.Type,
value: _ProtobufMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber,
wireFormat: .lengthDelimited).encodedSize
for (k,v) in value {
var sizer = BinaryEncodingSizeVisitor()
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &sizer)
try ValueType.visitSingular(value: v, fieldNumber: 2, with: &sizer)
let entrySize = sizer.serializedSize
serializedSize += Varint.encodedSize(of: Int64(entrySize)) + entrySize
}
serializedSize += value.count * tagSize
}
mutating func visitMapField<KeyType, ValueType>(
fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
value: _ProtobufEnumMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws where ValueType.RawValue == Int {
let tagSize = FieldTag(fieldNumber: fieldNumber,
wireFormat: .lengthDelimited).encodedSize
for (k,v) in value {
var sizer = BinaryEncodingSizeVisitor()
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &sizer)
try sizer.visitSingularEnumField(value: v, fieldNumber: 2)
let entrySize = sizer.serializedSize
serializedSize += Varint.encodedSize(of: Int64(entrySize)) + entrySize
}
serializedSize += value.count * tagSize
}
mutating func visitMapField<KeyType, ValueType>(
fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
value: _ProtobufMessageMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws {
let tagSize = FieldTag(fieldNumber: fieldNumber,
wireFormat: .lengthDelimited).encodedSize
for (k,v) in value {
var sizer = BinaryEncodingSizeVisitor()
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &sizer)
try sizer.visitSingularMessageField(value: v, fieldNumber: 2)
let entrySize = sizer.serializedSize
serializedSize += Varint.encodedSize(of: Int64(entrySize)) + entrySize
}
serializedSize += value.count * tagSize
}
mutating func visitExtensionFieldsAsMessageSet(
fields: ExtensionFieldValueSet,
start: Int,
end: Int
) throws {
var sizer = BinaryEncodingMessageSetSizeVisitor()
try fields.traverse(visitor: &sizer, start: start, end: end)
serializedSize += sizer.serializedSize
}
}
extension BinaryEncodingSizeVisitor {
// Helper Visitor to compute the sizes when writing out the extensions as MessageSets.
internal struct BinaryEncodingMessageSetSizeVisitor: SelectiveVisitor {
var serializedSize: Int = 0
init() {}
mutating func visitSingularMessageField<M: Message>(value: M, fieldNumber: Int) throws {
var groupSize = WireFormat.MessageSet.itemTagsEncodedSize
groupSize += Varint.encodedSize(of: Int32(fieldNumber))
let messageSize = try value.serializedDataSize()
groupSize += Varint.encodedSize(of: UInt64(messageSize)) + messageSize
serializedSize += groupSize
}
// SelectiveVisitor handles the rest.
}
}

View File

@ -0,0 +1,355 @@
// Sources/SwiftProtobuf/BinaryEncodingVisitor.swift - Binary encoding support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Core support for protobuf binary encoding. Note that this is built
/// on the general traversal machinery.
///
// -----------------------------------------------------------------------------
import Foundation
/// Visitor that encodes a message graph in the protobuf binary wire format.
internal struct BinaryEncodingVisitor: Visitor {
var encoder: BinaryEncoder
/// Creates a new visitor that writes the binary-coded message into the memory
/// at the given pointer.
///
/// - Precondition: `pointer` must point to an allocated block of memory that
/// is large enough to hold the entire encoded message. For performance
/// reasons, the encoder does not make any attempts to verify this.
init(forWritingInto pointer: UnsafeMutableRawPointer) {
encoder = BinaryEncoder(forWritingInto: pointer)
}
init(encoder: BinaryEncoder) {
self.encoder = encoder
}
mutating func visitUnknown(bytes: Data) throws {
encoder.appendUnknown(data: bytes)
}
mutating func visitSingularFloatField(value: Float, fieldNumber: Int) throws {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .fixed32)
encoder.putFloatValue(value: value)
}
mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .fixed64)
encoder.putDoubleValue(value: value)
}
mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
try visitSingularUInt64Field(value: UInt64(bitPattern: value), fieldNumber: fieldNumber)
}
mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .varint)
encoder.putVarInt(value: value)
}
mutating func visitSingularSInt32Field(value: Int32, fieldNumber: Int) throws {
try visitSingularSInt64Field(value: Int64(value), fieldNumber: fieldNumber)
}
mutating func visitSingularSInt64Field(value: Int64, fieldNumber: Int) throws {
try visitSingularUInt64Field(value: ZigZag.encoded(value), fieldNumber: fieldNumber)
}
mutating func visitSingularFixed32Field(value: UInt32, fieldNumber: Int) throws {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .fixed32)
encoder.putFixedUInt32(value: value)
}
mutating func visitSingularFixed64Field(value: UInt64, fieldNumber: Int) throws {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .fixed64)
encoder.putFixedUInt64(value: value)
}
mutating func visitSingularSFixed32Field(value: Int32, fieldNumber: Int) throws {
try visitSingularFixed32Field(value: UInt32(bitPattern: value), fieldNumber: fieldNumber)
}
mutating func visitSingularSFixed64Field(value: Int64, fieldNumber: Int) throws {
try visitSingularFixed64Field(value: UInt64(bitPattern: value), fieldNumber: fieldNumber)
}
mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
try visitSingularUInt64Field(value: value ? 1 : 0, fieldNumber: fieldNumber)
}
mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
encoder.putStringValue(value: value)
}
mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
encoder.putBytesValue(value: value)
}
mutating func visitSingularEnumField<E: Enum>(value: E,
fieldNumber: Int) throws {
try visitSingularUInt64Field(value: UInt64(bitPattern: Int64(value.rawValue)),
fieldNumber: fieldNumber)
}
mutating func visitSingularMessageField<M: Message>(value: M,
fieldNumber: Int) throws {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
let length = try value.serializedDataSize()
encoder.putVarInt(value: length)
try value.traverse(visitor: &self)
}
mutating func visitSingularGroupField<G: Message>(value: G, fieldNumber: Int) throws {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .startGroup)
try value.traverse(visitor: &self)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .endGroup)
}
// Repeated fields are handled by the default implementations in Visitor.swift
// Packed Fields
mutating func visitPackedFloatField(value: [Float], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
encoder.putVarInt(value: value.count * MemoryLayout<Float>.size)
for v in value {
encoder.putFloatValue(value: v)
}
}
mutating func visitPackedDoubleField(value: [Double], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
encoder.putVarInt(value: value.count * MemoryLayout<Double>.size)
for v in value {
encoder.putDoubleValue(value: v)
}
}
mutating func visitPackedInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
let packedSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
encoder.putVarInt(value: packedSize)
for v in value {
encoder.putVarInt(value: Int64(v))
}
}
mutating func visitPackedInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
let packedSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
encoder.putVarInt(value: packedSize)
for v in value {
encoder.putVarInt(value: v)
}
}
mutating func visitPackedSInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
let packedSize = value.reduce(0) { $0 + Varint.encodedSize(of: ZigZag.encoded($1)) }
encoder.putVarInt(value: packedSize)
for v in value {
encoder.putZigZagVarInt(value: Int64(v))
}
}
mutating func visitPackedSInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
let packedSize = value.reduce(0) { $0 + Varint.encodedSize(of: ZigZag.encoded($1)) }
encoder.putVarInt(value: packedSize)
for v in value {
encoder.putZigZagVarInt(value: v)
}
}
mutating func visitPackedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
let packedSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
encoder.putVarInt(value: packedSize)
for v in value {
encoder.putVarInt(value: UInt64(v))
}
}
mutating func visitPackedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
let packedSize = value.reduce(0) { $0 + Varint.encodedSize(of: $1) }
encoder.putVarInt(value: packedSize)
for v in value {
encoder.putVarInt(value: v)
}
}
mutating func visitPackedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
encoder.putVarInt(value: value.count * MemoryLayout<UInt32>.size)
for v in value {
encoder.putFixedUInt32(value: v)
}
}
mutating func visitPackedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
encoder.putVarInt(value: value.count * MemoryLayout<UInt64>.size)
for v in value {
encoder.putFixedUInt64(value: v)
}
}
mutating func visitPackedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
encoder.putVarInt(value: value.count * MemoryLayout<Int32>.size)
for v in value {
encoder.putFixedUInt32(value: UInt32(bitPattern: v))
}
}
mutating func visitPackedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
encoder.putVarInt(value: value.count * MemoryLayout<Int64>.size)
for v in value {
encoder.putFixedUInt64(value: UInt64(bitPattern: v))
}
}
mutating func visitPackedBoolField(value: [Bool], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
encoder.putVarInt(value: value.count)
for v in value {
encoder.putVarInt(value: v ? 1 : 0)
}
}
mutating func visitPackedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
assert(!value.isEmpty)
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
let packedSize = value.reduce(0) {
$0 + Varint.encodedSize(of: Int32(truncatingIfNeeded: $1.rawValue))
}
encoder.putVarInt(value: packedSize)
for v in value {
encoder.putVarInt(value: v.rawValue)
}
}
mutating func visitMapField<KeyType, ValueType: MapValueType>(
fieldType: _ProtobufMap<KeyType, ValueType>.Type,
value: _ProtobufMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws {
for (k,v) in value {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
var sizer = BinaryEncodingSizeVisitor()
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &sizer)
try ValueType.visitSingular(value: v, fieldNumber: 2, with: &sizer)
let entrySize = sizer.serializedSize
encoder.putVarInt(value: entrySize)
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &self)
try ValueType.visitSingular(value: v, fieldNumber: 2, with: &self)
}
}
mutating func visitMapField<KeyType, ValueType>(
fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
value: _ProtobufEnumMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws where ValueType.RawValue == Int {
for (k,v) in value {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
var sizer = BinaryEncodingSizeVisitor()
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &sizer)
try sizer.visitSingularEnumField(value: v, fieldNumber: 2)
let entrySize = sizer.serializedSize
encoder.putVarInt(value: entrySize)
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &self)
try visitSingularEnumField(value: v, fieldNumber: 2)
}
}
mutating func visitMapField<KeyType, ValueType>(
fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
value: _ProtobufMessageMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws {
for (k,v) in value {
encoder.startField(fieldNumber: fieldNumber, wireFormat: .lengthDelimited)
var sizer = BinaryEncodingSizeVisitor()
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &sizer)
try sizer.visitSingularMessageField(value: v, fieldNumber: 2)
let entrySize = sizer.serializedSize
encoder.putVarInt(value: entrySize)
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &self)
try visitSingularMessageField(value: v, fieldNumber: 2)
}
}
mutating func visitExtensionFieldsAsMessageSet(
fields: ExtensionFieldValueSet,
start: Int,
end: Int
) throws {
var subVisitor = BinaryEncodingMessageSetVisitor(encoder: encoder)
try fields.traverse(visitor: &subVisitor, start: start, end: end)
encoder = subVisitor.encoder
}
}
extension BinaryEncodingVisitor {
// Helper Visitor to when writing out the extensions as MessageSets.
internal struct BinaryEncodingMessageSetVisitor: SelectiveVisitor {
var encoder: BinaryEncoder
init(encoder: BinaryEncoder) {
self.encoder = encoder
}
mutating func visitSingularMessageField<M: Message>(value: M, fieldNumber: Int) throws {
encoder.putVarInt(value: Int64(WireFormat.MessageSet.Tags.itemStart.rawValue))
encoder.putVarInt(value: Int64(WireFormat.MessageSet.Tags.typeId.rawValue))
encoder.putVarInt(value: fieldNumber)
encoder.putVarInt(value: Int64(WireFormat.MessageSet.Tags.message.rawValue))
// Use a normal BinaryEncodingVisitor so any message fields end up in the
// normal wire format (instead of MessageSet format).
let length = try value.serializedDataSize()
encoder.putVarInt(value: length)
// Create the sub encoder after writing the length.
var subVisitor = BinaryEncodingVisitor(encoder: encoder)
try value.traverse(visitor: &subVisitor)
encoder = subVisitor.encoder
encoder.putVarInt(value: Int64(WireFormat.MessageSet.Tags.itemEnd.rawValue))
}
// SelectiveVisitor handles the rest.
}
}

View File

@ -0,0 +1,36 @@
// Sources/SwiftProtobuf/CustomJSONCodable.swift - Custom JSON support for WKTs
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Custom protocol for the WKTs to support their custom JSON encodings.
///
// -----------------------------------------------------------------------------
/// Allows WKTs to provide their custom JSON encodings.
internal protocol _CustomJSONCodable {
func encodedJSONString(options: JSONEncodingOptions) throws -> String
mutating func decodeJSON(from: inout JSONDecoder) throws
/// Called when the JSON `null` literal is encountered in a position where
/// a message of the conforming type is expected. The message type can then
/// handle the `null` value differently, if needed; for example,
/// `Google_Protobuf_Value` returns a special instance whose `kind` is set to
/// `.nullValue(.nullValue)`.
///
/// The default behavior is to return `nil`, which indicates that `null`
/// should be treated as the absence of a message.
static func decodedFromJSONNull() throws -> Self?
}
extension _CustomJSONCodable {
internal static func decodedFromJSONNull() -> Self? {
// Return nil by default. Concrete types can provide custom logic.
return nil
}
}

View File

@ -0,0 +1,34 @@
// Sources/SwiftProtobuf/Data+Extensions.swift - Extension exposing new Data API
//
// Copyright (c) 2014 - 2019 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extension exposing new Data API to Swift versions < 5.0.
///
// -----------------------------------------------------------------------------
import Foundation
#if !swift(>=5.0)
internal extension Data {
@usableFromInline
func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
let c = count
return try withUnsafeBytes { (p: UnsafePointer<UInt8>) throws -> T in
try body(UnsafeRawBufferPointer(start: p, count: c))
}
}
mutating func withUnsafeMutableBytes<T>(_ body: (UnsafeMutableRawBufferPointer) throws -> T) rethrows -> T {
let c = count
return try withUnsafeMutableBytes { (p: UnsafeMutablePointer<UInt8>) throws -> T in
try body(UnsafeMutableRawBufferPointer(start: p, count: c))
}
}
}
#endif

View File

@ -0,0 +1,150 @@
// Sources/SwiftProtobuf/Decoder.swift - Basic field setting
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// In this way, the generated code only knows about schema
/// information; the decoder logic knows how to decode particular
/// wire types based on that information.
///
// -----------------------------------------------------------------------------
import Foundation
/// This is the abstract protocol used by the generated code
/// to deserialize data.
///
/// The generated code looks roughly like this:
///
/// ```
/// while fieldNumber = try decoder.nextFieldNumber() {
/// switch fieldNumber {
/// case 1: decoder.decodeRepeatedInt32Field(value: &_field)
/// ... etc ...
/// }
/// ```
///
/// For performance, this is mostly broken out into a separate method
/// for singular/repeated fields of every supported type. Note that
/// we don't distinguish "packed" here, since all existing decoders
/// treat "packed" the same as "repeated" at this level. (That is,
/// even when the serializer distinguishes packed and non-packed
/// forms, the deserializer always accepts both.)
///
/// Generics come into play at only a few points: `Enum`s and `Message`s
/// use a generic type to locate the correct initializer. Maps and
/// extensions use generics to avoid the method explosion of having to
/// support a separate method for every map and extension type. Maps
/// do distinguish `Enum`-valued and `Message`-valued maps to avoid
/// polluting the generated `Enum` and `Message` types with all of the
/// necessary generic methods to support this.
public protocol Decoder {
/// Called by a `oneof` when it already has a value and is being asked to
/// accept a new value. Some formats require `oneof` decoding to fail in this
/// case.
mutating func handleConflictingOneOf() throws
/// Returns the next field number, or nil when the end of the input is
/// reached.
///
/// For JSON and text format, the decoder translates the field name to a
/// number at this point, based on information it obtained from the message
/// when it was initialized.
mutating func nextFieldNumber() throws -> Int?
// Primitive field decoders
mutating func decodeSingularFloatField(value: inout Float) throws
mutating func decodeSingularFloatField(value: inout Float?) throws
mutating func decodeRepeatedFloatField(value: inout [Float]) throws
mutating func decodeSingularDoubleField(value: inout Double) throws
mutating func decodeSingularDoubleField(value: inout Double?) throws
mutating func decodeRepeatedDoubleField(value: inout [Double]) throws
mutating func decodeSingularInt32Field(value: inout Int32) throws
mutating func decodeSingularInt32Field(value: inout Int32?) throws
mutating func decodeRepeatedInt32Field(value: inout [Int32]) throws
mutating func decodeSingularInt64Field(value: inout Int64) throws
mutating func decodeSingularInt64Field(value: inout Int64?) throws
mutating func decodeRepeatedInt64Field(value: inout [Int64]) throws
mutating func decodeSingularUInt32Field(value: inout UInt32) throws
mutating func decodeSingularUInt32Field(value: inout UInt32?) throws
mutating func decodeRepeatedUInt32Field(value: inout [UInt32]) throws
mutating func decodeSingularUInt64Field(value: inout UInt64) throws
mutating func decodeSingularUInt64Field(value: inout UInt64?) throws
mutating func decodeRepeatedUInt64Field(value: inout [UInt64]) throws
mutating func decodeSingularSInt32Field(value: inout Int32) throws
mutating func decodeSingularSInt32Field(value: inout Int32?) throws
mutating func decodeRepeatedSInt32Field(value: inout [Int32]) throws
mutating func decodeSingularSInt64Field(value: inout Int64) throws
mutating func decodeSingularSInt64Field(value: inout Int64?) throws
mutating func decodeRepeatedSInt64Field(value: inout [Int64]) throws
mutating func decodeSingularFixed32Field(value: inout UInt32) throws
mutating func decodeSingularFixed32Field(value: inout UInt32?) throws
mutating func decodeRepeatedFixed32Field(value: inout [UInt32]) throws
mutating func decodeSingularFixed64Field(value: inout UInt64) throws
mutating func decodeSingularFixed64Field(value: inout UInt64?) throws
mutating func decodeRepeatedFixed64Field(value: inout [UInt64]) throws
mutating func decodeSingularSFixed32Field(value: inout Int32) throws
mutating func decodeSingularSFixed32Field(value: inout Int32?) throws
mutating func decodeRepeatedSFixed32Field(value: inout [Int32]) throws
mutating func decodeSingularSFixed64Field(value: inout Int64) throws
mutating func decodeSingularSFixed64Field(value: inout Int64?) throws
mutating func decodeRepeatedSFixed64Field(value: inout [Int64]) throws
mutating func decodeSingularBoolField(value: inout Bool) throws
mutating func decodeSingularBoolField(value: inout Bool?) throws
mutating func decodeRepeatedBoolField(value: inout [Bool]) throws
mutating func decodeSingularStringField(value: inout String) throws
mutating func decodeSingularStringField(value: inout String?) throws
mutating func decodeRepeatedStringField(value: inout [String]) throws
mutating func decodeSingularBytesField(value: inout Data) throws
mutating func decodeSingularBytesField(value: inout Data?) throws
mutating func decodeRepeatedBytesField(value: inout [Data]) throws
// Decode Enum fields
mutating func decodeSingularEnumField<E: Enum>(value: inout E) throws where E.RawValue == Int
mutating func decodeSingularEnumField<E: Enum>(value: inout E?) throws where E.RawValue == Int
mutating func decodeRepeatedEnumField<E: Enum>(value: inout [E]) throws where E.RawValue == Int
// Decode Message fields
mutating func decodeSingularMessageField<M: Message>(value: inout M?) throws
mutating func decodeRepeatedMessageField<M: Message>(value: inout [M]) throws
// Decode Group fields
mutating func decodeSingularGroupField<G: Message>(value: inout G?) throws
mutating func decodeRepeatedGroupField<G: Message>(value: inout [G]) throws
// Decode Map fields.
// This is broken into separate methods depending on whether the value
// type is primitive (_ProtobufMap), enum (_ProtobufEnumMap), or message
// (_ProtobufMessageMap)
mutating func decodeMapField<KeyType, ValueType: MapValueType>(fieldType: _ProtobufMap<KeyType, ValueType>.Type, value: inout _ProtobufMap<KeyType, ValueType>.BaseType) throws
mutating func decodeMapField<KeyType, ValueType>(fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type, value: inout _ProtobufEnumMap<KeyType, ValueType>.BaseType) throws where ValueType.RawValue == Int
mutating func decodeMapField<KeyType, ValueType>(fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type, value: inout _ProtobufMessageMap<KeyType, ValueType>.BaseType) throws
// Decode extension fields
mutating func decodeExtensionField(values: inout ExtensionFieldValueSet, messageType: Message.Type, fieldNumber: Int) throws
// Run a decode loop decoding the MessageSet format for Extensions.
mutating func decodeExtensionFieldsAsMessageSet(values: inout ExtensionFieldValueSet,
messageType: Message.Type) throws
}
/// Most Decoders won't care about Extension handing as in MessageSet
/// format, so provide a default implementation simply looping on the
/// fieldNumbers and feeding through to extension decoding.
extension Decoder {
public mutating func decodeExtensionFieldsAsMessageSet(
values: inout ExtensionFieldValueSet,
messageType: Message.Type
) throws {
while let fieldNumber = try self.nextFieldNumber() {
try self.decodeExtensionField(values: &values,
messageType: messageType,
fieldNumber: fieldNumber)
}
}
}

View File

@ -0,0 +1,61 @@
// Sources/SwiftProtobuf/DoubleParser.swift - Generally useful mathematical functions
//
// Copyright (c) 2014 - 2019 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Numeric parsing helper for float and double strings
///
// -----------------------------------------------------------------------------
import Foundation
/// Support parsing float/double values from UTF-8
internal class DoubleParser {
// Temporary buffer so we can null-terminate the UTF-8 string
// before calling the C standard libray to parse it.
// In theory, JSON writers should be able to represent any IEEE Double
// in at most 25 bytes, but many writers will emit more digits than
// necessary, so we size this generously.
private var work =
UnsafeMutableBufferPointer<Int8>.allocate(capacity: 128)
deinit {
work.deallocate()
}
func utf8ToDouble(bytes: UnsafeRawBufferPointer,
start: UnsafeRawBufferPointer.Index,
end: UnsafeRawBufferPointer.Index) -> Double? {
return utf8ToDouble(bytes: UnsafeRawBufferPointer(rebasing: bytes[start..<end]))
}
func utf8ToDouble(bytes: UnsafeRawBufferPointer) -> Double? {
// Reject unreasonably long or short UTF8 number
if work.count <= bytes.count || bytes.count < 1 {
return nil
}
#if swift(>=4.1)
UnsafeMutableRawBufferPointer(work).copyMemory(from: bytes)
#else
UnsafeMutableRawBufferPointer(work).copyBytes(from: bytes)
#endif
work[bytes.count] = 0
// Use C library strtod() to parse it
var e: UnsafeMutablePointer<Int8>? = work.baseAddress
let d = strtod(work.baseAddress!, &e)
// Fail if strtod() did not consume everything we expected
// or if strtod() thought the number was out of range.
if e != work.baseAddress! + bytes.count || !d.isFinite {
return nil
}
return d
}
}

View File

@ -0,0 +1,93 @@
// Sources/SwiftProtobuf/Enum.swift - Enum support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Generated enums conform to SwiftProtobuf.Enum
///
/// See ProtobufTypes and JSONTypes for extension
/// methods to support binary and JSON coding.
///
// -----------------------------------------------------------------------------
/// Generated enum types conform to this protocol.
public protocol Enum: RawRepresentable, Hashable {
/// Creates a new instance of the enum initialized to its default value.
init()
/// Creates a new instance of the enum from the given raw integer value.
///
/// For proto2 enums, this initializer will fail if the raw value does not
/// correspond to a valid enum value. For proto3 enums, this initializer never
/// fails; unknown values are created as instances of the `UNRECOGNIZED` case.
///
/// - Parameter rawValue: The raw integer value from which to create the enum
/// value.
init?(rawValue: Int)
/// The raw integer value of the enum value.
///
/// For a recognized enum case, this is the integer value of the case as
/// defined in the .proto file. For `UNRECOGNIZED` cases in proto3, this is
/// the value that was originally decoded.
var rawValue: Int { get }
}
extension Enum {
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
hasher.combine(rawValue)
}
#else // swift(>=4.2)
public var hashValue: Int {
return rawValue
}
#endif // swift(>=4.2)
/// Internal convenience property representing the name of the enum value (or
/// `nil` if it is an `UNRECOGNIZED` value or doesn't provide names).
///
/// Since the text format and JSON names are always identical, we don't need
/// to distinguish them.
internal var name: _NameMap.Name? {
guard let nameProviding = Self.self as? _ProtoNameProviding.Type else {
return nil
}
return nameProviding._protobuf_nameMap.names(for: rawValue)?.proto
}
/// Internal convenience initializer that returns the enum value with the
/// given name, if it provides names.
///
/// Since the text format and JSON names are always identical, we don't need
/// to distinguish them.
///
/// - Parameter name: The name of the enum case.
internal init?(name: String) {
guard let nameProviding = Self.self as? _ProtoNameProviding.Type,
let number = nameProviding._protobuf_nameMap.number(forJSONName: name) else {
return nil
}
self.init(rawValue: number)
}
/// Internal convenience initializer that returns the enum value with the
/// given name, if it provides names.
///
/// Since the text format and JSON names are always identical, we don't need
/// to distinguish them.
///
/// - Parameter name: Buffer holding the UTF-8 bytes of the desired name.
internal init?(rawUTF8: UnsafeRawBufferPointer) {
guard let nameProviding = Self.self as? _ProtoNameProviding.Type,
let number = nameProviding._protobuf_nameMap.number(forJSONName: rawUTF8) else {
return nil
}
self.init(rawValue: number)
}
}

View File

@ -0,0 +1,73 @@
// Sources/SwiftProtobuf/ExtensibleMessage.swift - Extension support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Additional capabilities needed by messages that allow extensions.
///
// -----------------------------------------------------------------------------
// Messages that support extensions implement this protocol
public protocol ExtensibleMessage: Message {
var _protobuf_extensionFieldValues: ExtensionFieldValueSet { get set }
}
extension ExtensibleMessage {
public mutating func setExtensionValue<F: ExtensionField>(ext: MessageExtension<F, Self>, value: F.ValueType) {
_protobuf_extensionFieldValues[ext.fieldNumber] = F(protobufExtension: ext, value: value)
}
public func getExtensionValue<F: ExtensionField>(ext: MessageExtension<F, Self>) -> F.ValueType? {
if let fieldValue = _protobuf_extensionFieldValues[ext.fieldNumber] as? F {
return fieldValue.value
}
return nil
}
public func hasExtensionValue<F: ExtensionField>(ext: MessageExtension<F, Self>) -> Bool {
return _protobuf_extensionFieldValues[ext.fieldNumber] is F
}
public mutating func clearExtensionValue<F: ExtensionField>(ext: MessageExtension<F, Self>) {
_protobuf_extensionFieldValues[ext.fieldNumber] = nil
}
}
// Additional specializations for the different types of repeated fields so
// setting them to an empty array clears them from the map.
extension ExtensibleMessage {
public mutating func setExtensionValue<T>(ext: MessageExtension<RepeatedExtensionField<T>, Self>, value: [T.BaseType]) {
_protobuf_extensionFieldValues[ext.fieldNumber] =
value.isEmpty ? nil : RepeatedExtensionField<T>(protobufExtension: ext, value: value)
}
public mutating func setExtensionValue<T>(ext: MessageExtension<PackedExtensionField<T>, Self>, value: [T.BaseType]) {
_protobuf_extensionFieldValues[ext.fieldNumber] =
value.isEmpty ? nil : PackedExtensionField<T>(protobufExtension: ext, value: value)
}
public mutating func setExtensionValue<E>(ext: MessageExtension<RepeatedEnumExtensionField<E>, Self>, value: [E]) {
_protobuf_extensionFieldValues[ext.fieldNumber] =
value.isEmpty ? nil : RepeatedEnumExtensionField<E>(protobufExtension: ext, value: value)
}
public mutating func setExtensionValue<E>(ext: MessageExtension<PackedEnumExtensionField<E>, Self>, value: [E]) {
_protobuf_extensionFieldValues[ext.fieldNumber] =
value.isEmpty ? nil : PackedEnumExtensionField<E>(protobufExtension: ext, value: value)
}
public mutating func setExtensionValue<M>(ext: MessageExtension<RepeatedMessageExtensionField<M>, Self>, value: [M]) {
_protobuf_extensionFieldValues[ext.fieldNumber] =
value.isEmpty ? nil : RepeatedMessageExtensionField<M>(protobufExtension: ext, value: value)
}
public mutating func setExtensionValue<M>(ext: MessageExtension<RepeatedGroupExtensionField<M>, Self>, value: [M]) {
_protobuf_extensionFieldValues[ext.fieldNumber] =
value.isEmpty ? nil : RepeatedGroupExtensionField<M>(protobufExtension: ext, value: value)
}
}

View File

@ -0,0 +1,89 @@
// Sources/SwiftProtobuf/ExtensionFieldValueSet.swift - Extension support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// A collection of extension field values on a particular object.
/// This is only used within messages to manage the values of extension fields;
/// it does not need to be very sophisticated.
///
// -----------------------------------------------------------------------------
public struct ExtensionFieldValueSet: Hashable {
fileprivate var values = [Int : AnyExtensionField]()
public static func ==(lhs: ExtensionFieldValueSet,
rhs: ExtensionFieldValueSet) -> Bool {
guard lhs.values.count == rhs.values.count else {
return false
}
for (index, l) in lhs.values {
if let r = rhs.values[index] {
if type(of: l) != type(of: r) {
return false
}
if !l.isEqual(other: r) {
return false
}
} else {
return false
}
}
return true
}
public init() {}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
// AnyExtensionField is not Hashable, and the Self constraint that would
// add breaks some of the uses of it; so the only choice is to manually
// mix things in. However, one must remember to do things in an order
// independent manner.
var hash = 16777619
for (fieldNumber, v) in values {
var localHasher = hasher
localHasher.combine(fieldNumber)
v.hash(into: &localHasher)
hash = hash &+ localHasher.finalize()
}
hasher.combine(hash)
}
#else // swift(>=4.2)
public var hashValue: Int {
var hash = 16777619
for (fieldNumber, v) in values {
// Note: This calculation cannot depend on the order of the items.
hash = hash &+ fieldNumber &+ v.hashValue
}
return hash
}
#endif // swift(>=4.2)
public func traverse<V: Visitor>(visitor: inout V, start: Int, end: Int) throws {
let validIndexes = values.keys.filter {$0 >= start && $0 < end}
for i in validIndexes.sorted() {
let value = values[i]!
try value.traverse(visitor: &visitor)
}
}
public subscript(index: Int) -> AnyExtensionField? {
get { return values[index] }
set { values[index] = newValue }
}
public var isInitialized: Bool {
for (_, v) in values {
if !v.isInitialized {
return false
}
}
return true
}
}

View File

@ -0,0 +1,708 @@
// Sources/SwiftProtobuf/ExtensionFields.swift - Extension support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Core protocols implemented by generated extensions.
///
// -----------------------------------------------------------------------------
#if !swift(>=4.2)
private let i_2166136261 = Int(bitPattern: 2166136261)
private let i_16777619 = Int(16777619)
#endif
//
// Type-erased Extension field implementation.
// Note that it has no "self or associated type" references, so can
// be used as a protocol type. (In particular, although it does have
// a hashValue property, it cannot be Hashable.)
//
// This can encode, decode, return a hashValue and test for
// equality with some other extension field; but it's type-sealed
// so you can't actually access the contained value itself.
//
public protocol AnyExtensionField: CustomDebugStringConvertible {
#if swift(>=4.2)
func hash(into hasher: inout Hasher)
#else
var hashValue: Int { get }
#endif
var protobufExtension: AnyMessageExtension { get }
func isEqual(other: AnyExtensionField) -> Bool
/// Merging field decoding
mutating func decodeExtensionField<T: Decoder>(decoder: inout T) throws
/// Fields know their own type, so can dispatch to a visitor
func traverse<V: Visitor>(visitor: inout V) throws
/// Check if the field is initialized.
var isInitialized: Bool { get }
}
extension AnyExtensionField {
// Default implementation for extensions fields. The message types below provide
// custom versions.
public var isInitialized: Bool { return true }
}
///
/// The regular ExtensionField type exposes the value directly.
///
public protocol ExtensionField: AnyExtensionField, Hashable {
associatedtype ValueType
var value: ValueType { get set }
init(protobufExtension: AnyMessageExtension, value: ValueType)
init?<D: Decoder>(protobufExtension: AnyMessageExtension, decoder: inout D) throws
}
///
/// Singular field
///
public struct OptionalExtensionField<T: FieldType>: ExtensionField {
public typealias BaseType = T.BaseType
public typealias ValueType = BaseType
public var value: ValueType
public var protobufExtension: AnyMessageExtension
public static func ==(lhs: OptionalExtensionField,
rhs: OptionalExtensionField) -> Bool {
return lhs.value == rhs.value
}
public init(protobufExtension: AnyMessageExtension, value: ValueType) {
self.protobufExtension = protobufExtension
self.value = value
}
public var debugDescription: String {
get {
return String(reflecting: value)
}
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
hasher.combine(value)
}
#else // swift(>=4.2)
public var hashValue: Int {
get { return value.hashValue }
}
#endif // swift(>=4.2)
public func isEqual(other: AnyExtensionField) -> Bool {
let o = other as! OptionalExtensionField<T>
return self == o
}
public mutating func decodeExtensionField<D: Decoder>(decoder: inout D) throws {
var v: ValueType?
try T.decodeSingular(value: &v, from: &decoder)
if let v = v {
value = v
}
}
public init?<D: Decoder>(protobufExtension: AnyMessageExtension, decoder: inout D) throws {
var v: ValueType?
try T.decodeSingular(value: &v, from: &decoder)
if let v = v {
self.init(protobufExtension: protobufExtension, value: v)
} else {
return nil
}
}
public func traverse<V: Visitor>(visitor: inout V) throws {
try T.visitSingular(value: value, fieldNumber: protobufExtension.fieldNumber, with: &visitor)
}
}
///
/// Repeated fields
///
public struct RepeatedExtensionField<T: FieldType>: ExtensionField {
public typealias BaseType = T.BaseType
public typealias ValueType = [BaseType]
public var value: ValueType
public var protobufExtension: AnyMessageExtension
public static func ==(lhs: RepeatedExtensionField,
rhs: RepeatedExtensionField) -> Bool {
return lhs.value == rhs.value
}
public init(protobufExtension: AnyMessageExtension, value: ValueType) {
self.protobufExtension = protobufExtension
self.value = value
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
hasher.combine(value)
}
#else // swift(>=4.2)
public var hashValue: Int {
get {
var hash = i_2166136261
for e in value {
hash = (hash &* i_16777619) ^ e.hashValue
}
return hash
}
}
#endif // swift(>=4.2)
public func isEqual(other: AnyExtensionField) -> Bool {
let o = other as! RepeatedExtensionField<T>
return self == o
}
public var debugDescription: String {
return "[" + value.map{String(reflecting: $0)}.joined(separator: ",") + "]"
}
public mutating func decodeExtensionField<D: Decoder>(decoder: inout D) throws {
try T.decodeRepeated(value: &value, from: &decoder)
}
public init?<D: Decoder>(protobufExtension: AnyMessageExtension, decoder: inout D) throws {
var v: ValueType = []
try T.decodeRepeated(value: &v, from: &decoder)
self.init(protobufExtension: protobufExtension, value: v)
}
public func traverse<V: Visitor>(visitor: inout V) throws {
if value.count > 0 {
try T.visitRepeated(value: value, fieldNumber: protobufExtension.fieldNumber, with: &visitor)
}
}
}
///
/// Packed Repeated fields
///
/// TODO: This is almost (but not quite) identical to RepeatedFields;
/// find a way to collapse the implementations.
///
public struct PackedExtensionField<T: FieldType>: ExtensionField {
public typealias BaseType = T.BaseType
public typealias ValueType = [BaseType]
public var value: ValueType
public var protobufExtension: AnyMessageExtension
public static func ==(lhs: PackedExtensionField,
rhs: PackedExtensionField) -> Bool {
return lhs.value == rhs.value
}
public init(protobufExtension: AnyMessageExtension, value: ValueType) {
self.protobufExtension = protobufExtension
self.value = value
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
hasher.combine(value)
}
#else // swift(>=4.2)
public var hashValue: Int {
get {
var hash = i_2166136261
for e in value {
hash = (hash &* i_16777619) ^ e.hashValue
}
return hash
}
}
#endif // swift(>=4.2)
public func isEqual(other: AnyExtensionField) -> Bool {
let o = other as! PackedExtensionField<T>
return self == o
}
public var debugDescription: String {
return "[" + value.map{String(reflecting: $0)}.joined(separator: ",") + "]"
}
public mutating func decodeExtensionField<D: Decoder>(decoder: inout D) throws {
try T.decodeRepeated(value: &value, from: &decoder)
}
public init?<D: Decoder>(protobufExtension: AnyMessageExtension, decoder: inout D) throws {
var v: ValueType = []
try T.decodeRepeated(value: &v, from: &decoder)
self.init(protobufExtension: protobufExtension, value: v)
}
public func traverse<V: Visitor>(visitor: inout V) throws {
if value.count > 0 {
try T.visitPacked(value: value, fieldNumber: protobufExtension.fieldNumber, with: &visitor)
}
}
}
///
/// Enum extensions
///
public struct OptionalEnumExtensionField<E: Enum>: ExtensionField where E.RawValue == Int {
public typealias BaseType = E
public typealias ValueType = E
public var value: ValueType
public var protobufExtension: AnyMessageExtension
public static func ==(lhs: OptionalEnumExtensionField,
rhs: OptionalEnumExtensionField) -> Bool {
return lhs.value == rhs.value
}
public init(protobufExtension: AnyMessageExtension, value: ValueType) {
self.protobufExtension = protobufExtension
self.value = value
}
public var debugDescription: String {
get {
return String(reflecting: value)
}
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
hasher.combine(value)
}
#else // swift(>=4.2)
public var hashValue: Int {
get { return value.hashValue }
}
#endif // swift(>=4.2)
public func isEqual(other: AnyExtensionField) -> Bool {
let o = other as! OptionalEnumExtensionField<E>
return self == o
}
public mutating func decodeExtensionField<D: Decoder>(decoder: inout D) throws {
var v: ValueType?
try decoder.decodeSingularEnumField(value: &v)
if let v = v {
value = v
}
}
public init?<D: Decoder>(protobufExtension: AnyMessageExtension, decoder: inout D) throws {
var v: ValueType?
try decoder.decodeSingularEnumField(value: &v)
if let v = v {
self.init(protobufExtension: protobufExtension, value: v)
} else {
return nil
}
}
public func traverse<V: Visitor>(visitor: inout V) throws {
try visitor.visitSingularEnumField(
value: value,
fieldNumber: protobufExtension.fieldNumber)
}
}
///
/// Repeated Enum fields
///
public struct RepeatedEnumExtensionField<E: Enum>: ExtensionField where E.RawValue == Int {
public typealias BaseType = E
public typealias ValueType = [E]
public var value: ValueType
public var protobufExtension: AnyMessageExtension
public static func ==(lhs: RepeatedEnumExtensionField,
rhs: RepeatedEnumExtensionField) -> Bool {
return lhs.value == rhs.value
}
public init(protobufExtension: AnyMessageExtension, value: ValueType) {
self.protobufExtension = protobufExtension
self.value = value
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
hasher.combine(value)
}
#else // swift(>=4.2)
public var hashValue: Int {
get {
var hash = i_2166136261
for e in value {
hash = (hash &* i_16777619) ^ e.hashValue
}
return hash
}
}
#endif // swift(>=4.2)
public func isEqual(other: AnyExtensionField) -> Bool {
let o = other as! RepeatedEnumExtensionField<E>
return self == o
}
public var debugDescription: String {
return "[" + value.map{String(reflecting: $0)}.joined(separator: ",") + "]"
}
public mutating func decodeExtensionField<D: Decoder>(decoder: inout D) throws {
try decoder.decodeRepeatedEnumField(value: &value)
}
public init?<D: Decoder>(protobufExtension: AnyMessageExtension, decoder: inout D) throws {
var v: ValueType = []
try decoder.decodeRepeatedEnumField(value: &v)
self.init(protobufExtension: protobufExtension, value: v)
}
public func traverse<V: Visitor>(visitor: inout V) throws {
if value.count > 0 {
try visitor.visitRepeatedEnumField(
value: value,
fieldNumber: protobufExtension.fieldNumber)
}
}
}
///
/// Packed Repeated Enum fields
///
/// TODO: This is almost (but not quite) identical to RepeatedEnumFields;
/// find a way to collapse the implementations.
///
public struct PackedEnumExtensionField<E: Enum>: ExtensionField where E.RawValue == Int {
public typealias BaseType = E
public typealias ValueType = [E]
public var value: ValueType
public var protobufExtension: AnyMessageExtension
public static func ==(lhs: PackedEnumExtensionField,
rhs: PackedEnumExtensionField) -> Bool {
return lhs.value == rhs.value
}
public init(protobufExtension: AnyMessageExtension, value: ValueType) {
self.protobufExtension = protobufExtension
self.value = value
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
hasher.combine(value)
}
#else // swift(>=4.2)
public var hashValue: Int {
get {
var hash = i_2166136261
for e in value {
hash = (hash &* i_16777619) ^ e.hashValue
}
return hash
}
}
#endif // swift(>=4.2)
public func isEqual(other: AnyExtensionField) -> Bool {
let o = other as! PackedEnumExtensionField<E>
return self == o
}
public var debugDescription: String {
return "[" + value.map{String(reflecting: $0)}.joined(separator: ",") + "]"
}
public mutating func decodeExtensionField<D: Decoder>(decoder: inout D) throws {
try decoder.decodeRepeatedEnumField(value: &value)
}
public init?<D: Decoder>(protobufExtension: AnyMessageExtension, decoder: inout D) throws {
var v: ValueType = []
try decoder.decodeRepeatedEnumField(value: &v)
self.init(protobufExtension: protobufExtension, value: v)
}
public func traverse<V: Visitor>(visitor: inout V) throws {
if value.count > 0 {
try visitor.visitPackedEnumField(
value: value,
fieldNumber: protobufExtension.fieldNumber)
}
}
}
//
// ========== Message ==========
//
public struct OptionalMessageExtensionField<M: Message & Equatable>:
ExtensionField {
public typealias BaseType = M
public typealias ValueType = BaseType
public var value: ValueType
public var protobufExtension: AnyMessageExtension
public static func ==(lhs: OptionalMessageExtensionField,
rhs: OptionalMessageExtensionField) -> Bool {
return lhs.value == rhs.value
}
public init(protobufExtension: AnyMessageExtension, value: ValueType) {
self.protobufExtension = protobufExtension
self.value = value
}
public var debugDescription: String {
get {
return String(reflecting: value)
}
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
value.hash(into: &hasher)
}
#else // swift(>=4.2)
public var hashValue: Int {return value.hashValue}
#endif // swift(>=4.2)
public func isEqual(other: AnyExtensionField) -> Bool {
let o = other as! OptionalMessageExtensionField<M>
return self == o
}
public mutating func decodeExtensionField<D: Decoder>(decoder: inout D) throws {
var v: ValueType? = value
try decoder.decodeSingularMessageField(value: &v)
if let v = v {
self.value = v
}
}
public init?<D: Decoder>(protobufExtension: AnyMessageExtension, decoder: inout D) throws {
var v: ValueType?
try decoder.decodeSingularMessageField(value: &v)
if let v = v {
self.init(protobufExtension: protobufExtension, value: v)
} else {
return nil
}
}
public func traverse<V: Visitor>(visitor: inout V) throws {
try visitor.visitSingularMessageField(
value: value, fieldNumber: protobufExtension.fieldNumber)
}
public var isInitialized: Bool {
return value.isInitialized
}
}
public struct RepeatedMessageExtensionField<M: Message & Equatable>:
ExtensionField {
public typealias BaseType = M
public typealias ValueType = [BaseType]
public var value: ValueType
public var protobufExtension: AnyMessageExtension
public static func ==(lhs: RepeatedMessageExtensionField,
rhs: RepeatedMessageExtensionField) -> Bool {
return lhs.value == rhs.value
}
public init(protobufExtension: AnyMessageExtension, value: ValueType) {
self.protobufExtension = protobufExtension
self.value = value
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
for e in value {
e.hash(into: &hasher)
}
}
#else // swift(>=4.2)
public var hashValue: Int {
get {
var hash = i_2166136261
for e in value {
hash = (hash &* i_16777619) ^ e.hashValue
}
return hash
}
}
#endif // swift(>=4.2)
public func isEqual(other: AnyExtensionField) -> Bool {
let o = other as! RepeatedMessageExtensionField<M>
return self == o
}
public var debugDescription: String {
return "[" + value.map{String(reflecting: $0)}.joined(separator: ",") + "]"
}
public mutating func decodeExtensionField<D: Decoder>(decoder: inout D) throws {
try decoder.decodeRepeatedMessageField(value: &value)
}
public init?<D: Decoder>(protobufExtension: AnyMessageExtension, decoder: inout D) throws {
var v: ValueType = []
try decoder.decodeRepeatedMessageField(value: &v)
self.init(protobufExtension: protobufExtension, value: v)
}
public func traverse<V: Visitor>(visitor: inout V) throws {
if value.count > 0 {
try visitor.visitRepeatedMessageField(
value: value, fieldNumber: protobufExtension.fieldNumber)
}
}
public var isInitialized: Bool {
return Internal.areAllInitialized(value)
}
}
//
// ======== Groups within Messages ========
//
// Protoc internally treats groups the same as messages, but
// they serialize very differently, so we have separate serialization
// handling here...
public struct OptionalGroupExtensionField<G: Message & Hashable>:
ExtensionField {
public typealias BaseType = G
public typealias ValueType = BaseType
public var value: G
public var protobufExtension: AnyMessageExtension
public static func ==(lhs: OptionalGroupExtensionField,
rhs: OptionalGroupExtensionField) -> Bool {
return lhs.value == rhs.value
}
public init(protobufExtension: AnyMessageExtension, value: ValueType) {
self.protobufExtension = protobufExtension
self.value = value
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
hasher.combine(value)
}
#else // swift(>=4.2)
public var hashValue: Int {return value.hashValue}
#endif // swift(>=4.2)
public var debugDescription: String { get {return value.debugDescription} }
public func isEqual(other: AnyExtensionField) -> Bool {
let o = other as! OptionalGroupExtensionField<G>
return self == o
}
public mutating func decodeExtensionField<D: Decoder>(decoder: inout D) throws {
var v: ValueType? = value
try decoder.decodeSingularGroupField(value: &v)
if let v = v {
value = v
}
}
public init?<D: Decoder>(protobufExtension: AnyMessageExtension, decoder: inout D) throws {
var v: ValueType?
try decoder.decodeSingularGroupField(value: &v)
if let v = v {
self.init(protobufExtension: protobufExtension, value: v)
} else {
return nil
}
}
public func traverse<V: Visitor>(visitor: inout V) throws {
try visitor.visitSingularGroupField(
value: value, fieldNumber: protobufExtension.fieldNumber)
}
public var isInitialized: Bool {
return value.isInitialized
}
}
public struct RepeatedGroupExtensionField<G: Message & Hashable>:
ExtensionField {
public typealias BaseType = G
public typealias ValueType = [BaseType]
public var value: ValueType
public var protobufExtension: AnyMessageExtension
public static func ==(lhs: RepeatedGroupExtensionField,
rhs: RepeatedGroupExtensionField) -> Bool {
return lhs.value == rhs.value
}
public init(protobufExtension: AnyMessageExtension, value: ValueType) {
self.protobufExtension = protobufExtension
self.value = value
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
hasher.combine(value)
}
#else // swift(>=4.2)
public var hashValue: Int {
get {
var hash = i_2166136261
for e in value {
hash = (hash &* i_16777619) ^ e.hashValue
}
return hash
}
}
#endif // swift(>=4.2)
public var debugDescription: String {
return "[" + value.map{$0.debugDescription}.joined(separator: ",") + "]"
}
public func isEqual(other: AnyExtensionField) -> Bool {
let o = other as! RepeatedGroupExtensionField<G>
return self == o
}
public mutating func decodeExtensionField<D: Decoder>(decoder: inout D) throws {
try decoder.decodeRepeatedGroupField(value: &value)
}
public init?<D: Decoder>(protobufExtension: AnyMessageExtension, decoder: inout D) throws {
var v: ValueType = []
try decoder.decodeRepeatedGroupField(value: &v)
self.init(protobufExtension: protobufExtension, value: v)
}
public func traverse<V: Visitor>(visitor: inout V) throws {
if value.count > 0 {
try visitor.visitRepeatedGroupField(
value: value, fieldNumber: protobufExtension.fieldNumber)
}
}
public var isInitialized: Bool {
return Internal.areAllInitialized(value)
}
}

View File

@ -0,0 +1,38 @@
// Sources/SwiftProtobuf/ExtensionMap.swift - Extension support
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// A set of extensions that can be passed into deserializers
/// to provide details of the particular extensions that should
/// be recognized.
///
// -----------------------------------------------------------------------------
/// A collection of extension objects.
///
/// An `ExtensionMap` is used during decoding to look up
/// extension objects corresponding to the serialized data.
///
/// This is a protocol so that developers can build their own
/// extension handling if they need something more complex than the
/// standard `SimpleExtensionMap` implementation.
public protocol ExtensionMap {
/// Returns the extension object describing an extension or nil
subscript(messageType: Message.Type, fieldNumber: Int) -> AnyMessageExtension? { get }
/// Returns the field number for a message with a specific field name
///
/// The field name here matches the format used by the protobuf
/// Text serialization: it typically looks like
/// `package.message.field_name`, where `package` is the package
/// for the proto file and `message` is the name of the message in
/// which the extension was defined. (This is different from the
/// message that is being extended!)
func fieldNumberForProto(messageType: Message.Type, protoFieldName: String) -> Int?
}

View File

@ -0,0 +1,69 @@
// Sources/SwiftProtobuf/FieldTag.swift - Describes a binary field tag
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Types related to binary encoded tags (field numbers and wire formats).
///
// -----------------------------------------------------------------------------
/// Encapsulates the number and wire format of a field, which together form the
/// "tag".
///
/// This type also validates tags in that it will never allow a tag with an
/// improper field number (such as zero) or wire format (such as 6 or 7) to
/// exist. In other words, a `FieldTag`'s properties never need to be tested
/// for validity because they are guaranteed correct at initialization time.
internal struct FieldTag: RawRepresentable {
typealias RawValue = UInt32
/// The raw numeric value of the tag, which contains both the field number and
/// wire format.
let rawValue: UInt32
/// The field number component of the tag.
var fieldNumber: Int {
return Int(rawValue >> 3)
}
/// The wire format component of the tag.
var wireFormat: WireFormat {
// This force-unwrap is safe because there are only two initialization
// paths: one that takes a WireFormat directly (and is guaranteed valid at
// compile-time), or one that takes a raw value but which only lets valid
// wire formats through.
return WireFormat(rawValue: UInt8(rawValue & 7))!
}
/// A helper property that returns the number of bytes required to
/// varint-encode this tag.
var encodedSize: Int {
return Varint.encodedSize(of: rawValue)
}
/// Creates a new tag from its raw numeric representation.
///
/// Note that if the raw value given here is not a valid tag (for example, it
/// has an invalid wire format), this initializer will fail.
init?(rawValue: UInt32) {
// Verify that the field number and wire format are valid and fail if they
// are not.
guard rawValue & ~0x07 != 0,
let _ = WireFormat(rawValue: UInt8(rawValue % 8)) else {
return nil
}
self.rawValue = rawValue
}
/// Creates a new tag by composing the given field number and wire format.
init(fieldNumber: Int, wireFormat: WireFormat) {
self.rawValue = UInt32(truncatingIfNeeded: fieldNumber) << 3 |
UInt32(wireFormat.rawValue)
}
}

View File

@ -0,0 +1,412 @@
// Sources/SwiftProtobuf/FieldTypes.swift - Proto data types
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Serialization/deserialization support for each proto field type.
///
/// Note that we cannot just extend the standard Int32, etc, types
/// with serialization information since proto language supports
/// distinct types (with different codings) that use the same
/// in-memory representation. For example, proto "sint32" and
/// "sfixed32" both are represented in-memory as Int32.
///
/// These types are used generically and also passed into
/// various coding/decoding functions to provide type-specific
/// information.
///
// -----------------------------------------------------------------------------
import Foundation
// Note: The protobuf- and JSON-specific methods here are defined
// in ProtobufTypeAdditions.swift and JSONTypeAdditions.swift
public protocol FieldType {
// The Swift type used to store data for this field. For example,
// proto "sint32" fields use Swift "Int32" type.
associatedtype BaseType: Hashable
// The default value for this field type before it has been set.
// This is also used, for example, when JSON decodes a "null"
// value for a field.
static var proto3DefaultValue: BaseType { get }
// Generic reflector methods for looking up the correct
// encoding/decoding for extension fields, map keys, and map
// values.
static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws
static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws
static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws
static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws
static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws
}
///
/// Marker protocol for types that can be used as map keys
///
public protocol MapKeyType: FieldType {
}
///
/// Marker Protocol for types that can be used as map values.
///
public protocol MapValueType: FieldType {
}
//
// We have a struct for every basic proto field type which provides
// serialization/deserialization support as static methods.
//
///
/// Float traits
///
public struct ProtobufFloat: FieldType, MapValueType {
public typealias BaseType = Float
public static var proto3DefaultValue: Float {return 0.0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularFloatField(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedFloatField(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularFloatField(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedFloatField(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedFloatField(value: value, fieldNumber: fieldNumber)
}
}
///
/// Double
///
public struct ProtobufDouble: FieldType, MapValueType {
public typealias BaseType = Double
public static var proto3DefaultValue: Double {return 0.0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularDoubleField(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedDoubleField(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularDoubleField(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedDoubleField(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedDoubleField(value: value, fieldNumber: fieldNumber)
}
}
///
/// Int32
///
public struct ProtobufInt32: FieldType, MapKeyType, MapValueType {
public typealias BaseType = Int32
public static var proto3DefaultValue: Int32 {return 0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularInt32Field(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedInt32Field(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularInt32Field(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedInt32Field(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedInt32Field(value: value, fieldNumber: fieldNumber)
}
}
///
/// Int64
///
public struct ProtobufInt64: FieldType, MapKeyType, MapValueType {
public typealias BaseType = Int64
public static var proto3DefaultValue: Int64 {return 0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularInt64Field(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedInt64Field(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularInt64Field(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedInt64Field(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedInt64Field(value: value, fieldNumber: fieldNumber)
}
}
///
/// UInt32
///
public struct ProtobufUInt32: FieldType, MapKeyType, MapValueType {
public typealias BaseType = UInt32
public static var proto3DefaultValue: UInt32 {return 0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularUInt32Field(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedUInt32Field(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularUInt32Field(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedUInt32Field(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedUInt32Field(value: value, fieldNumber: fieldNumber)
}
}
///
/// UInt64
///
public struct ProtobufUInt64: FieldType, MapKeyType, MapValueType {
public typealias BaseType = UInt64
public static var proto3DefaultValue: UInt64 {return 0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularUInt64Field(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedUInt64Field(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularUInt64Field(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedUInt64Field(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedUInt64Field(value: value, fieldNumber: fieldNumber)
}
}
///
/// SInt32
///
public struct ProtobufSInt32: FieldType, MapKeyType, MapValueType {
public typealias BaseType = Int32
public static var proto3DefaultValue: Int32 {return 0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularSInt32Field(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedSInt32Field(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularSInt32Field(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedSInt32Field(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedSInt32Field(value: value, fieldNumber: fieldNumber)
}
}
///
/// SInt64
///
public struct ProtobufSInt64: FieldType, MapKeyType, MapValueType {
public typealias BaseType = Int64
public static var proto3DefaultValue: Int64 {return 0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularSInt64Field(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedSInt64Field(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularSInt64Field(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedSInt64Field(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedSInt64Field(value: value, fieldNumber: fieldNumber)
}
}
///
/// Fixed32
///
public struct ProtobufFixed32: FieldType, MapKeyType, MapValueType {
public typealias BaseType = UInt32
public static var proto3DefaultValue: UInt32 {return 0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularFixed32Field(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedFixed32Field(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularFixed32Field(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedFixed32Field(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedFixed32Field(value: value, fieldNumber: fieldNumber)
}
}
///
/// Fixed64
///
public struct ProtobufFixed64: FieldType, MapKeyType, MapValueType {
public typealias BaseType = UInt64
public static var proto3DefaultValue: UInt64 {return 0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularFixed64Field(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedFixed64Field(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularFixed64Field(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedFixed64Field(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedFixed64Field(value: value, fieldNumber: fieldNumber)
}
}
///
/// SFixed32
///
public struct ProtobufSFixed32: FieldType, MapKeyType, MapValueType {
public typealias BaseType = Int32
public static var proto3DefaultValue: Int32 {return 0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularSFixed32Field(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedSFixed32Field(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularSFixed32Field(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedSFixed32Field(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedSFixed32Field(value: value, fieldNumber: fieldNumber)
}
}
///
/// SFixed64
///
public struct ProtobufSFixed64: FieldType, MapKeyType, MapValueType {
public typealias BaseType = Int64
public static var proto3DefaultValue: Int64 {return 0}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularSFixed64Field(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedSFixed64Field(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularSFixed64Field(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedSFixed64Field(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedSFixed64Field(value: value, fieldNumber: fieldNumber)
}
}
///
/// Bool
///
public struct ProtobufBool: FieldType, MapKeyType, MapValueType {
public typealias BaseType = Bool
public static var proto3DefaultValue: Bool {return false}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularBoolField(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedBoolField(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularBoolField(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedBoolField(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitPackedBoolField(value: value, fieldNumber: fieldNumber)
}
}
///
/// String
///
public struct ProtobufString: FieldType, MapKeyType, MapValueType {
public typealias BaseType = String
public static var proto3DefaultValue: String {return String()}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularStringField(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedStringField(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularStringField(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedStringField(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
assert(false)
}
}
///
/// Bytes
///
public struct ProtobufBytes: FieldType, MapValueType {
public typealias BaseType = Data
public static var proto3DefaultValue: Data {return Data()}
public static func decodeSingular<D: Decoder>(value: inout BaseType?, from decoder: inout D) throws {
try decoder.decodeSingularBytesField(value: &value)
}
public static func decodeRepeated<D: Decoder>(value: inout [BaseType], from decoder: inout D) throws {
try decoder.decodeRepeatedBytesField(value: &value)
}
public static func visitSingular<V: Visitor>(value: BaseType, fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitSingularBytesField(value: value, fieldNumber: fieldNumber)
}
public static func visitRepeated<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
try visitor.visitRepeatedBytesField(value: value, fieldNumber: fieldNumber)
}
public static func visitPacked<V: Visitor>(value: [BaseType], fieldNumber: Int, with visitor: inout V) throws {
assert(false)
}
}

View File

@ -0,0 +1,143 @@
// Sources/SwiftProtobuf/Google_Protobuf_Any+Extensions.swift - Well-known Any type
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extends the `Google_Protobuf_Any` type with various custom behaviors.
///
// -----------------------------------------------------------------------------
// Explicit import of Foundation is necessary on Linux,
// don't remove unless obsolete on all platforms
import Foundation
public let defaultAnyTypeURLPrefix: String = "type.googleapis.com"
extension Google_Protobuf_Any {
/// Initialize an Any object from the provided message.
///
/// This corresponds to the `pack` operation in the C++ API.
///
/// Unlike the C++ implementation, the message is not immediately
/// serialized; it is merely stored until the Any object itself
/// needs to be serialized. This design avoids unnecessary
/// decoding/recoding when writing JSON format.
///
/// - Parameters:
/// - partial: If `false` (the default), this method will check
/// `Message.isInitialized` before encoding to verify that all required
/// fields are present. If any are missing, this method throws
/// `BinaryEncodingError.missingRequiredFields`.
/// - typePrefix: The prefix to be used when building the `type_url`.
/// Defaults to "type.googleapis.com".
/// - Throws: `BinaryEncodingError.missingRequiredFields` if `partial` is
/// false and `message` wasn't fully initialized.
public init(
message: Message,
partial: Bool = false,
typePrefix: String = defaultAnyTypeURLPrefix
) throws {
if !partial && !message.isInitialized {
throw BinaryEncodingError.missingRequiredFields
}
self.init()
typeURL = buildTypeURL(forMessage:message, typePrefix: typePrefix)
_storage.state = .message(message)
}
/// Creates a new `Google_Protobuf_Any` by decoding the given string
/// containing a serialized message in Protocol Buffer text format.
///
/// - Parameters:
/// - textFormatString: The text format string to decode.
/// - extensions: An `ExtensionMap` used to look up and decode any
/// extensions in this message or messages nested within this message's
/// fields.
/// - Throws: an instance of `TextFormatDecodingError` on failure.
public init(
textFormatString: String,
extensions: ExtensionMap? = nil
) throws {
self.init()
if !textFormatString.isEmpty {
if let data = textFormatString.data(using: String.Encoding.utf8) {
try data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
var textDecoder = try TextFormatDecoder(
messageType: Google_Protobuf_Any.self,
utf8Pointer: baseAddress,
count: body.count,
extensions: extensions)
try decodeTextFormat(decoder: &textDecoder)
if !textDecoder.complete {
throw TextFormatDecodingError.trailingGarbage
}
}
}
}
}
}
/// Returns true if this `Google_Protobuf_Any` message contains the given
/// message type.
///
/// The check is performed by looking at the passed `Message.Type` and the
/// `typeURL` of this message.
///
/// - Parameter type: The concrete message type.
/// - Returns: True if the receiver contains the given message type.
public func isA<M: Message>(_ type: M.Type) -> Bool {
return _storage.isA(type)
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
_storage.hash(into: &hasher)
}
#else // swift(>=4.2)
public var hashValue: Int {
return _storage.hashValue
}
#endif // swift(>=4.2)
}
extension Google_Protobuf_Any {
internal func textTraverse(visitor: inout TextFormatEncodingVisitor) {
_storage.textTraverse(visitor: &visitor)
try! unknownFields.traverse(visitor: &visitor)
}
}
extension Google_Protobuf_Any: _CustomJSONCodable {
// Custom text format decoding support for Any objects.
// (Note: This is not a part of any protocol; it's invoked
// directly from TextFormatDecoder whenever it sees an attempt
// to decode an Any object)
internal mutating func decodeTextFormat(
decoder: inout TextFormatDecoder
) throws {
// First, check if this uses the "verbose" Any encoding.
// If it does, and we have the type available, we can
// eagerly decode the contained Message object.
if let url = try decoder.scanner.nextOptionalAnyURL() {
try _uniqueStorage().decodeTextFormat(typeURL: url, decoder: &decoder)
} else {
// This is not using the specialized encoding, so we can use the
// standard path to decode the binary value.
try decodeMessage(decoder: &decoder)
}
}
internal func encodedJSONString(options: JSONEncodingOptions) throws -> String {
return try _storage.encodedJSONString(options: options)
}
internal mutating func decodeJSON(from decoder: inout JSONDecoder) throws {
try _uniqueStorage().decodeJSON(from: &decoder)
}
}

View File

@ -0,0 +1,135 @@
// Sources/SwiftProtobuf/Google_Protobuf_Any+Registry.swift - Registry for JSON support
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Support for registering and looking up Message types. Used
/// in support of Google_Protobuf_Any.
///
// -----------------------------------------------------------------------------
import Foundation
import Dispatch
// TODO: Should these first four be exposed as methods to go with
// the general registry support?
internal func buildTypeURL(forMessage message: Message, typePrefix: String) -> String {
var url = typePrefix
let needsSlash = typePrefix.isEmpty || typePrefix.last != "/"
if needsSlash {
url += "/"
}
return url + typeName(fromMessage: message)
}
internal func typeName(fromMessage message: Message) -> String {
let messageType = type(of: message)
return messageType.protoMessageName
}
internal func typeName(fromURL s: String) -> String {
var typeStart = s.startIndex
var i = typeStart
while i < s.endIndex {
let c = s[i]
i = s.index(after: i)
if c == "/" {
typeStart = i
}
}
return String(s[typeStart..<s.endIndex])
}
fileprivate var serialQueue = DispatchQueue(label: "org.swift.protobuf.typeRegistry")
// All access to this should be done on `serialQueue`.
fileprivate var knownTypes: [String:Message.Type] = [
// Seeded with the Well Known Types.
"google.protobuf.Any": Google_Protobuf_Any.self,
"google.protobuf.BoolValue": Google_Protobuf_BoolValue.self,
"google.protobuf.BytesValue": Google_Protobuf_BytesValue.self,
"google.protobuf.DoubleValue": Google_Protobuf_DoubleValue.self,
"google.protobuf.Duration": Google_Protobuf_Duration.self,
"google.protobuf.Empty": Google_Protobuf_Empty.self,
"google.protobuf.FieldMask": Google_Protobuf_FieldMask.self,
"google.protobuf.FloatValue": Google_Protobuf_FloatValue.self,
"google.protobuf.Int32Value": Google_Protobuf_Int32Value.self,
"google.protobuf.Int64Value": Google_Protobuf_Int64Value.self,
"google.protobuf.ListValue": Google_Protobuf_ListValue.self,
"google.protobuf.StringValue": Google_Protobuf_StringValue.self,
"google.protobuf.Struct": Google_Protobuf_Struct.self,
"google.protobuf.Timestamp": Google_Protobuf_Timestamp.self,
"google.protobuf.UInt32Value": Google_Protobuf_UInt32Value.self,
"google.protobuf.UInt64Value": Google_Protobuf_UInt64Value.self,
"google.protobuf.Value": Google_Protobuf_Value.self,
]
extension Google_Protobuf_Any {
/// Register a message type so that Any objects can use
/// them for decoding contents.
///
/// This is currently only required in two cases:
///
/// * When decoding Protobuf Text format. Currently,
/// Any objects do not defer deserialization from Text
/// format. Depending on how the Any objects are stored
/// in text format, the Any object may need to look up
/// the message type in order to deserialize itself.
///
/// * When re-encoding an Any object into a different
/// format than it was decoded from. For example, if
/// you decode a message containing an Any object from
/// JSON format and then re-encode the message into Protobuf
/// Binary format, the Any object will need to complete the
/// deferred deserialization of the JSON object before it
/// can re-encode.
///
/// Note that well-known types are pre-registered for you and
/// you do not need to register them from your code.
///
/// Also note that this is not needed if you only decode and encode
/// to and from the same format.
///
/// Returns: true if the type was registered, false if something
/// else was already registered for the messageName.
@discardableResult public static func register(messageType: Message.Type) -> Bool {
let messageTypeName = messageType.protoMessageName
var result: Bool = false
serialQueue.sync {
if let alreadyRegistered = knownTypes[messageTypeName] {
// Success/failure when something was already registered is
// based on if they are registering the same class or trying
// to register a different type
result = alreadyRegistered == messageType
} else {
knownTypes[messageTypeName] = messageType
result = true
}
}
return result
}
/// Returns the Message.Type expected for the given type URL.
public static func messageType(forTypeURL url: String) -> Message.Type? {
let messageTypeName = typeName(fromURL: url)
return messageType(forMessageName: messageTypeName)
}
/// Returns the Message.Type expected for the given proto message name.
public static func messageType(forMessageName name: String) -> Message.Type? {
var result: Message.Type?
serialQueue.sync {
result = knownTypes[name]
}
return result
}
}

View File

@ -0,0 +1,234 @@
// Sources/SwiftProtobuf/Google_Protobuf_Duration+Extensions.swift - Extensions for Duration type
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extends the generated Duration struct with various custom behaviors:
/// * JSON coding and decoding
/// * Arithmetic operations
///
// -----------------------------------------------------------------------------
import Foundation
private let minDurationSeconds: Int64 = -maxDurationSeconds
private let maxDurationSeconds: Int64 = 315576000000
private func parseDuration(text: String) throws -> (Int64, Int32) {
var digits = [Character]()
var digitCount = 0
var total = 0
var chars = text.makeIterator()
var seconds: Int64?
var nanos: Int32 = 0
while let c = chars.next() {
switch c {
case "-":
// Only accept '-' as very first character
if total > 0 {
throw JSONDecodingError.malformedDuration
}
digits.append(c)
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9":
digits.append(c)
digitCount += 1
case ".":
if let _ = seconds {
throw JSONDecodingError.malformedDuration
}
let digitString = String(digits)
if let s = Int64(digitString),
s >= minDurationSeconds && s <= maxDurationSeconds {
seconds = s
} else {
throw JSONDecodingError.malformedDuration
}
digits.removeAll()
digitCount = 0
case "s":
if let seconds = seconds {
// Seconds already set, digits holds nanos
while (digitCount < 9) {
digits.append(Character("0"))
digitCount += 1
}
while digitCount > 9 {
digits.removeLast()
digitCount -= 1
}
let digitString = String(digits)
if let rawNanos = Int32(digitString) {
if seconds < 0 {
nanos = -rawNanos
} else {
nanos = rawNanos
}
} else {
throw JSONDecodingError.malformedDuration
}
} else {
// No fraction, we just have an integral number of seconds
let digitString = String(digits)
if let s = Int64(digitString),
s >= minDurationSeconds && s <= maxDurationSeconds {
seconds = s
} else {
throw JSONDecodingError.malformedDuration
}
}
// Fail if there are characters after 's'
if chars.next() != nil {
throw JSONDecodingError.malformedDuration
}
return (seconds!, nanos)
default:
throw JSONDecodingError.malformedDuration
}
total += 1
}
throw JSONDecodingError.malformedDuration
}
private func formatDuration(seconds: Int64, nanos: Int32) -> String? {
let (seconds, nanos) = normalizeForDuration(seconds: seconds, nanos: nanos)
guard seconds >= minDurationSeconds && seconds <= maxDurationSeconds else {
return nil
}
if nanos == 0 {
return String(format: "%llds", seconds)
} else if nanos % 1000000 == 0 {
return String(format: "%lld.%03ds", seconds, abs(nanos) / 1000000)
} else if nanos % 1000 == 0 {
return String(format: "%lld.%06ds", seconds, abs(nanos) / 1000)
} else {
return String(format: "%lld.%09ds", seconds, abs(nanos))
}
}
extension Google_Protobuf_Duration {
/// Creates a new `Google_Protobuf_Duration` equal to the given number of
/// seconds and nanoseconds.
///
/// - Parameter seconds: The number of seconds.
/// - Parameter nanos: The number of nanoseconds.
public init(seconds: Int64 = 0, nanos: Int32 = 0) {
self.init()
self.seconds = seconds
self.nanos = nanos
}
}
extension Google_Protobuf_Duration: _CustomJSONCodable {
mutating func decodeJSON(from decoder: inout JSONDecoder) throws {
let s = try decoder.scanner.nextQuotedString()
(seconds, nanos) = try parseDuration(text: s)
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
if let formatted = formatDuration(seconds: seconds, nanos: nanos) {
return "\"\(formatted)\""
} else {
throw JSONEncodingError.durationRange
}
}
}
extension Google_Protobuf_Duration: ExpressibleByFloatLiteral {
public typealias FloatLiteralType = Double
/// Creates a new `Google_Protobuf_Duration` from a floating point literal
/// that is interpreted as a duration in seconds, rounded to the nearest
/// nanosecond.
public init(floatLiteral value: Double) {
let sd = trunc(value)
let nd = round((value - sd) * TimeInterval(nanosPerSecond))
let (s, n) = normalizeForDuration(seconds: Int64(sd), nanos: Int32(nd))
self.init(seconds: s, nanos: n)
}
}
extension Google_Protobuf_Duration {
/// Creates a new `Google_Protobuf_Duration` that is equal to the given
/// `TimeInterval` (measured in seconds), rounded to the nearest nanosecond.
///
/// - Parameter timeInterval: The `TimeInterval`.
public init(timeInterval: TimeInterval) {
let sd = trunc(timeInterval)
let nd = round((timeInterval - sd) * TimeInterval(nanosPerSecond))
let (s, n) = normalizeForDuration(seconds: Int64(sd), nanos: Int32(nd))
self.init(seconds: s, nanos: n)
}
/// The `TimeInterval` (measured in seconds) equal to this duration.
public var timeInterval: TimeInterval {
return TimeInterval(self.seconds) +
TimeInterval(self.nanos) / TimeInterval(nanosPerSecond)
}
}
private func normalizeForDuration(
seconds: Int64,
nanos: Int32
) -> (seconds: Int64, nanos: Int32) {
var s = seconds
var n = nanos
// If the magnitude of n exceeds a second then
// we need to factor it into s instead.
if n >= nanosPerSecond || n <= -nanosPerSecond {
s += Int64(n / nanosPerSecond)
n = n % nanosPerSecond
}
// The Duration spec says that when s != 0, s and
// n must have the same sign.
if s > 0 && n < 0 {
n += nanosPerSecond
s -= 1
} else if s < 0 && n > 0 {
n -= nanosPerSecond
s += 1
}
return (seconds: s, nanos: n)
}
public prefix func - (
operand: Google_Protobuf_Duration
) -> Google_Protobuf_Duration {
let (s, n) = normalizeForDuration(seconds: -operand.seconds,
nanos: -operand.nanos)
return Google_Protobuf_Duration(seconds: s, nanos: n)
}
public func + (
lhs: Google_Protobuf_Duration,
rhs: Google_Protobuf_Duration
) -> Google_Protobuf_Duration {
let (s, n) = normalizeForDuration(seconds: lhs.seconds + rhs.seconds,
nanos: lhs.nanos + rhs.nanos)
return Google_Protobuf_Duration(seconds: s, nanos: n)
}
public func - (
lhs: Google_Protobuf_Duration,
rhs: Google_Protobuf_Duration
) -> Google_Protobuf_Duration {
let (s, n) = normalizeForDuration(seconds: lhs.seconds - rhs.seconds,
nanos: lhs.nanos - rhs.nanos)
return Google_Protobuf_Duration(seconds: s, nanos: n)
}
public func - (
lhs: Google_Protobuf_Timestamp,
rhs: Google_Protobuf_Timestamp
) -> Google_Protobuf_Duration {
let (s, n) = normalizeForDuration(seconds: lhs.seconds - rhs.seconds,
nanos: lhs.nanos - rhs.nanos)
return Google_Protobuf_Duration(seconds: s, nanos: n)
}

View File

@ -0,0 +1,163 @@
// Sources/SwiftProtobuf/Google_Protobuf_FieldMask+Extensions.swift - Fieldmask extensions
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extend the generated FieldMask message with customized JSON coding and
/// convenience methods.
///
// -----------------------------------------------------------------------------
// TODO: We should have utilities to apply a fieldmask to an arbitrary
// message, intersect two fieldmasks, etc.
private func ProtoToJSON(name: String) -> String? {
var jsonPath = String()
var chars = name.makeIterator()
while let c = chars.next() {
switch c {
case "_":
if let toupper = chars.next() {
switch toupper {
case "a"..."z":
jsonPath.append(String(toupper).uppercased())
default:
return nil
}
} else {
return nil
}
case "A"..."Z":
return nil
default:
jsonPath.append(c)
}
}
return jsonPath
}
private func JSONToProto(name: String) -> String? {
var path = String()
for c in name {
switch c {
case "_":
return nil
case "A"..."Z":
path.append(Character("_"))
path.append(String(c).lowercased())
default:
path.append(c)
}
}
return path
}
private func parseJSONFieldNames(names: String) -> [String]? {
// An empty field mask is the empty string (no paths).
guard !names.isEmpty else { return [] }
var fieldNameCount = 0
var fieldName = String()
var split = [String]()
for c in names {
switch c {
case ",":
if fieldNameCount == 0 {
return nil
}
if let pbName = JSONToProto(name: fieldName) {
split.append(pbName)
} else {
return nil
}
fieldName = String()
fieldNameCount = 0
default:
fieldName.append(c)
fieldNameCount += 1
}
}
if fieldNameCount == 0 { // Last field name can't be empty
return nil
}
if let pbName = JSONToProto(name: fieldName) {
split.append(pbName)
} else {
return nil
}
return split
}
extension Google_Protobuf_FieldMask {
/// Creates a new `Google_Protobuf_FieldMask` from the given array of paths.
///
/// The paths should match the names used in the .proto file, which may be
/// different than the corresponding Swift property names.
///
/// - Parameter protoPaths: The paths from which to create the field mask,
/// defined using the .proto names for the fields.
public init(protoPaths: [String]) {
self.init()
paths = protoPaths
}
/// Creates a new `Google_Protobuf_FieldMask` from the given paths.
///
/// The paths should match the names used in the .proto file, which may be
/// different than the corresponding Swift property names.
///
/// - Parameter protoPaths: The paths from which to create the field mask,
/// defined using the .proto names for the fields.
public init(protoPaths: String...) {
self.init(protoPaths: protoPaths)
}
/// Creates a new `Google_Protobuf_FieldMask` from the given paths.
///
/// The paths should match the JSON names of the fields, which may be
/// different than the corresponding Swift property names.
///
/// - Parameter jsonPaths: The paths from which to create the field mask,
/// defined using the JSON names for the fields.
public init?(jsonPaths: String...) {
// TODO: This should fail if any of the conversions from JSON fails
#if swift(>=4.1)
self.init(protoPaths: jsonPaths.compactMap(JSONToProto))
#else
self.init(protoPaths: jsonPaths.flatMap(JSONToProto))
#endif
}
// It would be nice if to have an initializer that accepted Swift property
// names, but translating between swift and protobuf/json property
// names is not entirely deterministic.
}
extension Google_Protobuf_FieldMask: _CustomJSONCodable {
mutating func decodeJSON(from decoder: inout JSONDecoder) throws {
let s = try decoder.scanner.nextQuotedString()
if let names = parseJSONFieldNames(names: s) {
paths = names
} else {
throw JSONDecodingError.malformedFieldMask
}
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
// Note: Proto requires alphanumeric field names, so there
// cannot be a ',' or '"' character to mess up this formatting.
var jsonPaths = [String]()
for p in paths {
if let jsonPath = ProtoToJSON(name: p) {
jsonPaths.append(jsonPath)
} else {
throw JSONEncodingError.fieldMaskConversion
}
}
return "\"" + jsonPaths.joined(separator: ",") + "\""
}
}

View File

@ -0,0 +1,80 @@
// Sources/SwiftProtobuf/Google_Protobuf_ListValue+Extensions.swift - ListValue extensions
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// ListValue is a well-known message type that can be used to parse or encode
/// arbitrary JSON arrays without a predefined schema.
///
// -----------------------------------------------------------------------------
extension Google_Protobuf_ListValue: ExpressibleByArrayLiteral {
// TODO: Give this a direct array interface by proxying the interesting
// bits down to values
public typealias Element = Google_Protobuf_Value
/// Creates a new `Google_Protobuf_ListValue` from an array literal containing
/// `Google_Protobuf_Value` elements.
public init(arrayLiteral elements: Element...) {
self.init(values: elements)
}
}
extension Google_Protobuf_ListValue: _CustomJSONCodable {
internal func encodedJSONString(options: JSONEncodingOptions) throws -> String {
var jsonEncoder = JSONEncoder()
jsonEncoder.append(text: "[")
var separator: StaticString = ""
for v in values {
jsonEncoder.append(staticText: separator)
try v.serializeJSONValue(to: &jsonEncoder, options: options)
separator = ","
}
jsonEncoder.append(text: "]")
return jsonEncoder.stringResult
}
internal mutating func decodeJSON(from decoder: inout JSONDecoder) throws {
if decoder.scanner.skipOptionalNull() {
return
}
try decoder.scanner.skipRequiredArrayStart()
if decoder.scanner.skipOptionalArrayEnd() {
return
}
while true {
var v = Google_Protobuf_Value()
try v.decodeJSON(from: &decoder)
values.append(v)
if decoder.scanner.skipOptionalArrayEnd() {
return
}
try decoder.scanner.skipRequiredComma()
}
}
}
extension Google_Protobuf_ListValue {
/// Creates a new `Google_Protobuf_ListValue` from the given array of
/// `Google_Protobuf_Value` elements.
///
/// - Parameter values: The list of `Google_Protobuf_Value` messages from
/// which to create the `Google_Protobuf_ListValue`.
public init(values: [Google_Protobuf_Value]) {
self.init()
self.values = values
}
/// Accesses the `Google_Protobuf_Value` at the specified position.
///
/// - Parameter index: The position of the element to access.
public subscript(index: Int) -> Google_Protobuf_Value {
get {return values[index]}
set(newValue) {values[index] = newValue}
}
}

View File

@ -0,0 +1,28 @@
// Sources/SwiftProtobuf/Google_Protobuf_NullValue+Extensions.swift - NullValue extensions
//
// Copyright (c) 2014 - 2020 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// NullValue is a well-known message type that can be used to parse or encode
/// JSON Null values.
///
// -----------------------------------------------------------------------------
extension Google_Protobuf_NullValue: _CustomJSONCodable {
internal func encodedJSONString(options: JSONEncodingOptions) throws -> String {
return "null"
}
internal mutating func decodeJSON(from decoder: inout JSONDecoder) throws {
if decoder.scanner.skipOptionalNull() {
return
}
}
static func decodedFromJSONNull() -> Google_Protobuf_NullValue? {
return .nullValue
}
}

View File

@ -0,0 +1,85 @@
// Sources/SwiftProtobuf/Google_Protobuf_Struct+Extensions.swift - Struct extensions
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Struct is a well-known message type that can be used to parse or encode
/// arbitrary JSON objects without a predefined schema.
///
// -----------------------------------------------------------------------------
extension Google_Protobuf_Struct: ExpressibleByDictionaryLiteral {
public typealias Key = String
public typealias Value = Google_Protobuf_Value
/// Creates a new `Google_Protobuf_Struct` from a dictionary of string keys to
/// values of type `Google_Protobuf_Value`.
public init(dictionaryLiteral: (String, Google_Protobuf_Value)...) {
self.init()
for (k,v) in dictionaryLiteral {
fields[k] = v
}
}
}
extension Google_Protobuf_Struct: _CustomJSONCodable {
internal func encodedJSONString(options: JSONEncodingOptions) throws -> String {
var jsonEncoder = JSONEncoder()
jsonEncoder.startObject()
var mapVisitor = JSONMapEncodingVisitor(encoder: jsonEncoder, options: options)
for (k,v) in fields {
try mapVisitor.visitSingularStringField(value: k, fieldNumber: 1)
try mapVisitor.visitSingularMessageField(value: v, fieldNumber: 2)
}
mapVisitor.encoder.endObject()
return mapVisitor.encoder.stringResult
}
internal mutating func decodeJSON(from decoder: inout JSONDecoder) throws {
try decoder.scanner.skipRequiredObjectStart()
if decoder.scanner.skipOptionalObjectEnd() {
return
}
while true {
let key = try decoder.scanner.nextQuotedString()
try decoder.scanner.skipRequiredColon()
var value = Google_Protobuf_Value()
try value.decodeJSON(from: &decoder)
fields[key] = value
if decoder.scanner.skipOptionalObjectEnd() {
return
}
try decoder.scanner.skipRequiredComma()
}
}
}
extension Google_Protobuf_Struct {
/// Creates a new `Google_Protobuf_Struct` from a dictionary of string keys to
/// values of type `Google_Protobuf_Value`.
///
/// - Parameter fields: The dictionary from field names to
/// `Google_Protobuf_Value` messages that should be used to create the
/// `Struct`.
public init(fields: [String: Google_Protobuf_Value]) {
self.init()
self.fields = fields
}
/// Accesses the `Google_Protobuf_Value` with the given key for reading and
/// writing.
///
/// This key-based subscript returns the `Value` for the given key if the key
/// is found in the `Struct`, or nil if the key is not found. If you assign
/// nil as the `Value` for the given key, the `Struct` removes that key and
/// its associated `Value`.
public subscript(key: String) -> Google_Protobuf_Value? {
get {return fields[key]}
set(newValue) {fields[key] = newValue}
}
}

View File

@ -0,0 +1,337 @@
// Sources/SwiftProtobuf/Google_Protobuf_Timestamp+Extensions.swift - Timestamp extensions
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extend the generated Timestamp message with customized JSON coding,
/// arithmetic operations, and convenience methods.
///
// -----------------------------------------------------------------------------
import Foundation
private let minTimestampSeconds: Int64 = -62135596800 // 0001-01-01T00:00:00Z
private let maxTimestampSeconds: Int64 = 253402300799 // 9999-12-31T23:59:59Z
// TODO: Add convenience methods to interoperate with standard
// date/time classes: an initializer that accepts Unix timestamp as
// Int or Double, an easy way to convert to/from Foundation's
// NSDateTime (on Apple platforms only?), others?
// Parse an RFC3339 timestamp into a pair of seconds-since-1970 and nanos.
private func parseTimestamp(s: String) throws -> (Int64, Int32) {
// Convert to an array of integer character values
let value = s.utf8.map{Int($0)}
if value.count < 20 {
throw JSONDecodingError.malformedTimestamp
}
// Since the format is fixed-layout, we can just decode
// directly as follows.
let zero = Int(48)
let nine = Int(57)
let dash = Int(45)
let colon = Int(58)
let plus = Int(43)
let letterT = Int(84)
let letterZ = Int(90)
let period = Int(46)
func fromAscii2(_ digit0: Int, _ digit1: Int) throws -> Int {
if digit0 < zero || digit0 > nine || digit1 < zero || digit1 > nine {
throw JSONDecodingError.malformedTimestamp
}
return digit0 * 10 + digit1 - 528
}
func fromAscii4(
_ digit0: Int,
_ digit1: Int,
_ digit2: Int,
_ digit3: Int
) throws -> Int {
if (digit0 < zero || digit0 > nine
|| digit1 < zero || digit1 > nine
|| digit2 < zero || digit2 > nine
|| digit3 < zero || digit3 > nine) {
throw JSONDecodingError.malformedTimestamp
}
return digit0 * 1000 + digit1 * 100 + digit2 * 10 + digit3 - 53328
}
// Year: 4 digits followed by '-'
let year = try fromAscii4(value[0], value[1], value[2], value[3])
if value[4] != dash || year < Int(1) || year > Int(9999) {
throw JSONDecodingError.malformedTimestamp
}
// Month: 2 digits followed by '-'
let month = try fromAscii2(value[5], value[6])
if value[7] != dash || month < Int(1) || month > Int(12) {
throw JSONDecodingError.malformedTimestamp
}
// Day: 2 digits followed by 'T'
let mday = try fromAscii2(value[8], value[9])
if value[10] != letterT || mday < Int(1) || mday > Int(31) {
throw JSONDecodingError.malformedTimestamp
}
// Hour: 2 digits followed by ':'
let hour = try fromAscii2(value[11], value[12])
if value[13] != colon || hour > Int(23) {
throw JSONDecodingError.malformedTimestamp
}
// Minute: 2 digits followed by ':'
let minute = try fromAscii2(value[14], value[15])
if value[16] != colon || minute > Int(59) {
throw JSONDecodingError.malformedTimestamp
}
// Second: 2 digits (following char is checked below)
let second = try fromAscii2(value[17], value[18])
if second > Int(61) {
throw JSONDecodingError.malformedTimestamp
}
// timegm() is almost entirely useless. It's nonexistent on
// some platforms, broken on others. Everything else I've tried
// is even worse. Hence the code below.
// (If you have a better way to do this, try it and see if it
// passes the test suite on both Linux and OS X.)
// Day of year
let mdayStart: [Int] = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
var yday = Int64(mdayStart[month - 1])
let isleap = (year % 400 == 0) || ((year % 100 != 0) && (year % 4 == 0))
if isleap && (month > 2) {
yday += 1
}
yday += Int64(mday - 1)
// Days since start of epoch (including leap days)
var daysSinceEpoch = yday
daysSinceEpoch += Int64(365 * year) - Int64(719527)
daysSinceEpoch += Int64((year - 1) / 4)
daysSinceEpoch -= Int64((year - 1) / 100)
daysSinceEpoch += Int64((year - 1) / 400)
// Second within day
var daySec = Int64(hour)
daySec *= 60
daySec += Int64(minute)
daySec *= 60
daySec += Int64(second)
// Seconds since start of epoch
let t = daysSinceEpoch * Int64(86400) + daySec
// After seconds, comes various optional bits
var pos = 19
var nanos: Int32 = 0
if value[pos] == period { // "." begins fractional seconds
pos += 1
var digitValue = 100000000
while pos < value.count && value[pos] >= zero && value[pos] <= nine {
nanos += Int32(digitValue * (value[pos] - zero))
digitValue /= 10
pos += 1
}
}
var seconds: Int64 = 0
// "+" or "-" starts Timezone offset
if value[pos] == plus || value[pos] == dash {
if pos + 6 > value.count {
throw JSONDecodingError.malformedTimestamp
}
let hourOffset = try fromAscii2(value[pos + 1], value[pos + 2])
let minuteOffset = try fromAscii2(value[pos + 4], value[pos + 5])
if hourOffset > Int(13) || minuteOffset > Int(59) || value[pos + 3] != colon {
throw JSONDecodingError.malformedTimestamp
}
var adjusted: Int64 = t
if value[pos] == plus {
adjusted -= Int64(hourOffset) * Int64(3600)
adjusted -= Int64(minuteOffset) * Int64(60)
} else {
adjusted += Int64(hourOffset) * Int64(3600)
adjusted += Int64(minuteOffset) * Int64(60)
}
if adjusted < minTimestampSeconds || adjusted > maxTimestampSeconds {
throw JSONDecodingError.malformedTimestamp
}
seconds = adjusted
pos += 6
} else if value[pos] == letterZ { // "Z" indicator for UTC
seconds = t
pos += 1
} else {
throw JSONDecodingError.malformedTimestamp
}
if pos != value.count {
throw JSONDecodingError.malformedTimestamp
}
return (seconds, nanos)
}
private func formatTimestamp(seconds: Int64, nanos: Int32) -> String? {
let (seconds, nanos) = normalizeForTimestamp(seconds: seconds, nanos: nanos)
guard seconds >= minTimestampSeconds && seconds <= maxTimestampSeconds else {
return nil
}
let (hh, mm, ss) = timeOfDayFromSecondsSince1970(seconds: seconds)
let (YY, MM, DD) = gregorianDateFromSecondsSince1970(seconds: seconds)
if nanos == 0 {
return String(format: "%04d-%02d-%02dT%02d:%02d:%02dZ",
YY, MM, DD, hh, mm, ss)
} else if nanos % 1000000 == 0 {
return String(format: "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
YY, MM, DD, hh, mm, ss, nanos / 1000000)
} else if nanos % 1000 == 0 {
return String(format: "%04d-%02d-%02dT%02d:%02d:%02d.%06dZ",
YY, MM, DD, hh, mm, ss, nanos / 1000)
} else {
return String(format: "%04d-%02d-%02dT%02d:%02d:%02d.%09dZ",
YY, MM, DD, hh, mm, ss, nanos)
}
}
extension Google_Protobuf_Timestamp {
/// Creates a new `Google_Protobuf_Timestamp` equal to the given number of
/// seconds and nanoseconds.
///
/// - Parameter seconds: The number of seconds.
/// - Parameter nanos: The number of nanoseconds.
public init(seconds: Int64 = 0, nanos: Int32 = 0) {
self.init()
self.seconds = seconds
self.nanos = nanos
}
}
extension Google_Protobuf_Timestamp: _CustomJSONCodable {
mutating func decodeJSON(from decoder: inout JSONDecoder) throws {
let s = try decoder.scanner.nextQuotedString()
(seconds, nanos) = try parseTimestamp(s: s)
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
if let formatted = formatTimestamp(seconds: seconds, nanos: nanos) {
return "\"\(formatted)\""
} else {
throw JSONEncodingError.timestampRange
}
}
}
extension Google_Protobuf_Timestamp {
/// Creates a new `Google_Protobuf_Timestamp` initialized relative to 00:00:00
/// UTC on 1 January 1970 by a given number of seconds.
///
/// - Parameter timeIntervalSince1970: The `TimeInterval`, interpreted as
/// seconds relative to 00:00:00 UTC on 1 January 1970.
public init(timeIntervalSince1970: TimeInterval) {
let sd = floor(timeIntervalSince1970)
let nd = round((timeIntervalSince1970 - sd) * TimeInterval(nanosPerSecond))
let (s, n) = normalizeForTimestamp(seconds: Int64(sd), nanos: Int32(nd))
self.init(seconds: s, nanos: n)
}
/// Creates a new `Google_Protobuf_Timestamp` initialized relative to 00:00:00
/// UTC on 1 January 2001 by a given number of seconds.
///
/// - Parameter timeIntervalSinceReferenceDate: The `TimeInterval`,
/// interpreted as seconds relative to 00:00:00 UTC on 1 January 2001.
public init(timeIntervalSinceReferenceDate: TimeInterval) {
let sd = floor(timeIntervalSinceReferenceDate)
let nd = round(
(timeIntervalSinceReferenceDate - sd) * TimeInterval(nanosPerSecond))
// The addition of timeIntervalBetween1970And... is deliberately delayed
// until the input is separated into an integer part and a fraction
// part, so that we don't unnecessarily lose precision.
let (s, n) = normalizeForTimestamp(
seconds: Int64(sd) + Int64(Date.timeIntervalBetween1970AndReferenceDate),
nanos: Int32(nd))
self.init(seconds: s, nanos: n)
}
/// Creates a new `Google_Protobuf_Timestamp` initialized to the same time as
/// the given `Date`.
///
/// - Parameter date: The `Date` with which to initialize the timestamp.
public init(date: Date) {
// Note: Internally, Date uses the "reference date," not the 1970 date.
// We use it when interacting with Dates so that Date doesn't perform
// any double arithmetic on our behalf, which might cost us precision.
self.init(
timeIntervalSinceReferenceDate: date.timeIntervalSinceReferenceDate)
}
/// The interval between the timestamp and 00:00:00 UTC on 1 January 1970.
public var timeIntervalSince1970: TimeInterval {
return TimeInterval(self.seconds) +
TimeInterval(self.nanos) / TimeInterval(nanosPerSecond)
}
/// The interval between the timestamp and 00:00:00 UTC on 1 January 2001.
public var timeIntervalSinceReferenceDate: TimeInterval {
return TimeInterval(
self.seconds - Int64(Date.timeIntervalBetween1970AndReferenceDate)) +
TimeInterval(self.nanos) / TimeInterval(nanosPerSecond)
}
/// A `Date` initialized to the same time as the timestamp.
public var date: Date {
return Date(
timeIntervalSinceReferenceDate: self.timeIntervalSinceReferenceDate)
}
}
private func normalizeForTimestamp(
seconds: Int64,
nanos: Int32
) -> (seconds: Int64, nanos: Int32) {
// The Timestamp spec says that nanos must be in the range [0, 999999999),
// as in actual modular arithmetic.
let s = seconds + Int64(div(nanos, nanosPerSecond))
let n = mod(nanos, nanosPerSecond)
return (seconds: s, nanos: n)
}
public func + (
lhs: Google_Protobuf_Timestamp,
rhs: Google_Protobuf_Duration
) -> Google_Protobuf_Timestamp {
let (s, n) = normalizeForTimestamp(seconds: lhs.seconds + rhs.seconds,
nanos: lhs.nanos + rhs.nanos)
return Google_Protobuf_Timestamp(seconds: s, nanos: n)
}
public func + (
lhs: Google_Protobuf_Duration,
rhs: Google_Protobuf_Timestamp
) -> Google_Protobuf_Timestamp {
let (s, n) = normalizeForTimestamp(seconds: lhs.seconds + rhs.seconds,
nanos: lhs.nanos + rhs.nanos)
return Google_Protobuf_Timestamp(seconds: s, nanos: n)
}
public func - (
lhs: Google_Protobuf_Timestamp,
rhs: Google_Protobuf_Duration
) -> Google_Protobuf_Timestamp {
let (s, n) = normalizeForTimestamp(seconds: lhs.seconds - rhs.seconds,
nanos: lhs.nanos - rhs.nanos)
return Google_Protobuf_Timestamp(seconds: s, nanos: n)
}

View File

@ -0,0 +1,163 @@
// Sources/SwiftProtobuf/Google_Protobuf_Value+Extensions.swift - Value extensions
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Value is a well-known message type that can be used to parse or encode
/// arbitrary JSON without a predefined schema.
///
// -----------------------------------------------------------------------------
extension Google_Protobuf_Value: ExpressibleByIntegerLiteral {
public typealias IntegerLiteralType = Int64
/// Creates a new `Google_Protobuf_Value` from an integer literal.
public init(integerLiteral value: Int64) {
self.init(kind: .numberValue(Double(value)))
}
}
extension Google_Protobuf_Value: ExpressibleByFloatLiteral {
public typealias FloatLiteralType = Double
/// Creates a new `Google_Protobuf_Value` from a floating point literal.
public init(floatLiteral value: Double) {
self.init(kind: .numberValue(value))
}
}
extension Google_Protobuf_Value: ExpressibleByBooleanLiteral {
public typealias BooleanLiteralType = Bool
/// Creates a new `Google_Protobuf_Value` from a boolean literal.
public init(booleanLiteral value: Bool) {
self.init(kind: .boolValue(value))
}
}
extension Google_Protobuf_Value: ExpressibleByStringLiteral {
public typealias StringLiteralType = String
public typealias ExtendedGraphemeClusterLiteralType = String
public typealias UnicodeScalarLiteralType = String
/// Creates a new `Google_Protobuf_Value` from a string literal.
public init(stringLiteral value: String) {
self.init(kind: .stringValue(value))
}
/// Creates a new `Google_Protobuf_Value` from a Unicode scalar literal.
public init(unicodeScalarLiteral value: String) {
self.init(kind: .stringValue(value))
}
/// Creates a new `Google_Protobuf_Value` from a character literal.
public init(extendedGraphemeClusterLiteral value: String) {
self.init(kind: .stringValue(value))
}
}
extension Google_Protobuf_Value: ExpressibleByNilLiteral {
/// Creates a new `Google_Protobuf_Value` from the nil literal.
public init(nilLiteral: ()) {
self.init(kind: .nullValue(.nullValue))
}
}
extension Google_Protobuf_Value: _CustomJSONCodable {
internal func encodedJSONString(options: JSONEncodingOptions) throws -> String {
var jsonEncoder = JSONEncoder()
try serializeJSONValue(to: &jsonEncoder, options: options)
return jsonEncoder.stringResult
}
internal mutating func decodeJSON(from decoder: inout JSONDecoder) throws {
let c = try decoder.scanner.peekOneCharacter()
switch c {
case "n":
if !decoder.scanner.skipOptionalNull() {
throw JSONDecodingError.failure
}
kind = .nullValue(.nullValue)
case "[":
var l = Google_Protobuf_ListValue()
try l.decodeJSON(from: &decoder)
kind = .listValue(l)
case "{":
var s = Google_Protobuf_Struct()
try s.decodeJSON(from: &decoder)
kind = .structValue(s)
case "t", "f":
let b = try decoder.scanner.nextBool()
kind = .boolValue(b)
case "\"":
let s = try decoder.scanner.nextQuotedString()
kind = .stringValue(s)
default:
let d = try decoder.scanner.nextDouble()
kind = .numberValue(d)
}
}
internal static func decodedFromJSONNull() -> Google_Protobuf_Value? {
return Google_Protobuf_Value(kind: .nullValue(.nullValue))
}
}
extension Google_Protobuf_Value {
/// Creates a new `Google_Protobuf_Value` with the given kind.
fileprivate init(kind: OneOf_Kind) {
self.init()
self.kind = kind
}
/// Creates a new `Google_Protobuf_Value` whose `kind` is `numberValue` with
/// the given floating-point value.
public init(numberValue: Double) {
self.init(kind: .numberValue(numberValue))
}
/// Creates a new `Google_Protobuf_Value` whose `kind` is `stringValue` with
/// the given string value.
public init(stringValue: String) {
self.init(kind: .stringValue(stringValue))
}
/// Creates a new `Google_Protobuf_Value` whose `kind` is `boolValue` with the
/// given boolean value.
public init(boolValue: Bool) {
self.init(kind: .boolValue(boolValue))
}
/// Creates a new `Google_Protobuf_Value` whose `kind` is `structValue` with
/// the given `Google_Protobuf_Struct` value.
public init(structValue: Google_Protobuf_Struct) {
self.init(kind: .structValue(structValue))
}
/// Creates a new `Google_Protobuf_Value` whose `kind` is `listValue` with the
/// given `Google_Struct_ListValue` value.
public init(listValue: Google_Protobuf_ListValue) {
self.init(kind: .listValue(listValue))
}
/// Writes out the JSON representation of the value to the given encoder.
internal func serializeJSONValue(
to encoder: inout JSONEncoder,
options: JSONEncodingOptions
) throws {
switch kind {
case .nullValue?: encoder.putNullValue()
case .numberValue(let v)?: encoder.putDoubleValue(value: v)
case .stringValue(let v)?: encoder.putStringValue(value: v)
case .boolValue(let v)?: encoder.putBoolValue(value: v)
case .structValue(let v)?: encoder.append(text: try v.jsonString(options: options))
case .listValue(let v)?: encoder.append(text: try v.jsonString(options: options))
case nil: throw JSONEncodingError.missingValue
}
}
}

View File

@ -0,0 +1,247 @@
// Sources/SwiftProtobuf/Google_Protobuf_Wrappers+Extensions.swift - Well-known wrapper type extensions
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extensions to the well-known types in wrapper.proto that customize the JSON
/// format of those messages and provide convenience initializers from literals.
///
// -----------------------------------------------------------------------------
import Foundation
/// Internal protocol that minimizes the code duplication across the multiple
/// wrapper types extended below.
protocol ProtobufWrapper {
/// The wrapped protobuf type (for example, `ProtobufDouble`).
associatedtype WrappedType: FieldType
/// Exposes the generated property to the extensions here.
var value: WrappedType.BaseType { get set }
/// Exposes the parameterless initializer to the extensions here.
init()
/// Creates a new instance of the wrapper with the given value.
init(_ value: WrappedType.BaseType)
}
extension ProtobufWrapper {
mutating func decodeJSON(from decoder: inout JSONDecoder) throws {
var v: WrappedType.BaseType?
try WrappedType.decodeSingular(value: &v, from: &decoder)
value = v ?? WrappedType.proto3DefaultValue
}
}
extension Google_Protobuf_DoubleValue:
ProtobufWrapper, ExpressibleByFloatLiteral, _CustomJSONCodable {
public typealias WrappedType = ProtobufDouble
public typealias FloatLiteralType = WrappedType.BaseType
public init(_ value: WrappedType.BaseType) {
self.init()
self.value = value
}
public init(floatLiteral: FloatLiteralType) {
self.init(floatLiteral)
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
if value.isFinite {
// Swift 4.2 and later guarantees that this is accurate
// enough to parse back to the exact value on the other end.
return value.description
} else {
// Protobuf-specific handling of NaN and infinities
var encoder = JSONEncoder()
encoder.putDoubleValue(value: value)
return encoder.stringResult
}
}
}
extension Google_Protobuf_FloatValue:
ProtobufWrapper, ExpressibleByFloatLiteral, _CustomJSONCodable {
public typealias WrappedType = ProtobufFloat
public typealias FloatLiteralType = Float
public init(_ value: WrappedType.BaseType) {
self.init()
self.value = value
}
public init(floatLiteral: FloatLiteralType) {
self.init(floatLiteral)
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
if value.isFinite {
// Swift 4.2 and later guarantees that this is accurate
// enough to parse back to the exact value on the other end.
return value.description
} else {
// Protobuf-specific handling of NaN and infinities
var encoder = JSONEncoder()
encoder.putFloatValue(value: value)
return encoder.stringResult
}
}
}
extension Google_Protobuf_Int64Value:
ProtobufWrapper, ExpressibleByIntegerLiteral, _CustomJSONCodable {
public typealias WrappedType = ProtobufInt64
public typealias IntegerLiteralType = WrappedType.BaseType
public init(_ value: WrappedType.BaseType) {
self.init()
self.value = value
}
public init(integerLiteral: IntegerLiteralType) {
self.init(integerLiteral)
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
return "\"" + String(value) + "\""
}
}
extension Google_Protobuf_UInt64Value:
ProtobufWrapper, ExpressibleByIntegerLiteral, _CustomJSONCodable {
public typealias WrappedType = ProtobufUInt64
public typealias IntegerLiteralType = WrappedType.BaseType
public init(_ value: WrappedType.BaseType) {
self.init()
self.value = value
}
public init(integerLiteral: IntegerLiteralType) {
self.init(integerLiteral)
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
return "\"" + String(value) + "\""
}
}
extension Google_Protobuf_Int32Value:
ProtobufWrapper, ExpressibleByIntegerLiteral, _CustomJSONCodable {
public typealias WrappedType = ProtobufInt32
public typealias IntegerLiteralType = WrappedType.BaseType
public init(_ value: WrappedType.BaseType) {
self.init()
self.value = value
}
public init(integerLiteral: IntegerLiteralType) {
self.init(integerLiteral)
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
return String(value)
}
}
extension Google_Protobuf_UInt32Value:
ProtobufWrapper, ExpressibleByIntegerLiteral, _CustomJSONCodable {
public typealias WrappedType = ProtobufUInt32
public typealias IntegerLiteralType = WrappedType.BaseType
public init(_ value: WrappedType.BaseType) {
self.init()
self.value = value
}
public init(integerLiteral: IntegerLiteralType) {
self.init(integerLiteral)
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
return String(value)
}
}
extension Google_Protobuf_BoolValue:
ProtobufWrapper, ExpressibleByBooleanLiteral, _CustomJSONCodable {
public typealias WrappedType = ProtobufBool
public typealias BooleanLiteralType = Bool
public init(_ value: WrappedType.BaseType) {
self.init()
self.value = value
}
public init(booleanLiteral: Bool) {
self.init(booleanLiteral)
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
return value ? "true" : "false"
}
}
extension Google_Protobuf_StringValue:
ProtobufWrapper, ExpressibleByStringLiteral, _CustomJSONCodable {
public typealias WrappedType = ProtobufString
public typealias StringLiteralType = String
public typealias ExtendedGraphemeClusterLiteralType = String
public typealias UnicodeScalarLiteralType = String
public init(_ value: WrappedType.BaseType) {
self.init()
self.value = value
}
public init(stringLiteral: String) {
self.init(stringLiteral)
}
public init(extendedGraphemeClusterLiteral: String) {
self.init(extendedGraphemeClusterLiteral)
}
public init(unicodeScalarLiteral: String) {
self.init(unicodeScalarLiteral)
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
var encoder = JSONEncoder()
encoder.putStringValue(value: value)
return encoder.stringResult
}
}
extension Google_Protobuf_BytesValue: ProtobufWrapper, _CustomJSONCodable {
public typealias WrappedType = ProtobufBytes
public init(_ value: WrappedType.BaseType) {
self.init()
self.value = value
}
func encodedJSONString(options: JSONEncodingOptions) throws -> String {
var encoder = JSONEncoder()
encoder.putBytesValue(value: value)
return encoder.stringResult
}
}

View File

@ -0,0 +1,426 @@
// Sources/SwiftProtobuf/HashVisitor.swift - Hashing support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Hashing is basically a serialization problem, so we can leverage the
/// generated traversal methods for that.
///
// -----------------------------------------------------------------------------
import Foundation
private let i_2166136261 = Int(bitPattern: 2166136261)
private let i_16777619 = Int(16777619)
/// Computes the hash of a message by visiting its fields recursively.
///
/// Note that because this visits every field, it has the potential to be slow
/// for large or deeply nested messages. Users who need to use such messages as
/// dictionary keys or set members can use a wrapper struct around the message
/// and use a custom Hashable implementation that looks at the subset of the
/// message fields they want to include.
internal struct HashVisitor: Visitor {
#if swift(>=4.2)
internal private(set) var hasher: Hasher
#else // swift(>=4.2)
// Roughly based on FNV hash: http://tools.ietf.org/html/draft-eastlake-fnv-03
private(set) var hashValue = i_2166136261
private mutating func mix(_ hash: Int) {
hashValue = (hashValue ^ hash) &* i_16777619
}
private mutating func mixMap<K, V: Hashable>(map: Dictionary<K,V>) {
var mapHash = 0
for (k, v) in map {
// Note: This calculation cannot depend on the order of the items.
mapHash = mapHash &+ (k.hashValue ^ v.hashValue)
}
mix(mapHash)
}
#endif // swift(>=4.2)
#if swift(>=4.2)
init(_ hasher: Hasher) {
self.hasher = hasher
}
#else
init() {}
#endif
mutating func visitUnknown(bytes: Data) throws {
#if swift(>=4.2)
hasher.combine(bytes)
#else
mix(bytes.hashValue)
#endif
}
mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
mix(value.hashValue)
#endif
}
mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
mix(value.hashValue)
#endif
}
mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
mix(value.hashValue)
#endif
}
mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
mix(value.hashValue)
#endif
}
mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
mix(value.hashValue)
#endif
}
mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
mix(value.hashValue)
#endif
}
mutating func visitSingularEnumField<E: Enum>(value: E,
fieldNumber: Int) {
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
mix(value.hashValue)
#endif
}
mutating func visitSingularMessageField<M: Message>(value: M, fieldNumber: Int) {
#if swift(>=4.2)
hasher.combine(fieldNumber)
value.hash(into: &hasher)
#else
mix(fieldNumber)
mix(value.hashValue)
#endif
}
mutating func visitRepeatedFloatField(value: [Float], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedDoubleField(value: [Double], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedSInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedSInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedBoolField(value: [Bool], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedStringField(value: [String], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedBytesField(value: [Data], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedMessageField<M: Message>(value: [M], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
for v in value {
v.hash(into: &hasher)
}
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitRepeatedGroupField<G: Message>(value: [G], fieldNumber: Int) throws {
assert(!value.isEmpty)
#if swift(>=4.2)
hasher.combine(fieldNumber)
for v in value {
v.hash(into: &hasher)
}
#else
mix(fieldNumber)
for v in value {
mix(v.hashValue)
}
#endif
}
mutating func visitMapField<KeyType, ValueType: MapValueType>(
fieldType: _ProtobufMap<KeyType, ValueType>.Type,
value: _ProtobufMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws {
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
mixMap(map: value)
#endif
}
mutating func visitMapField<KeyType, ValueType>(
fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
value: _ProtobufEnumMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws where ValueType.RawValue == Int {
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
mixMap(map: value)
#endif
}
mutating func visitMapField<KeyType, ValueType>(
fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
value: _ProtobufMessageMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws {
#if swift(>=4.2)
hasher.combine(fieldNumber)
hasher.combine(value)
#else
mix(fieldNumber)
mixMap(map: value)
#endif
}
}

View File

@ -0,0 +1,51 @@
// Sources/SwiftProtobuf/Internal.swift - Message support
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Internal helpers on Messages for the library. These are public
/// just so the generated code can call them, but shouldn't be called
/// by developers directly.
///
// -----------------------------------------------------------------------------
import Foundation
/// Functions that are public only because they are used by generated message
/// implementations. NOT INTENDED TO BE CALLED BY CLIENTS.
public enum Internal {
/// A singleton instance of an empty data that is used by the generated code
/// for default values. This is a performance enhancement to work around the
/// fact that the `Data` type in Swift involves a new heap allocation every
/// time an empty instance is initialized, instead of sharing a common empty
/// backing storage.
public static let emptyData = Data()
/// Helper to loop over a list of Messages to see if they are all
/// initialized (see Message.isInitialized for what that means).
public static func areAllInitialized(_ listOfMessages: [Message]) -> Bool {
for msg in listOfMessages {
if !msg.isInitialized {
return false
}
}
return true
}
/// Helper to loop over dictionary with values that are Messages to see if
/// they are all initialized (see Message.isInitialized for what that means).
public static func areAllInitialized<K>(_ mapToMessages: [K: Message]) -> Bool {
for (_, msg) in mapToMessages {
if !msg.isInitialized {
return false
}
}
return true
}
}

View File

@ -0,0 +1,735 @@
// Sources/SwiftProtobuf/JSONDecoder.swift - JSON format decoding
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// JSON format decoding engine.
///
// -----------------------------------------------------------------------------
import Foundation
internal struct JSONDecoder: Decoder {
internal var scanner: JSONScanner
internal var messageType: Message.Type
private var fieldCount = 0
private var isMapKey = false
private var fieldNameMap: _NameMap?
internal var options: JSONDecodingOptions {
return scanner.options
}
mutating func handleConflictingOneOf() throws {
throw JSONDecodingError.conflictingOneOf
}
internal init(source: UnsafeRawBufferPointer, options: JSONDecodingOptions,
messageType: Message.Type, extensions: ExtensionMap?) {
let scanner = JSONScanner(source: source,
options: options,
extensions: extensions)
self.init(scanner: scanner, messageType: messageType)
}
private init(scanner: JSONScanner, messageType: Message.Type) {
self.scanner = scanner
self.messageType = messageType
}
mutating func nextFieldNumber() throws -> Int? {
if scanner.skipOptionalObjectEnd() {
return nil
}
if fieldCount > 0 {
try scanner.skipRequiredComma()
}
let fieldNumber = try scanner.nextFieldNumber(names: fieldNameMap!,
messageType: messageType)
if let fieldNumber = fieldNumber {
fieldCount += 1
return fieldNumber
}
return nil
}
mutating func decodeSingularFloatField(value: inout Float) throws {
if scanner.skipOptionalNull() {
value = 0
return
}
value = try scanner.nextFloat()
}
mutating func decodeSingularFloatField(value: inout Float?) throws {
if scanner.skipOptionalNull() {
value = nil
return
}
value = try scanner.nextFloat()
}
mutating func decodeRepeatedFloatField(value: inout [Float]) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredArrayStart()
if scanner.skipOptionalArrayEnd() {
return
}
while true {
let n = try scanner.nextFloat()
value.append(n)
if scanner.skipOptionalArrayEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeSingularDoubleField(value: inout Double) throws {
if scanner.skipOptionalNull() {
value = 0
return
}
value = try scanner.nextDouble()
}
mutating func decodeSingularDoubleField(value: inout Double?) throws {
if scanner.skipOptionalNull() {
value = nil
return
}
value = try scanner.nextDouble()
}
mutating func decodeRepeatedDoubleField(value: inout [Double]) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredArrayStart()
if scanner.skipOptionalArrayEnd() {
return
}
while true {
let n = try scanner.nextDouble()
value.append(n)
if scanner.skipOptionalArrayEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeSingularInt32Field(value: inout Int32) throws {
if scanner.skipOptionalNull() {
value = 0
return
}
let n = try scanner.nextSInt()
if n > Int64(Int32.max) || n < Int64(Int32.min) {
throw JSONDecodingError.numberRange
}
value = Int32(truncatingIfNeeded: n)
}
mutating func decodeSingularInt32Field(value: inout Int32?) throws {
if scanner.skipOptionalNull() {
value = nil
return
}
let n = try scanner.nextSInt()
if n > Int64(Int32.max) || n < Int64(Int32.min) {
throw JSONDecodingError.numberRange
}
value = Int32(truncatingIfNeeded: n)
}
mutating func decodeRepeatedInt32Field(value: inout [Int32]) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredArrayStart()
if scanner.skipOptionalArrayEnd() {
return
}
while true {
let n = try scanner.nextSInt()
if n > Int64(Int32.max) || n < Int64(Int32.min) {
throw JSONDecodingError.numberRange
}
value.append(Int32(truncatingIfNeeded: n))
if scanner.skipOptionalArrayEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeSingularInt64Field(value: inout Int64) throws {
if scanner.skipOptionalNull() {
value = 0
return
}
value = try scanner.nextSInt()
}
mutating func decodeSingularInt64Field(value: inout Int64?) throws {
if scanner.skipOptionalNull() {
value = nil
return
}
value = try scanner.nextSInt()
}
mutating func decodeRepeatedInt64Field(value: inout [Int64]) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredArrayStart()
if scanner.skipOptionalArrayEnd() {
return
}
while true {
let n = try scanner.nextSInt()
value.append(n)
if scanner.skipOptionalArrayEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeSingularUInt32Field(value: inout UInt32) throws {
if scanner.skipOptionalNull() {
value = 0
return
}
let n = try scanner.nextUInt()
if n > UInt64(UInt32.max) {
throw JSONDecodingError.numberRange
}
value = UInt32(truncatingIfNeeded: n)
}
mutating func decodeSingularUInt32Field(value: inout UInt32?) throws {
if scanner.skipOptionalNull() {
value = nil
return
}
let n = try scanner.nextUInt()
if n > UInt64(UInt32.max) {
throw JSONDecodingError.numberRange
}
value = UInt32(truncatingIfNeeded: n)
}
mutating func decodeRepeatedUInt32Field(value: inout [UInt32]) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredArrayStart()
if scanner.skipOptionalArrayEnd() {
return
}
while true {
let n = try scanner.nextUInt()
if n > UInt64(UInt32.max) {
throw JSONDecodingError.numberRange
}
value.append(UInt32(truncatingIfNeeded: n))
if scanner.skipOptionalArrayEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeSingularUInt64Field(value: inout UInt64) throws {
if scanner.skipOptionalNull() {
value = 0
return
}
value = try scanner.nextUInt()
}
mutating func decodeSingularUInt64Field(value: inout UInt64?) throws {
if scanner.skipOptionalNull() {
value = nil
return
}
value = try scanner.nextUInt()
}
mutating func decodeRepeatedUInt64Field(value: inout [UInt64]) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredArrayStart()
if scanner.skipOptionalArrayEnd() {
return
}
while true {
let n = try scanner.nextUInt()
value.append(n)
if scanner.skipOptionalArrayEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeSingularSInt32Field(value: inout Int32) throws {
try decodeSingularInt32Field(value: &value)
}
mutating func decodeSingularSInt32Field(value: inout Int32?) throws {
try decodeSingularInt32Field(value: &value)
}
mutating func decodeRepeatedSInt32Field(value: inout [Int32]) throws {
try decodeRepeatedInt32Field(value: &value)
}
mutating func decodeSingularSInt64Field(value: inout Int64) throws {
try decodeSingularInt64Field(value: &value)
}
mutating func decodeSingularSInt64Field(value: inout Int64?) throws {
try decodeSingularInt64Field(value: &value)
}
mutating func decodeRepeatedSInt64Field(value: inout [Int64]) throws {
try decodeRepeatedInt64Field(value: &value)
}
mutating func decodeSingularFixed32Field(value: inout UInt32) throws {
try decodeSingularUInt32Field(value: &value)
}
mutating func decodeSingularFixed32Field(value: inout UInt32?) throws {
try decodeSingularUInt32Field(value: &value)
}
mutating func decodeRepeatedFixed32Field(value: inout [UInt32]) throws {
try decodeRepeatedUInt32Field(value: &value)
}
mutating func decodeSingularFixed64Field(value: inout UInt64) throws {
try decodeSingularUInt64Field(value: &value)
}
mutating func decodeSingularFixed64Field(value: inout UInt64?) throws {
try decodeSingularUInt64Field(value: &value)
}
mutating func decodeRepeatedFixed64Field(value: inout [UInt64]) throws {
try decodeRepeatedUInt64Field(value: &value)
}
mutating func decodeSingularSFixed32Field(value: inout Int32) throws {
try decodeSingularInt32Field(value: &value)
}
mutating func decodeSingularSFixed32Field(value: inout Int32?) throws {
try decodeSingularInt32Field(value: &value)
}
mutating func decodeRepeatedSFixed32Field(value: inout [Int32]) throws {
try decodeRepeatedInt32Field(value: &value)
}
mutating func decodeSingularSFixed64Field(value: inout Int64) throws {
try decodeSingularInt64Field(value: &value)
}
mutating func decodeSingularSFixed64Field(value: inout Int64?) throws {
try decodeSingularInt64Field(value: &value)
}
mutating func decodeRepeatedSFixed64Field(value: inout [Int64]) throws {
try decodeRepeatedInt64Field(value: &value)
}
mutating func decodeSingularBoolField(value: inout Bool) throws {
if scanner.skipOptionalNull() {
value = false
return
}
if isMapKey {
value = try scanner.nextQuotedBool()
} else {
value = try scanner.nextBool()
}
}
mutating func decodeSingularBoolField(value: inout Bool?) throws {
if scanner.skipOptionalNull() {
value = nil
return
}
if isMapKey {
value = try scanner.nextQuotedBool()
} else {
value = try scanner.nextBool()
}
}
mutating func decodeRepeatedBoolField(value: inout [Bool]) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredArrayStart()
if scanner.skipOptionalArrayEnd() {
return
}
while true {
let n = try scanner.nextBool()
value.append(n)
if scanner.skipOptionalArrayEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeSingularStringField(value: inout String) throws {
if scanner.skipOptionalNull() {
value = String()
return
}
value = try scanner.nextQuotedString()
}
mutating func decodeSingularStringField(value: inout String?) throws {
if scanner.skipOptionalNull() {
value = nil
return
}
value = try scanner.nextQuotedString()
}
mutating func decodeRepeatedStringField(value: inout [String]) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredArrayStart()
if scanner.skipOptionalArrayEnd() {
return
}
while true {
let n = try scanner.nextQuotedString()
value.append(n)
if scanner.skipOptionalArrayEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeSingularBytesField(value: inout Data) throws {
if scanner.skipOptionalNull() {
value = Data()
return
}
value = try scanner.nextBytesValue()
}
mutating func decodeSingularBytesField(value: inout Data?) throws {
if scanner.skipOptionalNull() {
value = nil
return
}
value = try scanner.nextBytesValue()
}
mutating func decodeRepeatedBytesField(value: inout [Data]) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredArrayStart()
if scanner.skipOptionalArrayEnd() {
return
}
while true {
let n = try scanner.nextBytesValue()
value.append(n)
if scanner.skipOptionalArrayEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeSingularEnumField<E: Enum>(value: inout E?) throws
where E.RawValue == Int {
if scanner.skipOptionalNull() {
if let customDecodable = E.self as? _CustomJSONCodable.Type {
value = try customDecodable.decodedFromJSONNull() as? E
return
}
value = nil
return
}
value = try scanner.nextEnumValue() as E
}
mutating func decodeSingularEnumField<E: Enum>(value: inout E) throws
where E.RawValue == Int {
if scanner.skipOptionalNull() {
if let customDecodable = E.self as? _CustomJSONCodable.Type {
value = try customDecodable.decodedFromJSONNull() as! E
return
}
value = E()
return
}
value = try scanner.nextEnumValue()
}
mutating func decodeRepeatedEnumField<E: Enum>(value: inout [E]) throws
where E.RawValue == Int {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredArrayStart()
if scanner.skipOptionalArrayEnd() {
return
}
let maybeCustomDecodable = E.self as? _CustomJSONCodable.Type
while true {
if scanner.skipOptionalNull() {
if let customDecodable = maybeCustomDecodable {
let e = try customDecodable.decodedFromJSONNull() as! E
value.append(e)
} else {
throw JSONDecodingError.illegalNull
}
} else {
let e: E = try scanner.nextEnumValue()
value.append(e)
}
if scanner.skipOptionalArrayEnd() {
return
}
try scanner.skipRequiredComma()
}
}
internal mutating func decodeFullObject<M: Message>(message: inout M) throws {
guard let nameProviding = (M.self as? _ProtoNameProviding.Type) else {
throw JSONDecodingError.missingFieldNames
}
fieldNameMap = nameProviding._protobuf_nameMap
if let m = message as? _CustomJSONCodable {
var customCodable = m
try customCodable.decodeJSON(from: &self)
message = customCodable as! M
} else {
try scanner.skipRequiredObjectStart()
if scanner.skipOptionalObjectEnd() {
return
}
try message.decodeMessage(decoder: &self)
}
}
mutating func decodeSingularMessageField<M: Message>(value: inout M?) throws {
if scanner.skipOptionalNull() {
if M.self is _CustomJSONCodable.Type {
value =
try (M.self as! _CustomJSONCodable.Type).decodedFromJSONNull() as? M
return
}
// All other message field types treat 'null' as an unset
value = nil
return
}
if value == nil {
value = M()
}
var subDecoder = JSONDecoder(scanner: scanner, messageType: M.self)
try subDecoder.decodeFullObject(message: &value!)
assert(scanner.recursionBudget == subDecoder.scanner.recursionBudget)
scanner = subDecoder.scanner
}
mutating func decodeRepeatedMessageField<M: Message>(
value: inout [M]
) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredArrayStart()
if scanner.skipOptionalArrayEnd() {
return
}
while true {
if scanner.skipOptionalNull() {
var appended = false
if M.self is _CustomJSONCodable.Type {
if let message = try (M.self as! _CustomJSONCodable.Type)
.decodedFromJSONNull() as? M {
value.append(message)
appended = true
}
}
if !appended {
throw JSONDecodingError.illegalNull
}
} else {
var message = M()
var subDecoder = JSONDecoder(scanner: scanner, messageType: M.self)
try subDecoder.decodeFullObject(message: &message)
value.append(message)
assert(scanner.recursionBudget == subDecoder.scanner.recursionBudget)
scanner = subDecoder.scanner
}
if scanner.skipOptionalArrayEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeSingularGroupField<G: Message>(value: inout G?) throws {
throw JSONDecodingError.schemaMismatch
}
mutating func decodeRepeatedGroupField<G: Message>(value: inout [G]) throws {
throw JSONDecodingError.schemaMismatch
}
mutating func decodeMapField<KeyType, ValueType: MapValueType>(
fieldType: _ProtobufMap<KeyType, ValueType>.Type,
value: inout _ProtobufMap<KeyType, ValueType>.BaseType
) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredObjectStart()
if scanner.skipOptionalObjectEnd() {
return
}
while true {
// Next character must be double quote, because
// map keys must always be quoted strings.
let c = try scanner.peekOneCharacter()
if c != "\"" {
throw JSONDecodingError.unquotedMapKey
}
isMapKey = true
var keyField: KeyType.BaseType?
try KeyType.decodeSingular(value: &keyField, from: &self)
isMapKey = false
try scanner.skipRequiredColon()
var valueField: ValueType.BaseType?
try ValueType.decodeSingular(value: &valueField, from: &self)
if let keyField = keyField, let valueField = valueField {
value[keyField] = valueField
} else {
throw JSONDecodingError.malformedMap
}
if scanner.skipOptionalObjectEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeMapField<KeyType, ValueType>(
fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
value: inout _ProtobufEnumMap<KeyType, ValueType>.BaseType
) throws where ValueType.RawValue == Int {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredObjectStart()
if scanner.skipOptionalObjectEnd() {
return
}
while true {
// Next character must be double quote, because
// map keys must always be quoted strings.
let c = try scanner.peekOneCharacter()
if c != "\"" {
throw JSONDecodingError.unquotedMapKey
}
isMapKey = true
var keyField: KeyType.BaseType?
try KeyType.decodeSingular(value: &keyField, from: &self)
isMapKey = false
try scanner.skipRequiredColon()
var valueField: ValueType?
try decodeSingularEnumField(value: &valueField)
if let keyField = keyField, let valueField = valueField {
value[keyField] = valueField
} else {
throw JSONDecodingError.malformedMap
}
if scanner.skipOptionalObjectEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeMapField<KeyType, ValueType>(
fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
value: inout _ProtobufMessageMap<KeyType, ValueType>.BaseType
) throws {
if scanner.skipOptionalNull() {
return
}
try scanner.skipRequiredObjectStart()
if scanner.skipOptionalObjectEnd() {
return
}
while true {
// Next character must be double quote, because
// map keys must always be quoted strings.
let c = try scanner.peekOneCharacter()
if c != "\"" {
throw JSONDecodingError.unquotedMapKey
}
isMapKey = true
var keyField: KeyType.BaseType?
try KeyType.decodeSingular(value: &keyField, from: &self)
isMapKey = false
try scanner.skipRequiredColon()
var valueField: ValueType?
try decodeSingularMessageField(value: &valueField)
if let keyField = keyField, let valueField = valueField {
value[keyField] = valueField
} else {
throw JSONDecodingError.malformedMap
}
if scanner.skipOptionalObjectEnd() {
return
}
try scanner.skipRequiredComma()
}
}
mutating func decodeExtensionField(
values: inout ExtensionFieldValueSet,
messageType: Message.Type,
fieldNumber: Int
) throws {
// Force-unwrap: we can only get here if the extension exists.
let ext = scanner.extensions[messageType, fieldNumber]!
var fieldValue = values[fieldNumber]
if fieldValue != nil {
try fieldValue!.decodeExtensionField(decoder: &self)
} else {
fieldValue = try ext._protobuf_newField(decoder: &self)
}
values[fieldNumber] = fieldValue!
}
}

View File

@ -0,0 +1,62 @@
// Sources/SwiftProtobuf/JSONDecodingError.swift - JSON decoding errors
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// JSON decoding errors
///
// -----------------------------------------------------------------------------
public enum JSONDecodingError: Error {
/// Something was wrong
case failure
/// A number could not be parsed
case malformedNumber
/// Numeric value was out of range or was not an integer value when expected
case numberRange
/// A map could not be parsed
case malformedMap
/// A bool could not be parsed
case malformedBool
/// We expected a quoted string, or a quoted string has a malformed backslash sequence
case malformedString
/// We encountered malformed UTF8
case invalidUTF8
/// The message does not have fieldName information
case missingFieldNames
/// The data type does not match the schema description
case schemaMismatch
/// A value (text or numeric) for an enum was not found on the enum
case unrecognizedEnumValue
/// A 'null' token appeared in an illegal location.
/// For example, Protobuf JSON does not allow 'null' tokens to appear
/// in lists.
case illegalNull
/// A map key was not quoted
case unquotedMapKey
/// JSON RFC 7519 does not allow numbers to have extra leading zeros
case leadingZero
/// We hit the end of the JSON string and expected something more...
case truncated
/// A JSON Duration could not be parsed
case malformedDuration
/// A JSON Timestamp could not be parsed
case malformedTimestamp
/// A FieldMask could not be parsed
case malformedFieldMask
/// Extraneous data remained after decoding should have been complete
case trailingGarbage
/// More than one value was specified for the same oneof field
case conflictingOneOf
/// Reached the nesting limit for messages within messages while decoding.
case messageDepthLimit
/// Encountered an unknown field with the given name. When parsing JSON, you
/// can instead instruct the library to ignore this via
/// JSONDecodingOptions.ignoreUnknownFields.
case unknownField(String)
}

View File

@ -0,0 +1,29 @@
// Sources/SwiftProtobuf/JSONDecodingOptions.swift - JSON decoding options
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// JSON decoding options
///
// -----------------------------------------------------------------------------
/// Options for JSONDecoding.
public struct JSONDecodingOptions {
/// The maximum nesting of message with messages. The default is 100.
///
/// To prevent corrupt or malicious messages from causing stack overflows,
/// this controls how deep messages can be nested within other messages
/// while parsing.
public var messageDepthLimit: Int = 100
/// If unknown fields in the JSON should be ignored. If they aren't
/// ignored, an error will be raised if one is encountered.
public var ignoreUnknownFields: Bool = false
public init() {}
}

View File

@ -0,0 +1,386 @@
// Sources/SwiftProtobuf/JSONEncoder.swift - JSON Encoding support
//
// Copyright (c) 2014 - 2019 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// JSON serialization engine.
///
// -----------------------------------------------------------------------------
import Foundation
private let asciiZero = UInt8(ascii: "0")
private let asciiOne = UInt8(ascii: "1")
private let asciiTwo = UInt8(ascii: "2")
private let asciiThree = UInt8(ascii: "3")
private let asciiFour = UInt8(ascii: "4")
private let asciiFive = UInt8(ascii: "5")
private let asciiSix = UInt8(ascii: "6")
private let asciiSeven = UInt8(ascii: "7")
private let asciiEight = UInt8(ascii: "8")
private let asciiNine = UInt8(ascii: "9")
private let asciiMinus = UInt8(ascii: "-")
private let asciiPlus = UInt8(ascii: "+")
private let asciiEquals = UInt8(ascii: "=")
private let asciiColon = UInt8(ascii: ":")
private let asciiComma = UInt8(ascii: ",")
private let asciiDoubleQuote = UInt8(ascii: "\"")
private let asciiBackslash = UInt8(ascii: "\\")
private let asciiForwardSlash = UInt8(ascii: "/")
private let asciiOpenSquareBracket = UInt8(ascii: "[")
private let asciiCloseSquareBracket = UInt8(ascii: "]")
private let asciiOpenCurlyBracket = UInt8(ascii: "{")
private let asciiCloseCurlyBracket = UInt8(ascii: "}")
private let asciiUpperA = UInt8(ascii: "A")
private let asciiUpperB = UInt8(ascii: "B")
private let asciiUpperC = UInt8(ascii: "C")
private let asciiUpperD = UInt8(ascii: "D")
private let asciiUpperE = UInt8(ascii: "E")
private let asciiUpperF = UInt8(ascii: "F")
private let asciiUpperZ = UInt8(ascii: "Z")
private let asciiLowerA = UInt8(ascii: "a")
private let asciiLowerZ = UInt8(ascii: "z")
private let base64Digits: [UInt8] = {
var digits = [UInt8]()
digits.append(contentsOf: asciiUpperA...asciiUpperZ)
digits.append(contentsOf: asciiLowerA...asciiLowerZ)
digits.append(contentsOf: asciiZero...asciiNine)
digits.append(asciiPlus)
digits.append(asciiForwardSlash)
return digits
}()
private let hexDigits: [UInt8] = {
var digits = [UInt8]()
digits.append(contentsOf: asciiZero...asciiNine)
digits.append(contentsOf: asciiUpperA...asciiUpperF)
return digits
}()
internal struct JSONEncoder {
private var data = [UInt8]()
private var separator: UInt8?
internal init() {}
internal var dataResult: Data { return Data(data) }
internal var stringResult: String {
get {
return String(bytes: data, encoding: String.Encoding.utf8)!
}
}
/// Append a `StaticString` to the JSON text. Because
/// `StaticString` is already UTF8 internally, this is faster
/// than appending a regular `String`.
internal mutating func append(staticText: StaticString) {
let buff = UnsafeBufferPointer(start: staticText.utf8Start, count: staticText.utf8CodeUnitCount)
data.append(contentsOf: buff)
}
/// Append a `_NameMap.Name` to the JSON text surrounded by quotes.
/// As with StaticString above, a `_NameMap.Name` provides pre-converted
/// UTF8 bytes, so this is much faster than appending a regular
/// `String`.
internal mutating func appendQuoted(name: _NameMap.Name) {
data.append(asciiDoubleQuote)
data.append(contentsOf: name.utf8Buffer)
data.append(asciiDoubleQuote)
}
/// Append a `String` to the JSON text.
internal mutating func append(text: String) {
data.append(contentsOf: text.utf8)
}
/// Append a raw utf8 in a `Data` to the JSON text.
internal mutating func append(utf8Data: Data) {
data.append(contentsOf: utf8Data)
}
/// Begin a new field whose name is given as a `_NameMap.Name`
internal mutating func startField(name: _NameMap.Name) {
if let s = separator {
data.append(s)
}
appendQuoted(name: name)
data.append(asciiColon)
separator = asciiComma
}
/// Begin a new field whose name is given as a `String`.
internal mutating func startField(name: String) {
if let s = separator {
data.append(s)
}
data.append(asciiDoubleQuote)
// Can avoid overhead of putStringValue, since
// the JSON field names are always clean ASCII.
data.append(contentsOf: name.utf8)
append(staticText: "\":")
separator = asciiComma
}
/// Begin a new extension field
internal mutating func startExtensionField(name: String) {
if let s = separator {
data.append(s)
}
append(staticText: "\"[")
data.append(contentsOf: name.utf8)
append(staticText: "]\":")
separator = asciiComma
}
/// Append an open square bracket `[` to the JSON.
internal mutating func startArray() {
data.append(asciiOpenSquareBracket)
separator = nil
}
/// Append a close square bracket `]` to the JSON.
internal mutating func endArray() {
data.append(asciiCloseSquareBracket)
separator = asciiComma
}
/// Append a comma `,` to the JSON.
internal mutating func comma() {
data.append(asciiComma)
}
/// Append an open curly brace `{` to the JSON.
/// Assumes this object is part of an array of objects.
internal mutating func startArrayObject() {
if let s = separator {
data.append(s)
}
data.append(asciiOpenCurlyBracket)
separator = nil
}
/// Append an open curly brace `{` to the JSON.
internal mutating func startObject() {
data.append(asciiOpenCurlyBracket)
separator = nil
}
/// Append a close curly brace `}` to the JSON.
internal mutating func endObject() {
data.append(asciiCloseCurlyBracket)
separator = asciiComma
}
/// Write a JSON `null` token to the output.
internal mutating func putNullValue() {
append(staticText: "null")
}
/// Append a float value to the output.
/// This handles Nan and infinite values by
/// writing well-known string values.
internal mutating func putFloatValue(value: Float) {
if value.isNaN {
append(staticText: "\"NaN\"")
} else if !value.isFinite {
if value < 0 {
append(staticText: "\"-Infinity\"")
} else {
append(staticText: "\"Infinity\"")
}
} else {
data.append(contentsOf: value.debugDescription.utf8)
}
}
/// Append a double value to the output.
/// This handles Nan and infinite values by
/// writing well-known string values.
internal mutating func putDoubleValue(value: Double) {
if value.isNaN {
append(staticText: "\"NaN\"")
} else if !value.isFinite {
if value < 0 {
append(staticText: "\"-Infinity\"")
} else {
append(staticText: "\"Infinity\"")
}
} else {
data.append(contentsOf: value.debugDescription.utf8)
}
}
/// Append a UInt64 to the output (without quoting).
private mutating func appendUInt(value: UInt64) {
if value >= 10 {
appendUInt(value: value / 10)
}
data.append(asciiZero + UInt8(value % 10))
}
/// Append an Int64 to the output (without quoting).
private mutating func appendInt(value: Int64) {
if value < 0 {
data.append(asciiMinus)
// This is the twos-complement negation of value,
// computed in a way that won't overflow a 64-bit
// signed integer.
appendUInt(value: 1 + ~UInt64(bitPattern: value))
} else {
appendUInt(value: UInt64(bitPattern: value))
}
}
/// Write an Enum as an int.
internal mutating func putEnumInt(value: Int) {
appendInt(value: Int64(value))
}
/// Write an `Int64` using protobuf JSON quoting conventions.
internal mutating func putInt64(value: Int64) {
data.append(asciiDoubleQuote)
appendInt(value: value)
data.append(asciiDoubleQuote)
}
/// Write an `Int32` with quoting suitable for
/// using the value as a map key.
internal mutating func putQuotedInt32(value: Int32) {
data.append(asciiDoubleQuote)
appendInt(value: Int64(value))
data.append(asciiDoubleQuote)
}
/// Write an `Int32` in the default format.
internal mutating func putInt32(value: Int32) {
appendInt(value: Int64(value))
}
/// Write a `UInt64` using protobuf JSON quoting conventions.
internal mutating func putUInt64(value: UInt64) {
data.append(asciiDoubleQuote)
appendUInt(value: value)
data.append(asciiDoubleQuote)
}
/// Write a `UInt32` with quoting suitable for
/// using the value as a map key.
internal mutating func putQuotedUInt32(value: UInt32) {
data.append(asciiDoubleQuote)
appendUInt(value: UInt64(value))
data.append(asciiDoubleQuote)
}
/// Write a `UInt32` in the default format.
internal mutating func putUInt32(value: UInt32) {
appendUInt(value: UInt64(value))
}
/// Write a `Bool` with quoting suitable for
/// using the value as a map key.
internal mutating func putQuotedBoolValue(value: Bool) {
data.append(asciiDoubleQuote)
putBoolValue(value: value)
data.append(asciiDoubleQuote)
}
/// Write a `Bool` in the default format.
internal mutating func putBoolValue(value: Bool) {
if value {
append(staticText: "true")
} else {
append(staticText: "false")
}
}
/// Append a string value escaping special characters as needed.
internal mutating func putStringValue(value: String) {
data.append(asciiDoubleQuote)
for c in value.unicodeScalars {
switch c.value {
// Special two-byte escapes
case 8: append(staticText: "\\b")
case 9: append(staticText: "\\t")
case 10: append(staticText: "\\n")
case 12: append(staticText: "\\f")
case 13: append(staticText: "\\r")
case 34: append(staticText: "\\\"")
case 92: append(staticText: "\\\\")
case 0...31, 127...159: // Hex form for C0 control chars
append(staticText: "\\u00")
data.append(hexDigits[Int(c.value / 16)])
data.append(hexDigits[Int(c.value & 15)])
case 23...126:
data.append(UInt8(truncatingIfNeeded: c.value))
case 0x80...0x7ff:
data.append(0xc0 + UInt8(truncatingIfNeeded: c.value >> 6))
data.append(0x80 + UInt8(truncatingIfNeeded: c.value & 0x3f))
case 0x800...0xffff:
data.append(0xe0 + UInt8(truncatingIfNeeded: c.value >> 12))
data.append(0x80 + UInt8(truncatingIfNeeded: (c.value >> 6) & 0x3f))
data.append(0x80 + UInt8(truncatingIfNeeded: c.value & 0x3f))
default:
data.append(0xf0 + UInt8(truncatingIfNeeded: c.value >> 18))
data.append(0x80 + UInt8(truncatingIfNeeded: (c.value >> 12) & 0x3f))
data.append(0x80 + UInt8(truncatingIfNeeded: (c.value >> 6) & 0x3f))
data.append(0x80 + UInt8(truncatingIfNeeded: c.value & 0x3f))
}
}
data.append(asciiDoubleQuote)
}
/// Append a bytes value using protobuf JSON Base-64 encoding.
internal mutating func putBytesValue(value: Data) {
data.append(asciiDoubleQuote)
if value.count > 0 {
value.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
if let p = body.baseAddress, body.count > 0 {
var t: Int = 0
var bytesInGroup: Int = 0
for i in 0..<body.count {
if bytesInGroup == 3 {
data.append(base64Digits[(t >> 18) & 63])
data.append(base64Digits[(t >> 12) & 63])
data.append(base64Digits[(t >> 6) & 63])
data.append(base64Digits[t & 63])
t = 0
bytesInGroup = 0
}
t = (t << 8) + Int(p[i])
bytesInGroup += 1
}
switch bytesInGroup {
case 3:
data.append(base64Digits[(t >> 18) & 63])
data.append(base64Digits[(t >> 12) & 63])
data.append(base64Digits[(t >> 6) & 63])
data.append(base64Digits[t & 63])
case 2:
t <<= 8
data.append(base64Digits[(t >> 18) & 63])
data.append(base64Digits[(t >> 12) & 63])
data.append(base64Digits[(t >> 6) & 63])
data.append(asciiEquals)
case 1:
t <<= 16
data.append(base64Digits[(t >> 18) & 63])
data.append(base64Digits[(t >> 12) & 63])
data.append(asciiEquals)
data.append(asciiEquals)
default:
break
}
}
}
}
data.append(asciiDoubleQuote)
}
}

View File

@ -0,0 +1,35 @@
// Sources/SwiftProtobuf/JSONEncodingError.swift - Error constants
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Enum constants that identify the particular error.
///
// -----------------------------------------------------------------------------
public enum JSONEncodingError: Error {
/// Any fields that were decoded from binary format cannot be
/// re-encoded into JSON unless the object they hold is a
/// well-known type or a type registered with via
/// Google_Protobuf_Any.register()
case anyTranscodeFailure
/// Timestamp values can only be JSON encoded if they hold a value
/// between 0001-01-01Z00:00:00 and 9999-12-31Z23:59:59.
case timestampRange
/// Duration values can only be JSON encoded if they hold a value
/// less than +/- 100 years.
case durationRange
/// Field masks get edited when converting between JSON and protobuf
case fieldMaskConversion
/// Field names were not compiled into the binary
case missingFieldNames
/// Instances of `Google_Protobuf_Value` can only be encoded if they have a
/// valid `kind` (that is, they represent a null value, number, boolean,
/// string, struct, or list).
case missingValue
}

View File

@ -0,0 +1,26 @@
// Sources/SwiftProtobuf/JSONEncodingOptions.swift - JSON encoding options
//
// Copyright (c) 2014 - 2018 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// JSON encoding options
///
// -----------------------------------------------------------------------------
/// Options for JSONEncoding.
public struct JSONEncodingOptions {
/// Always print enums as ints. By default they are printed as strings.
public var alwaysPrintEnumsAsInts: Bool = false
/// Whether to preserve proto field names.
/// By default they are converted to JSON(lowerCamelCase) names.
public var preserveProtoFieldNames: Bool = false
public init() {}
}

View File

@ -0,0 +1,404 @@
// Sources/SwiftProtobuf/JSONEncodingVisitor.swift - JSON encoding visitor
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Visitor that writes a message in JSON format.
///
// -----------------------------------------------------------------------------
import Foundation
/// Visitor that serializes a message into JSON format.
internal struct JSONEncodingVisitor: Visitor {
private var encoder = JSONEncoder()
private var nameMap: _NameMap
private var extensions: ExtensionFieldValueSet?
private let options: JSONEncodingOptions
/// The JSON text produced by the visitor, as raw UTF8 bytes.
var dataResult: Data {
return encoder.dataResult
}
/// The JSON text produced by the visitor, as a String.
internal var stringResult: String {
return encoder.stringResult
}
/// Creates a new visitor for serializing a message of the given type to JSON
/// format.
init(type: Message.Type, options: JSONEncodingOptions) throws {
if let nameProviding = type as? _ProtoNameProviding.Type {
self.nameMap = nameProviding._protobuf_nameMap
} else {
throw JSONEncodingError.missingFieldNames
}
self.options = options
}
mutating func startArray() {
encoder.startArray()
}
mutating func endArray() {
encoder.endArray()
}
mutating func startObject(message: Message) {
self.extensions = (message as? ExtensibleMessage)?._protobuf_extensionFieldValues
encoder.startObject()
}
mutating func startArrayObject(message: Message) {
self.extensions = (message as? ExtensibleMessage)?._protobuf_extensionFieldValues
encoder.startArrayObject()
}
mutating func endObject() {
encoder.endObject()
}
mutating func encodeField(name: String, stringValue value: String) {
encoder.startField(name: name)
encoder.putStringValue(value: value)
}
mutating func encodeField(name: String, jsonText text: String) {
encoder.startField(name: name)
encoder.append(text: text)
}
mutating func visitUnknown(bytes: Data) throws {
// JSON encoding has no provision for carrying proto2 unknown fields.
}
mutating func visitSingularFloatField(value: Float, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.putFloatValue(value: value)
}
mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.putDoubleValue(value: value)
}
mutating func visitSingularInt32Field(value: Int32, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.putInt32(value: value)
}
mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.putInt64(value: value)
}
mutating func visitSingularUInt32Field(value: UInt32, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.putUInt32(value: value)
}
mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.putUInt64(value: value)
}
mutating func visitSingularFixed32Field(value: UInt32, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.putUInt32(value: value)
}
mutating func visitSingularSFixed32Field(value: Int32, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.putInt32(value: value)
}
mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.putBoolValue(value: value)
}
mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.putStringValue(value: value)
}
mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.putBytesValue(value: value)
}
private mutating func _visitRepeated<T>(
value: [T],
fieldNumber: Int,
encode: (inout JSONEncoder, T) throws -> ()
) throws {
assert(!value.isEmpty)
try startField(for: fieldNumber)
var comma = false
encoder.startArray()
for v in value {
if comma {
encoder.comma()
}
comma = true
try encode(&encoder, v)
}
encoder.endArray()
}
mutating func visitSingularEnumField<E: Enum>(value: E, fieldNumber: Int) throws {
try startField(for: fieldNumber)
if let e = value as? _CustomJSONCodable {
let json = try e.encodedJSONString(options: options)
encoder.append(text: json)
} else if !options.alwaysPrintEnumsAsInts, let n = value.name {
encoder.appendQuoted(name: n)
} else {
encoder.putEnumInt(value: value.rawValue)
}
}
mutating func visitSingularMessageField<M: Message>(value: M, fieldNumber: Int) throws {
try startField(for: fieldNumber)
if let m = value as? _CustomJSONCodable {
let json = try m.encodedJSONString(options: options)
encoder.append(text: json)
} else if let newNameMap = (M.self as? _ProtoNameProviding.Type)?._protobuf_nameMap {
// Preserve outer object's name and extension maps; restore them before returning
let oldNameMap = self.nameMap
let oldExtensions = self.extensions
defer {
self.nameMap = oldNameMap
self.extensions = oldExtensions
}
// Install inner object's name and extension maps
self.nameMap = newNameMap
startObject(message: value)
try value.traverse(visitor: &self)
endObject()
} else {
throw JSONEncodingError.missingFieldNames
}
}
mutating func visitSingularGroupField<G: Message>(value: G, fieldNumber: Int) throws {
// Google does not serialize groups into JSON
}
mutating func visitRepeatedFloatField(value: [Float], fieldNumber: Int) throws {
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
(encoder: inout JSONEncoder, v: Float) in
encoder.putFloatValue(value: v)
}
}
mutating func visitRepeatedDoubleField(value: [Double], fieldNumber: Int) throws {
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
(encoder: inout JSONEncoder, v: Double) in
encoder.putDoubleValue(value: v)
}
}
mutating func visitRepeatedInt32Field(value: [Int32], fieldNumber: Int) throws {
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
(encoder: inout JSONEncoder, v: Int32) in
encoder.putInt32(value: v)
}
}
mutating func visitRepeatedInt64Field(value: [Int64], fieldNumber: Int) throws {
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
(encoder: inout JSONEncoder, v: Int64) in
encoder.putInt64(value: v)
}
}
mutating func visitRepeatedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
(encoder: inout JSONEncoder, v: UInt32) in
encoder.putUInt32(value: v)
}
}
mutating func visitRepeatedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
(encoder: inout JSONEncoder, v: UInt64) in
encoder.putUInt64(value: v)
}
}
mutating func visitRepeatedSInt32Field(value: [Int32], fieldNumber: Int) throws {
try visitRepeatedInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedSInt64Field(value: [Int64], fieldNumber: Int) throws {
try visitRepeatedInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
try visitRepeatedUInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
try visitRepeatedUInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
try visitRepeatedInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
try visitRepeatedInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedBoolField(value: [Bool], fieldNumber: Int) throws {
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
(encoder: inout JSONEncoder, v: Bool) in
encoder.putBoolValue(value: v)
}
}
mutating func visitRepeatedStringField(value: [String], fieldNumber: Int) throws {
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
(encoder: inout JSONEncoder, v: String) in
encoder.putStringValue(value: v)
}
}
mutating func visitRepeatedBytesField(value: [Data], fieldNumber: Int) throws {
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
(encoder: inout JSONEncoder, v: Data) in
encoder.putBytesValue(value: v)
}
}
mutating func visitRepeatedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
if let _ = E.self as? _CustomJSONCodable.Type {
let options = self.options
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
(encoder: inout JSONEncoder, v: E) throws in
let e = v as! _CustomJSONCodable
let json = try e.encodedJSONString(options: options)
encoder.append(text: json)
}
} else {
let alwaysPrintEnumsAsInts = options.alwaysPrintEnumsAsInts
try _visitRepeated(value: value, fieldNumber: fieldNumber) {
(encoder: inout JSONEncoder, v: E) throws in
if !alwaysPrintEnumsAsInts, let n = v.name {
encoder.appendQuoted(name: n)
} else {
encoder.putEnumInt(value: v.rawValue)
}
}
}
}
mutating func visitRepeatedMessageField<M: Message>(value: [M], fieldNumber: Int) throws {
assert(!value.isEmpty)
try startField(for: fieldNumber)
var comma = false
encoder.startArray()
if let _ = M.self as? _CustomJSONCodable.Type {
for v in value {
if comma {
encoder.comma()
}
comma = true
let json = try v.jsonString(options: options)
encoder.append(text: json)
}
} else if let newNameMap = (M.self as? _ProtoNameProviding.Type)?._protobuf_nameMap {
// Preserve name and extension maps for outer object
let oldNameMap = self.nameMap
let oldExtensions = self.extensions
// Restore outer object's name and extension maps before returning
defer {
self.nameMap = oldNameMap
self.extensions = oldExtensions
}
self.nameMap = newNameMap
for v in value {
startArrayObject(message: v)
try v.traverse(visitor: &self)
encoder.endObject()
}
} else {
throw JSONEncodingError.missingFieldNames
}
encoder.endArray()
}
mutating func visitRepeatedGroupField<G: Message>(value: [G], fieldNumber: Int) throws {
assert(!value.isEmpty)
// Google does not serialize groups into JSON
}
// Packed fields are handled the same as non-packed fields, so JSON just
// relies on the default implementations in Visitor.swift
mutating func visitMapField<KeyType, ValueType: MapValueType>(fieldType: _ProtobufMap<KeyType, ValueType>.Type, value: _ProtobufMap<KeyType, ValueType>.BaseType, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.append(text: "{")
var mapVisitor = JSONMapEncodingVisitor(encoder: encoder, options: options)
for (k,v) in value {
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &mapVisitor)
try ValueType.visitSingular(value: v, fieldNumber: 2, with: &mapVisitor)
}
encoder = mapVisitor.encoder
encoder.append(text: "}")
}
mutating func visitMapField<KeyType, ValueType>(fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type, value: _ProtobufEnumMap<KeyType, ValueType>.BaseType, fieldNumber: Int) throws where ValueType.RawValue == Int {
try startField(for: fieldNumber)
encoder.append(text: "{")
var mapVisitor = JSONMapEncodingVisitor(encoder: encoder, options: options)
for (k, v) in value {
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &mapVisitor)
try mapVisitor.visitSingularEnumField(value: v, fieldNumber: 2)
}
encoder = mapVisitor.encoder
encoder.append(text: "}")
}
mutating func visitMapField<KeyType, ValueType>(fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type, value: _ProtobufMessageMap<KeyType, ValueType>.BaseType, fieldNumber: Int) throws {
try startField(for: fieldNumber)
encoder.append(text: "{")
var mapVisitor = JSONMapEncodingVisitor(encoder: encoder, options: options)
for (k,v) in value {
try KeyType.visitSingular(value: k, fieldNumber: 1, with: &mapVisitor)
try mapVisitor.visitSingularMessageField(value: v, fieldNumber: 2)
}
encoder = mapVisitor.encoder
encoder.append(text: "}")
}
/// Helper function that throws an error if the field number could not be
/// resolved.
private mutating func startField(for number: Int) throws {
let name: _NameMap.Name?
if options.preserveProtoFieldNames {
name = nameMap.names(for: number)?.proto
} else {
name = nameMap.names(for: number)?.json
}
if let name = name {
encoder.startField(name: name)
} else if let name = extensions?[number]?.protobufExtension.fieldName {
encoder.startExtensionField(name: name)
} else {
throw JSONEncodingError.missingFieldNames
}
}
}

View File

@ -0,0 +1,174 @@
// Sources/SwiftProtobuf/JSONMapEncodingVisitor.swift - JSON map encoding visitor
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Visitor that writes out the key/value pairs for a JSON map.
///
// -----------------------------------------------------------------------------
import Foundation
/// Visitor that serializes a message into JSON map format.
///
/// This expects to alternately visit the keys and values for a JSON
/// map. It only accepts singular values. Keys should be identified
/// as `fieldNumber:1`, values should be identified as `fieldNumber:2`
///
internal struct JSONMapEncodingVisitor: SelectiveVisitor {
private var separator: StaticString?
internal var encoder: JSONEncoder
private let options: JSONEncodingOptions
init(encoder: JSONEncoder, options: JSONEncodingOptions) {
self.encoder = encoder
self.options = options
}
private mutating func startKey() {
if let s = separator {
encoder.append(staticText: s)
} else {
separator = ","
}
}
private mutating func startValue() {
encoder.append(staticText: ":")
}
mutating func visitSingularFloatField(value: Float, fieldNumber: Int) throws {
// Doubles/Floats can never be map keys, only values
assert(fieldNumber == 2)
startValue()
encoder.putFloatValue(value: value)
}
mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
// Doubles/Floats can never be map keys, only values
assert(fieldNumber == 2)
startValue()
encoder.putDoubleValue(value: value)
}
mutating func visitSingularInt32Field(value: Int32, fieldNumber: Int) throws {
if fieldNumber == 1 {
startKey()
encoder.putQuotedInt32(value: value)
} else {
startValue()
encoder.putInt32(value: value)
}
}
mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
if fieldNumber == 1 {
startKey()
} else {
startValue()
}
// Int64 fields are always quoted anyway
encoder.putInt64(value: value)
}
mutating func visitSingularUInt32Field(value: UInt32, fieldNumber: Int) throws {
if fieldNumber == 1 {
startKey()
encoder.putQuotedUInt32(value: value)
} else {
startValue()
encoder.putUInt32(value: value)
}
}
mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
if fieldNumber == 1 {
startKey()
} else {
startValue()
}
encoder.putUInt64(value: value)
}
mutating func visitSingularSInt32Field(value: Int32, fieldNumber: Int) throws {
try visitSingularInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitSingularSInt64Field(value: Int64, fieldNumber: Int) throws {
try visitSingularInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitSingularFixed32Field(value: UInt32, fieldNumber: Int) throws {
try visitSingularUInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitSingularFixed64Field(value: UInt64, fieldNumber: Int) throws {
try visitSingularUInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitSingularSFixed32Field(value: Int32, fieldNumber: Int) throws {
try visitSingularInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitSingularSFixed64Field(value: Int64, fieldNumber: Int) throws {
try visitSingularInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
if fieldNumber == 1 {
startKey()
encoder.putQuotedBoolValue(value: value)
} else {
startValue()
encoder.putBoolValue(value: value)
}
}
mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
if fieldNumber == 1 {
startKey()
} else {
startValue()
}
encoder.putStringValue(value: value)
}
mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
// Bytes can only be map values, never keys
assert(fieldNumber == 2)
startValue()
encoder.putBytesValue(value: value)
}
mutating func visitSingularEnumField<E: Enum>(value: E, fieldNumber: Int) throws {
// Enums can only be map values, never keys
assert(fieldNumber == 2)
startValue()
if !options.alwaysPrintEnumsAsInts, let n = value.name {
encoder.putStringValue(value: String(describing: n))
} else {
encoder.putEnumInt(value: value.rawValue)
}
}
mutating func visitSingularMessageField<M: Message>(value: M, fieldNumber: Int) throws {
// Messages can only be map values, never keys
assert(fieldNumber == 2)
startValue()
let json = try value.jsonString(options: options)
encoder.append(text: json)
}
// SelectiveVisitor will block:
// - single Groups
// - everything repeated
// - everything packed
// - all maps
// - unknown fields
// - extensions
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
// Sources/SwiftProtobuf/MathUtils.swift - Generally useful mathematical functions
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Generally useful mathematical and arithmetic functions.
///
// -----------------------------------------------------------------------------
import Foundation
/// Remainder in standard modular arithmetic (modulo). This coincides with (%)
/// when a > 0.
///
/// - Parameters:
/// - a: The dividend. Can be positive, 0 or negative.
/// - b: The divisor. This must be positive, and is an error if 0 or negative.
/// - Returns: The unique value r such that 0 <= r < b and b * q + r = a for some q.
internal func mod<T : SignedInteger>(_ a: T, _ b: T) -> T {
assert(b > 0)
let r = a % b
return r >= 0 ? r : r + b
}
/// Quotient in standard modular arithmetic (Euclidean division). This coincides
/// with (/) when a > 0.
///
/// - Parameters:
/// - a: The dividend. Can be positive, 0 or negative.
/// - b: The divisor. This must be positive, and is an error if 0 or negative.
/// - Returns: The unique value q such that for some 0 <= r < b, b * q + r = a.
internal func div<T : SignedInteger>(_ a: T, _ b: T) -> T {
assert(b > 0)
return a >= 0 ? a / b : (a + 1) / b - 1
}

View File

@ -0,0 +1,45 @@
// Sources/SwiftProtobuf/Message+AnyAdditions.swift - Any-related Message extensions
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extends the `Message` type with `Google_Protobuf_Any`-specific behavior.
///
// -----------------------------------------------------------------------------
extension Message {
/// Initialize this message from the provided `google.protobuf.Any`
/// well-known type.
///
/// This corresponds to the `unpack` method in the Google C++ API.
///
/// If the Any object was decoded from Protobuf Binary or JSON
/// format, then the enclosed field data was stored and is not
/// fully decoded until you unpack the Any object into a message.
/// As such, this method will typically need to perform a full
/// deserialization of the enclosed data and can fail for any
/// reason that deserialization can fail.
///
/// See `Google_Protobuf_Any.unpackTo()` for more discussion.
///
/// - Parameter unpackingAny: the message to decode.
/// - Parameter extensions: An `ExtensionMap` used to look up and decode any
/// extensions in this message or messages nested within this message's
/// fields.
/// - Parameter options: The BinaryDecodingOptions to use.
/// - Throws: an instance of `AnyUnpackError`, `JSONDecodingError`, or
/// `BinaryDecodingError` on failure.
public init(
unpackingAny: Google_Protobuf_Any,
extensions: ExtensionMap? = nil,
options: BinaryDecodingOptions = BinaryDecodingOptions()
) throws {
self.init()
try unpackingAny._storage.unpackTo(target: &self, extensions: extensions, options: options)
}
}

View File

@ -0,0 +1,204 @@
// Sources/SwiftProtobuf/Message+BinaryAdditions.swift - Per-type binary coding
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extensions to `Message` to provide binary coding and decoding.
///
// -----------------------------------------------------------------------------
import Foundation
/// Binary encoding and decoding methods for messages.
extension Message {
/// Returns a `Data` value containing the Protocol Buffer binary format
/// serialization of the message.
///
/// - Parameters:
/// - partial: If `false` (the default), this method will check
/// `Message.isInitialized` before encoding to verify that all required
/// fields are present. If any are missing, this method throws
/// `BinaryEncodingError.missingRequiredFields`.
/// - Returns: A `Data` value containing the binary serialization of the
/// message.
/// - Throws: `BinaryEncodingError` if encoding fails.
public func serializedData(partial: Bool = false) throws -> Data {
if !partial && !isInitialized {
throw BinaryEncodingError.missingRequiredFields
}
let requiredSize = try serializedDataSize()
var data = Data(count: requiredSize)
try data.withUnsafeMutableBytes { (body: UnsafeMutableRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
var visitor = BinaryEncodingVisitor(forWritingInto: baseAddress)
try traverse(visitor: &visitor)
// Currently not exposing this from the api because it really would be
// an internal error in the library and should never happen.
assert(requiredSize == visitor.encoder.distance(pointer: baseAddress))
}
}
return data
}
/// Returns the size in bytes required to encode the message in binary format.
/// This is used by `serializedData()` to precalculate the size of the buffer
/// so that encoding can proceed without bounds checks or reallocation.
internal func serializedDataSize() throws -> Int {
// Note: since this api is internal, it doesn't currently worry about
// needing a partial argument to handle proto2 syntax required fields.
// If this become public, it will need that added.
var visitor = BinaryEncodingSizeVisitor()
try traverse(visitor: &visitor)
return visitor.serializedSize
}
/// Creates a new message by decoding the given `Data` value containing a
/// serialized message in Protocol Buffer binary format.
///
/// - Parameters:
/// - serializedData: The binary-encoded message data to decode.
/// - extensions: An `ExtensionMap` used to look up and decode any
/// extensions in this message or messages nested within this message's
/// fields.
/// - partial: If `false` (the default), this method will check
/// `Message.isInitialized` before encoding to verify that all required
/// fields are present. If any are missing, this method throws
/// `BinaryEncodingError.missingRequiredFields`.
/// - options: The BinaryDecodingOptions to use.
/// - Throws: `BinaryDecodingError` if decoding fails.
@inlinable
public init(
serializedData data: Data,
extensions: ExtensionMap? = nil,
partial: Bool = false,
options: BinaryDecodingOptions = BinaryDecodingOptions()
) throws {
self.init()
#if swift(>=5.0)
try merge(contiguousBytes: data, extensions: extensions, partial: partial, options: options)
#else
try merge(serializedData: data, extensions: extensions, partial: partial, options: options)
#endif
}
#if swift(>=5.0)
/// Creates a new message by decoding the given `ContiguousBytes` value
/// containing a serialized message in Protocol Buffer binary format.
///
/// - Parameters:
/// - contiguousBytes: The binary-encoded message data to decode.
/// - extensions: An `ExtensionMap` used to look up and decode any
/// extensions in this message or messages nested within this message's
/// fields.
/// - partial: If `false` (the default), this method will check
/// `Message.isInitialized` before encoding to verify that all required
/// fields are present. If any are missing, this method throws
/// `BinaryEncodingError.missingRequiredFields`.
/// - options: The BinaryDecodingOptions to use.
/// - Throws: `BinaryDecodingError` if decoding fails.
@inlinable
public init<Bytes: ContiguousBytes>(
contiguousBytes bytes: Bytes,
extensions: ExtensionMap? = nil,
partial: Bool = false,
options: BinaryDecodingOptions = BinaryDecodingOptions()
) throws {
self.init()
try merge(contiguousBytes: bytes, extensions: extensions, partial: partial, options: options)
}
#endif // #if swift(>=5.0)
/// Updates the message by decoding the given `Data` value containing a
/// serialized message in Protocol Buffer binary format into the receiver.
///
/// - Note: If this method throws an error, the message may still have been
/// partially mutated by the binary data that was decoded before the error
/// occurred.
///
/// - Parameters:
/// - serializedData: The binary-encoded message data to decode.
/// - extensions: An `ExtensionMap` used to look up and decode any
/// extensions in this message or messages nested within this message's
/// fields.
/// - partial: If `false` (the default), this method will check
/// `Message.isInitialized` before encoding to verify that all required
/// fields are present. If any are missing, this method throws
/// `BinaryEncodingError.missingRequiredFields`.
/// - options: The BinaryDecodingOptions to use.
/// - Throws: `BinaryDecodingError` if decoding fails.
@inlinable
public mutating func merge(
serializedData data: Data,
extensions: ExtensionMap? = nil,
partial: Bool = false,
options: BinaryDecodingOptions = BinaryDecodingOptions()
) throws {
#if swift(>=5.0)
try merge(contiguousBytes: data, extensions: extensions, partial: partial, options: options)
#else
try data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
try _merge(rawBuffer: body, extensions: extensions, partial: partial, options: options)
}
#endif // swift(>=5.0)
}
#if swift(>=5.0)
/// Updates the message by decoding the given `ContiguousBytes` value
/// containing a serialized message in Protocol Buffer binary format into the
/// receiver.
///
/// - Note: If this method throws an error, the message may still have been
/// partially mutated by the binary data that was decoded before the error
/// occurred.
///
/// - Parameters:
/// - contiguousBytes: The binary-encoded message data to decode.
/// - extensions: An `ExtensionMap` used to look up and decode any
/// extensions in this message or messages nested within this message's
/// fields.
/// - partial: If `false` (the default), this method will check
/// `Message.isInitialized` before encoding to verify that all required
/// fields are present. If any are missing, this method throws
/// `BinaryEncodingError.missingRequiredFields`.
/// - options: The BinaryDecodingOptions to use.
/// - Throws: `BinaryDecodingError` if decoding fails.
@inlinable
public mutating func merge<Bytes: ContiguousBytes>(
contiguousBytes bytes: Bytes,
extensions: ExtensionMap? = nil,
partial: Bool = false,
options: BinaryDecodingOptions = BinaryDecodingOptions()
) throws {
try bytes.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
try _merge(rawBuffer: body, extensions: extensions, partial: partial, options: options)
}
}
#endif // swift(>=5.0)
// Helper for `merge()`s to keep the Decoder internal to SwiftProtobuf while
// allowing the generic over ContiguousBytes to get better codegen from the
// compiler by being `@inlinable`.
@usableFromInline
internal mutating func _merge(
rawBuffer body: UnsafeRawBufferPointer,
extensions: ExtensionMap?,
partial: Bool,
options: BinaryDecodingOptions
) throws {
if let baseAddress = body.baseAddress, body.count > 0 {
var decoder = BinaryDecoder(forReadingFrom: baseAddress,
count: body.count,
options: options,
extensions: extensions)
try decoder.decodeFullMessage(message: &self)
}
if !partial && !isInitialized {
throw BinaryDecodingError.missingRequiredFields
}
}
}

View File

@ -0,0 +1,150 @@
// Sources/SwiftProtobuf/Message+JSONAdditions.swift - JSON format primitive types
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extensions to `Message` to support JSON encoding/decoding.
///
// -----------------------------------------------------------------------------
import Foundation
/// JSON encoding and decoding methods for messages.
extension Message {
/// Returns a string containing the JSON serialization of the message.
///
/// Unlike binary encoding, presence of required fields is not enforced when
/// serializing to JSON.
///
/// - Returns: A string containing the JSON serialization of the message.
/// - Parameters:
/// - options: The JSONEncodingOptions to use.
/// - Throws: `JSONEncodingError` if encoding fails.
public func jsonString(
options: JSONEncodingOptions = JSONEncodingOptions()
) throws -> String {
if let m = self as? _CustomJSONCodable {
return try m.encodedJSONString(options: options)
}
let data = try jsonUTF8Data(options: options)
return String(data: data, encoding: String.Encoding.utf8)!
}
/// Returns a Data containing the UTF-8 JSON serialization of the message.
///
/// Unlike binary encoding, presence of required fields is not enforced when
/// serializing to JSON.
///
/// - Returns: A Data containing the JSON serialization of the message.
/// - Parameters:
/// - options: The JSONEncodingOptions to use.
/// - Throws: `JSONEncodingError` if encoding fails.
public func jsonUTF8Data(
options: JSONEncodingOptions = JSONEncodingOptions()
) throws -> Data {
if let m = self as? _CustomJSONCodable {
let string = try m.encodedJSONString(options: options)
let data = string.data(using: String.Encoding.utf8)! // Cannot fail!
return data
}
var visitor = try JSONEncodingVisitor(type: Self.self, options: options)
visitor.startObject(message: self)
try traverse(visitor: &visitor)
visitor.endObject()
return visitor.dataResult
}
/// Creates a new message by decoding the given string containing a
/// serialized message in JSON format.
///
/// - Parameter jsonString: The JSON-formatted string to decode.
/// - Parameter options: The JSONDecodingOptions to use.
/// - Throws: `JSONDecodingError` if decoding fails.
public init(
jsonString: String,
options: JSONDecodingOptions = JSONDecodingOptions()
) throws {
try self.init(jsonString: jsonString, extensions: nil, options: options)
}
/// Creates a new message by decoding the given string containing a
/// serialized message in JSON format.
///
/// - Parameter jsonString: The JSON-formatted string to decode.
/// - Parameter extensions: An ExtensionMap for looking up extensions by name
/// - Parameter options: The JSONDecodingOptions to use.
/// - Throws: `JSONDecodingError` if decoding fails.
public init(
jsonString: String,
extensions: ExtensionMap? = nil,
options: JSONDecodingOptions = JSONDecodingOptions()
) throws {
if jsonString.isEmpty {
throw JSONDecodingError.truncated
}
if let data = jsonString.data(using: String.Encoding.utf8) {
try self.init(jsonUTF8Data: data, extensions: extensions, options: options)
} else {
throw JSONDecodingError.truncated
}
}
/// Creates a new message by decoding the given `Data` containing a
/// serialized message in JSON format, interpreting the data as UTF-8 encoded
/// text.
///
/// - Parameter jsonUTF8Data: The JSON-formatted data to decode, represented
/// as UTF-8 encoded text.
/// - Parameter options: The JSONDecodingOptions to use.
/// - Throws: `JSONDecodingError` if decoding fails.
public init(
jsonUTF8Data: Data,
options: JSONDecodingOptions = JSONDecodingOptions()
) throws {
try self.init(jsonUTF8Data: jsonUTF8Data, extensions: nil, options: options)
}
/// Creates a new message by decoding the given `Data` containing a
/// serialized message in JSON format, interpreting the data as UTF-8 encoded
/// text.
///
/// - Parameter jsonUTF8Data: The JSON-formatted data to decode, represented
/// as UTF-8 encoded text.
/// - Parameter extensions: The extension map to use with this decode
/// - Parameter options: The JSONDecodingOptions to use.
/// - Throws: `JSONDecodingError` if decoding fails.
public init(
jsonUTF8Data: Data,
extensions: ExtensionMap? = nil,
options: JSONDecodingOptions = JSONDecodingOptions()
) throws {
self.init()
try jsonUTF8Data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
// Empty input is valid for binary, but not for JSON.
guard body.count > 0 else {
throw JSONDecodingError.truncated
}
var decoder = JSONDecoder(source: body, options: options,
messageType: Self.self, extensions: extensions)
if decoder.scanner.skipOptionalNull() {
if let customCodable = Self.self as? _CustomJSONCodable.Type,
let message = try customCodable.decodedFromJSONNull() {
self = message as! Self
} else {
throw JSONDecodingError.illegalNull
}
} else {
try decoder.decodeFullObject(message: &self)
}
if !decoder.scanner.complete {
throw JSONDecodingError.trailingGarbage
}
}
}
}

View File

@ -0,0 +1,146 @@
// Sources/SwiftProtobuf/Array+JSONAdditions.swift - JSON format primitive types
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extensions to `Array` to support JSON encoding/decoding.
///
// -----------------------------------------------------------------------------
import Foundation
/// JSON encoding and decoding methods for arrays of messages.
extension Message {
/// Returns a string containing the JSON serialization of the messages.
///
/// Unlike binary encoding, presence of required fields is not enforced when
/// serializing to JSON.
///
/// - Returns: A string containing the JSON serialization of the messages.
/// - Parameters:
/// - collection: The list of messages to encode.
/// - options: The JSONEncodingOptions to use.
/// - Throws: `JSONEncodingError` if encoding fails.
public static func jsonString<C: Collection>(
from collection: C,
options: JSONEncodingOptions = JSONEncodingOptions()
) throws -> String where C.Iterator.Element == Self {
let data = try jsonUTF8Data(from: collection, options: options)
return String(data: data, encoding: String.Encoding.utf8)!
}
/// Returns a Data containing the UTF-8 JSON serialization of the messages.
///
/// Unlike binary encoding, presence of required fields is not enforced when
/// serializing to JSON.
///
/// - Returns: A Data containing the JSON serialization of the messages.
/// - Parameters:
/// - collection: The list of messages to encode.
/// - options: The JSONEncodingOptions to use.
/// - Throws: `JSONEncodingError` if encoding fails.
public static func jsonUTF8Data<C: Collection>(
from collection: C,
options: JSONEncodingOptions = JSONEncodingOptions()
) throws -> Data where C.Iterator.Element == Self {
var visitor = try JSONEncodingVisitor(type: Self.self, options: options)
visitor.startArray()
for message in collection {
visitor.startArrayObject(message: message)
try message.traverse(visitor: &visitor)
visitor.endObject()
}
visitor.endArray()
return visitor.dataResult
}
/// Creates a new array of messages by decoding the given string containing a
/// serialized array of messages in JSON format.
///
/// - Parameter jsonString: The JSON-formatted string to decode.
/// - Parameter options: The JSONDecodingOptions to use.
/// - Throws: `JSONDecodingError` if decoding fails.
public static func array(
fromJSONString jsonString: String,
options: JSONDecodingOptions = JSONDecodingOptions()
) throws -> [Self] {
return try self.array(fromJSONString: jsonString,
extensions: SimpleExtensionMap(),
options: options)
}
/// Creates a new array of messages by decoding the given string containing a
/// serialized array of messages in JSON format.
///
/// - Parameter jsonString: The JSON-formatted string to decode.
/// - Parameter extensions: The extension map to use with this decode
/// - Parameter options: The JSONDecodingOptions to use.
/// - Throws: `JSONDecodingError` if decoding fails.
public static func array(
fromJSONString jsonString: String,
extensions: ExtensionMap = SimpleExtensionMap(),
options: JSONDecodingOptions = JSONDecodingOptions()
) throws -> [Self] {
if jsonString.isEmpty {
throw JSONDecodingError.truncated
}
if let data = jsonString.data(using: String.Encoding.utf8) {
return try array(fromJSONUTF8Data: data, extensions: extensions, options: options)
} else {
throw JSONDecodingError.truncated
}
}
/// Creates a new array of messages by decoding the given `Data` containing a
/// serialized array of messages in JSON format, interpreting the data as
/// UTF-8 encoded text.
///
/// - Parameter jsonUTF8Data: The JSON-formatted data to decode, represented
/// as UTF-8 encoded text.
/// - Parameter options: The JSONDecodingOptions to use.
/// - Throws: `JSONDecodingError` if decoding fails.
public static func array(
fromJSONUTF8Data jsonUTF8Data: Data,
options: JSONDecodingOptions = JSONDecodingOptions()
) throws -> [Self] {
return try self.array(fromJSONUTF8Data: jsonUTF8Data,
extensions: SimpleExtensionMap(),
options: options)
}
/// Creates a new array of messages by decoding the given `Data` containing a
/// serialized array of messages in JSON format, interpreting the data as
/// UTF-8 encoded text.
///
/// - Parameter jsonUTF8Data: The JSON-formatted data to decode, represented
/// as UTF-8 encoded text.
/// - Parameter extensions: The extension map to use with this decode
/// - Parameter options: The JSONDecodingOptions to use.
/// - Throws: `JSONDecodingError` if decoding fails.
public static func array(
fromJSONUTF8Data jsonUTF8Data: Data,
extensions: ExtensionMap = SimpleExtensionMap(),
options: JSONDecodingOptions = JSONDecodingOptions()
) throws -> [Self] {
return try jsonUTF8Data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
var array = [Self]()
if body.count > 0 {
var decoder = JSONDecoder(source: body, options: options,
messageType: Self.self, extensions: extensions)
try decoder.decodeRepeatedMessageField(value: &array)
if !decoder.scanner.complete {
throw JSONDecodingError.trailingGarbage
}
}
return array
}
}
}

View File

@ -0,0 +1,88 @@
// Sources/SwiftProtobuf/Message+TextFormatAdditions.swift - Text format primitive types
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Extensions to `Message` to support text format encoding/decoding.
///
// -----------------------------------------------------------------------------
import Foundation
/// Text format encoding and decoding methods for messages.
extension Message {
/// Returns a string containing the Protocol Buffer text format serialization
/// of the message.
///
/// Unlike binary encoding, presence of required fields is not enforced when
/// serializing to text format.
///
/// - Returns: A string containing the text format serialization of the
/// message.
public func textFormatString() -> String {
// This is implemented as a separate zero-argument function
// to preserve binary compatibility.
return textFormatString(options: TextFormatEncodingOptions())
}
/// Returns a string containing the Protocol Buffer text format serialization
/// of the message.
///
/// Unlike binary encoding, presence of required fields is not enforced when
/// serializing to JSON.
///
/// - Returns: A string containing the text format serialization of the message.
/// - Parameters:
/// - options: The TextFormatEncodingOptions to use.
public func textFormatString(
options: TextFormatEncodingOptions
) -> String {
var visitor = TextFormatEncodingVisitor(message: self, options: options)
if let any = self as? Google_Protobuf_Any {
any._storage.textTraverse(visitor: &visitor)
} else {
// Although the general traversal/encoding infrastructure supports
// throwing errors (needed for JSON/Binary WKTs support, binary format
// missing required fields); TextEncoding never actually does throw.
try! traverse(visitor: &visitor)
}
return visitor.result
}
/// Creates a new message by decoding the given string containing a
/// serialized message in Protocol Buffer text format.
///
/// - Parameters:
/// - textFormatString: The text format string to decode.
/// - extensions: An `ExtensionMap` used to look up and decode any
/// extensions in this message or messages nested within this message's
/// fields.
/// - Throws: an instance of `TextFormatDecodingError` on failure.
public init(
textFormatString: String,
extensions: ExtensionMap? = nil
) throws {
self.init()
if !textFormatString.isEmpty {
if let data = textFormatString.data(using: String.Encoding.utf8) {
try data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
if let baseAddress = body.baseAddress, body.count > 0 {
var decoder = try TextFormatDecoder(messageType: Self.self,
utf8Pointer: baseAddress,
count: body.count,
extensions: extensions)
try decodeMessage(decoder: &decoder)
if !decoder.complete {
throw TextFormatDecodingError.trailingGarbage
}
}
}
}
}
}
}

View File

@ -0,0 +1,216 @@
// Sources/SwiftProtobuf/Message.swift - Message support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
/// The protocol which all generated protobuf messages implement.
/// `Message` is the protocol type you should use whenever
/// you need an argument or variable which holds "some message".
///
/// Generated messages also implement `Hashable`, and thus `Equatable`.
/// However, the protocol conformance is declared on a different protocol.
/// This allows you to use `Message` as a type directly:
///
/// func consume(message: Message) { ... }
///
/// Instead of needing to use it as a type constraint on a generic declaration:
///
/// func consume<M: Message>(message: M) { ... }
///
/// If you need to convince the compiler that your message is `Hashable` so
/// you can insert it into a `Set` or use it as a `Dictionary` key, use
/// a generic declaration with a type constraint:
///
/// func insertIntoSet<M: Message & Hashable>(message: M) {
/// mySet.insert(message)
/// }
///
/// The actual functionality is implemented either in the generated code or in
/// default implementations of the below methods and properties.
public protocol Message: CustomDebugStringConvertible {
/// Creates a new message with all of its fields initialized to their default
/// values.
init()
// Metadata
// Basic facts about this class and the proto message it was generated from
// Used by various encoders and decoders
/// The fully-scoped name of the message from the original .proto file,
/// including any relevant package name.
static var protoMessageName: String { get }
/// True if all required fields (if any) on this message and any nested
/// messages (recursively) have values set; otherwise, false.
var isInitialized: Bool { get }
/// Some formats include enough information to transport fields that were
/// not known at generation time. When encountered, they are stored here.
var unknownFields: UnknownStorage { get set }
//
// General serialization/deserialization machinery
//
/// Decode all of the fields from the given decoder.
///
/// This is a simple loop that repeatedly gets the next field number
/// from `decoder.nextFieldNumber()` and then uses the number returned
/// and the type information from the original .proto file to decide
/// what type of data should be decoded for that field. The corresponding
/// method on the decoder is then called to get the field value.
///
/// This is the core method used by the deserialization machinery. It is
/// `public` to enable users to implement their own encoding formats by
/// conforming to `Decoder`; it should not be called otherwise.
///
/// Note that this is not specific to binary encodng; formats that use
/// textual identifiers translate those to field numbers and also go
/// through this to decode messages.
///
/// - Parameters:
/// - decoder: a `Decoder`; the `Message` will call the method
/// corresponding to the type of this field.
/// - Throws: an error on failure or type mismatch. The type of error
/// thrown depends on which decoder is used.
mutating func decodeMessage<D: Decoder>(decoder: inout D) throws
/// Traverses the fields of the message, calling the appropriate methods
/// of the passed `Visitor` object.
///
/// This is used internally by:
///
/// * Protobuf binary serialization
/// * JSON serialization (with some twists to account for specialty JSON)
/// * Protobuf Text serialization
/// * `Hashable` computation
///
/// Conceptually, serializers create visitor objects that are
/// then passed recursively to every message and field via generated
/// `traverse` methods. The details get a little involved due to
/// the need to allow particular messages to override particular
/// behaviors for specific encodings, but the general idea is quite simple.
func traverse<V: Visitor>(visitor: inout V) throws
// Standard utility properties and methods.
// Most of these are simple wrappers on top of the visitor machinery.
// They are implemented in the protocol, not in the generated structs,
// so can be overridden in user code by defining custom extensions to
// the generated struct.
#if swift(>=4.2)
/// An implementation of hash(into:) to provide conformance with the
/// `Hashable` protocol.
func hash(into hasher: inout Hasher)
#else // swift(>=4.2)
/// The hash value generated from this message's contents, for conformance
/// with the `Hashable` protocol.
var hashValue: Int { get }
#endif // swift(>=4.2)
/// Helper to compare `Message`s when not having a specific type to use
/// normal `Equatable`. `Equatable` is provided with specific generated
/// types.
func isEqualTo(message: Message) -> Bool
}
extension Message {
/// Generated proto2 messages that contain required fields, nested messages
/// that contain required fields, and/or extensions will provide their own
/// implementation of this property that tests that all required fields are
/// set. Users of the generated code SHOULD NOT override this property.
public var isInitialized: Bool {
// The generated code will include a specialization as needed.
return true
}
/// A hash based on the message's full contents.
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
var visitor = HashVisitor(hasher)
try? traverse(visitor: &visitor)
hasher = visitor.hasher
}
#else // swift(>=4.2)
public var hashValue: Int {
var visitor = HashVisitor()
try? traverse(visitor: &visitor)
return visitor.hashValue
}
#endif // swift(>=4.2)
/// A description generated by recursively visiting all fields in the message,
/// including messages.
public var debugDescription: String {
// TODO Ideally there would be something like serializeText() that can
// take a prefix so we could do something like:
// [class name](
// [text format]
// )
let className = String(reflecting: type(of: self))
let header = "\(className):\n"
return header + textFormatString()
}
/// Creates an instance of the message type on which this method is called,
/// executes the given block passing the message in as its sole `inout`
/// argument, and then returns the message.
///
/// This method acts essentially as a "builder" in that the initialization of
/// the message is captured within the block, allowing the returned value to
/// be set in an immutable variable. For example,
///
/// let msg = MyMessage.with { $0.myField = "foo" }
/// msg.myOtherField = 5 // error: msg is immutable
///
/// - Parameter populator: A block or function that populates the new message,
/// which is passed into the block as an `inout` argument.
/// - Returns: The message after execution of the block.
public static func with(
_ populator: (inout Self) throws -> ()
) rethrows -> Self {
var message = Self()
try populator(&message)
return message
}
}
/// Implementation base for all messages; not intended for client use.
///
/// In general, use `SwiftProtobuf.Message` instead when you need a variable or
/// argument that can hold any type of message. Occasionally, you can use
/// `SwiftProtobuf.Message & Equatable` or `SwiftProtobuf.Message & Hashable` as
/// generic constraints if you need to write generic code that can be applied to
/// multiple message types that uses equality tests, puts messages in a `Set`,
/// or uses them as `Dictionary` keys.
public protocol _MessageImplementationBase: Message, Hashable {
// Legacy function; no longer used, but left to maintain source compatibility.
func _protobuf_generated_isEqualTo(other: Self) -> Bool
}
extension _MessageImplementationBase {
public func isEqualTo(message: Message) -> Bool {
guard let other = message as? Self else {
return false
}
return self == other
}
// Legacy default implementation that is used by old generated code, current
// versions of the plugin/generator provide this directly, but this is here
// just to avoid breaking source compatibility.
public static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs._protobuf_generated_isEqualTo(other: rhs)
}
// Legacy function that is generated by old versions of the plugin/generator,
// defaulted to keep things simple without changing the api surface.
public func _protobuf_generated_isEqualTo(other: Self) -> Bool {
return self == other
}
}

View File

@ -0,0 +1,41 @@
// Sources/SwiftProtobuf/MessageExtension.swift - Extension support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// A 'Message Extension' is an immutable class object that describes
/// a particular extension field, including string and number
/// identifiers, serialization details, and the identity of the
/// message that is being extended.
///
// -----------------------------------------------------------------------------
/// Type-erased MessageExtension field implementation.
public protocol AnyMessageExtension {
var fieldNumber: Int { get }
var fieldName: String { get }
var messageType: Message.Type { get }
func _protobuf_newField<D: Decoder>(decoder: inout D) throws -> AnyExtensionField?
}
/// A "Message Extension" relates a particular extension field to
/// a particular message. The generic constraints allow
/// compile-time compatibility checks.
public class MessageExtension<FieldType: ExtensionField, MessageType: Message>: AnyMessageExtension {
public let fieldNumber: Int
public let fieldName: String
public let messageType: Message.Type
public init(_protobuf_fieldNumber: Int, fieldName: String) {
self.fieldNumber = _protobuf_fieldNumber
self.fieldName = fieldName
self.messageType = MessageType.self
}
public func _protobuf_newField<D: Decoder>(decoder: inout D) throws -> AnyExtensionField? {
return try FieldType(protobufExtension: self, decoder: &decoder)
}
}

View File

@ -0,0 +1,310 @@
// Sources/SwiftProtobuf/NameMap.swift - Bidirectional number/name mapping
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
/// TODO: Right now, only the NameMap and the NameDescription enum
/// (which are directly used by the generated code) are public.
/// This means that code outside the library has no way to actually
/// use this data. We should develop and publicize a suitable API
/// for that purpose. (Which might be the same as the internal API.)
/// This must be exactly the same as the corresponding code in the
/// protoc-gen-swift code generator. Changing it will break
/// compatibility of the library with older generated code.
///
/// It does not necessarily need to match protoc's JSON field naming
/// logic, however.
private func toJsonFieldName(_ s: String) -> String {
var result = String()
var capitalizeNext = false
for c in s {
if c == "_" {
capitalizeNext = true
} else if capitalizeNext {
result.append(String(c).uppercased())
capitalizeNext = false
} else {
result.append(String(c))
}
}
return result
}
/// Allocate static memory buffers to intern UTF-8
/// string data. Track the buffers and release all of those buffers
/// in case we ever get deallocated.
fileprivate class InternPool {
private var interned = [UnsafeRawBufferPointer]()
func intern(utf8: String.UTF8View) -> UnsafeRawBufferPointer {
#if swift(>=4.1)
let mutable = UnsafeMutableRawBufferPointer.allocate(byteCount: utf8.count,
alignment: MemoryLayout<UInt8>.alignment)
#else
let mutable = UnsafeMutableRawBufferPointer.allocate(count: utf8.count)
#endif
mutable.copyBytes(from: utf8)
let immutable = UnsafeRawBufferPointer(mutable)
interned.append(immutable)
return immutable
}
func intern(utf8Ptr: UnsafeBufferPointer<UInt8>) -> UnsafeRawBufferPointer {
#if swift(>=4.1)
let mutable = UnsafeMutableRawBufferPointer.allocate(byteCount: utf8Ptr.count,
alignment: MemoryLayout<UInt8>.alignment)
#else
let mutable = UnsafeMutableRawBufferPointer.allocate(count: utf8.count)
#endif
mutable.copyBytes(from: utf8Ptr)
let immutable = UnsafeRawBufferPointer(mutable)
interned.append(immutable)
return immutable
}
deinit {
for buff in interned {
#if swift(>=4.1)
buff.deallocate()
#else
let p = UnsafeMutableRawPointer(mutating: buff.baseAddress)!
p.deallocate(bytes: buff.count, alignedTo: 1)
#endif
}
}
}
#if !swift(>=4.2)
// Constants for FNV hash http://tools.ietf.org/html/draft-eastlake-fnv-03
private let i_2166136261 = Int(bitPattern: 2166136261)
private let i_16777619 = Int(16777619)
#endif
/// An immutable bidirectional mapping between field/enum-case names
/// and numbers, used to record field names for text-based
/// serialization (JSON and text). These maps are lazily instantiated
/// for each message as needed, so there is no run-time overhead for
/// users who do not use text-based serialization formats.
public struct _NameMap: ExpressibleByDictionaryLiteral {
/// An immutable interned string container. The `utf8Start` pointer
/// is guaranteed valid for the lifetime of the `NameMap` that you
/// fetched it from. Since `NameMap`s are only instantiated as
/// immutable static values, that should be the lifetime of the
/// program.
///
/// Internally, this uses `StaticString` (which refers to a fixed
/// block of UTF-8 data) where possible. In cases where the string
/// has to be computed, it caches the UTF-8 bytes in an
/// unmovable and immutable heap area.
internal struct Name: Hashable, CustomStringConvertible {
// This should not be used outside of this file, as it requires
// coordinating the lifecycle with the lifecycle of the pool
// where the raw UTF8 gets interned.
fileprivate init(staticString: StaticString, pool: InternPool) {
self.nameString = .staticString(staticString)
if staticString.hasPointerRepresentation {
self.utf8Buffer = UnsafeRawBufferPointer(start: staticString.utf8Start,
count: staticString.utf8CodeUnitCount)
} else {
self.utf8Buffer = staticString.withUTF8Buffer { pool.intern(utf8Ptr: $0) }
}
}
// This should not be used outside of this file, as it requires
// coordinating the lifecycle with the lifecycle of the pool
// where the raw UTF8 gets interned.
fileprivate init(string: String, pool: InternPool) {
let utf8 = string.utf8
self.utf8Buffer = pool.intern(utf8: utf8)
self.nameString = .string(string)
}
// This is for building a transient `Name` object sufficient for lookup purposes.
// It MUST NOT be exposed outside of this file.
fileprivate init(transientUtf8Buffer: UnsafeRawBufferPointer) {
self.nameString = .staticString("")
self.utf8Buffer = transientUtf8Buffer
}
private(set) var utf8Buffer: UnsafeRawBufferPointer
private enum NameString {
case string(String)
case staticString(StaticString)
}
private var nameString: NameString
public var description: String {
switch nameString {
case .string(let s): return s
case .staticString(let s): return s.description
}
}
#if swift(>=4.2)
public func hash(into hasher: inout Hasher) {
for byte in utf8Buffer {
hasher.combine(byte)
}
}
#else // swift(>=4.2)
public var hashValue: Int {
var h = i_2166136261
for byte in utf8Buffer {
h = (h ^ Int(byte)) &* i_16777619
}
return h
}
#endif // swift(>=4.2)
public static func ==(lhs: Name, rhs: Name) -> Bool {
if lhs.utf8Buffer.count != rhs.utf8Buffer.count {
return false
}
return lhs.utf8Buffer.elementsEqual(rhs.utf8Buffer)
}
}
/// The JSON and proto names for a particular field, enum case, or extension.
internal struct Names {
private(set) var json: Name?
private(set) var proto: Name
}
/// A description of the names for a particular field or enum case.
/// The different forms here let us minimize the amount of string
/// data that we store in the binary.
///
/// These are only used in the generated code to initialize a NameMap.
public enum NameDescription {
/// The proto (text format) name and the JSON name are the same string.
case same(proto: StaticString)
/// The JSON name can be computed from the proto string
case standard(proto: StaticString)
/// The JSON and text format names are just different.
case unique(proto: StaticString, json: StaticString)
/// Used for enum cases only to represent a value's primary proto name (the
/// first defined case) and its aliases. The JSON and text format names for
/// enums are always the same.
case aliased(proto: StaticString, aliases: [StaticString])
}
private var internPool = InternPool()
/// The mapping from field/enum-case numbers to names.
private var numberToNameMap: [Int: Names] = [:]
/// The mapping from proto/text names to field/enum-case numbers.
private var protoToNumberMap: [Name: Int] = [:]
/// The mapping from JSON names to field/enum-case numbers.
/// Note that this also contains all of the proto/text names,
/// as required by Google's spec for protobuf JSON.
private var jsonToNumberMap: [Name: Int] = [:]
/// Creates a new empty field/enum-case name/number mapping.
public init() {}
/// Build the bidirectional maps between numbers and proto/JSON names.
public init(dictionaryLiteral elements: (Int, NameDescription)...) {
for (number, description) in elements {
switch description {
case .same(proto: let p):
let protoName = Name(staticString: p, pool: internPool)
let names = Names(json: protoName, proto: protoName)
numberToNameMap[number] = names
protoToNumberMap[protoName] = number
jsonToNumberMap[protoName] = number
case .standard(proto: let p):
let protoName = Name(staticString: p, pool: internPool)
let jsonString = toJsonFieldName(protoName.description)
let jsonName = Name(string: jsonString, pool: internPool)
let names = Names(json: jsonName, proto: protoName)
numberToNameMap[number] = names
protoToNumberMap[protoName] = number
jsonToNumberMap[protoName] = number
jsonToNumberMap[jsonName] = number
case .unique(proto: let p, json: let j):
let jsonName = Name(staticString: j, pool: internPool)
let protoName = Name(staticString: p, pool: internPool)
let names = Names(json: jsonName, proto: protoName)
numberToNameMap[number] = names
protoToNumberMap[protoName] = number
jsonToNumberMap[protoName] = number
jsonToNumberMap[jsonName] = number
case .aliased(proto: let p, aliases: let aliases):
let protoName = Name(staticString: p, pool: internPool)
let names = Names(json: protoName, proto: protoName)
numberToNameMap[number] = names
protoToNumberMap[protoName] = number
jsonToNumberMap[protoName] = number
for alias in aliases {
let protoName = Name(staticString: alias, pool: internPool)
protoToNumberMap[protoName] = number
jsonToNumberMap[protoName] = number
}
}
}
}
/// Returns the name bundle for the field/enum-case with the given number, or
/// `nil` if there is no match.
internal func names(for number: Int) -> Names? {
return numberToNameMap[number]
}
/// Returns the field/enum-case number that has the given JSON name,
/// or `nil` if there is no match.
///
/// This is used by the Text format parser to look up field or enum
/// names using a direct reference to the un-decoded UTF8 bytes.
internal func number(forProtoName raw: UnsafeRawBufferPointer) -> Int? {
let n = Name(transientUtf8Buffer: raw)
return protoToNumberMap[n]
}
/// Returns the field/enum-case number that has the given JSON name,
/// or `nil` if there is no match.
///
/// This accepts a regular `String` and is used in JSON parsing
/// only when a field name or enum name was decoded from a string
/// containing backslash escapes.
///
/// JSON parsing must interpret *both* the JSON name of the
/// field/enum-case provided by the descriptor *as well as* its
/// original proto/text name.
internal func number(forJSONName name: String) -> Int? {
let utf8 = Array(name.utf8)
return utf8.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) in
let n = Name(transientUtf8Buffer: buffer)
return jsonToNumberMap[n]
}
}
/// Returns the field/enum-case number that has the given JSON name,
/// or `nil` if there is no match.
///
/// This is used by the JSON parser when a field name or enum name
/// required no special processing. As a result, we can avoid
/// copying the name and look up the number using a direct reference
/// to the un-decoded UTF8 bytes.
internal func number(forJSONName raw: UnsafeRawBufferPointer) -> Int? {
let n = Name(transientUtf8Buffer: raw)
return jsonToNumberMap[n]
}
}

View File

@ -0,0 +1,23 @@
// Sources/SwiftProtobuf/ProtoNameProviding.swift - Support for accessing proto names
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
/// SwiftProtobuf Internal: Common support looking up field names.
///
/// Messages conform to this protocol to provide the proto/text and JSON field
/// names for their fields. This allows these names to be pulled out into
/// extensions in separate files so that users can omit them in release builds
/// (reducing bloat and minimizing leaks of field names).
public protocol _ProtoNameProviding {
/// The mapping between field numbers and proto/JSON field names defined in
/// the conforming message type.
static var _protobuf_nameMap: _NameMap { get }
}

View File

@ -0,0 +1,43 @@
// Sources/SwiftProtobuf/ProtobufAPIVersionCheck.swift - Version checking
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// A scheme that ensures that generated protos cannot be compiled or linked
/// against a version of the runtime with which they are not compatible.
///
/// In many cases, API changes themselves might introduce incompatibilities
/// between generated code and the runtime library, but we also want to protect
/// against cases where breaking behavioral changes (without affecting the API)
/// would cause generated code to be incompatible with a particular version of
/// the runtime.
///
// -----------------------------------------------------------------------------
/// An empty protocol that encodes the version of the runtime library.
///
/// This protocol will be replaced with one containing a different version
/// number any time that breaking changes are made to the Swift Protobuf API.
/// Combined with the protocol below, this lets us verify that generated code is
/// never compiled against a version of the API with which it is incompatible.
///
/// The version associated with a particular build of the compiler is defined as
/// `Version.compatibilityVersion` in `protoc-gen-swift`. That version and this
/// version must match for the generated protos to be compatible, so if you
/// update one, make sure to update it here and in the associated type below.
public protocol ProtobufAPIVersion_2 {}
/// This protocol is expected to be implemented by a `fileprivate` type in each
/// source file emitted by `protoc-gen-swift`. It effectively creates a binding
/// between the version of the generated code and the version of this library,
/// causing a compile-time error (with reasonable diagnostics) if they are
/// incompatible.
public protocol ProtobufAPIVersionCheck {
associatedtype Version: ProtobufAPIVersion_2
}

View File

@ -0,0 +1,39 @@
// Sources/SwiftProtobuf/ProtobufMap.swift - Map<> support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Generic type representing proto map<> fields.
///
// -----------------------------------------------------------------------------
import Foundation
/// SwiftProtobuf Internal: Support for Encoding/Decoding.
public struct _ProtobufMap<KeyType: MapKeyType, ValueType: FieldType>
{
public typealias Key = KeyType.BaseType
public typealias Value = ValueType.BaseType
public typealias BaseType = Dictionary<Key, Value>
}
/// SwiftProtobuf Internal: Support for Encoding/Decoding.
public struct _ProtobufMessageMap<KeyType: MapKeyType, ValueType: Message & Hashable>
{
public typealias Key = KeyType.BaseType
public typealias Value = ValueType
public typealias BaseType = Dictionary<Key, Value>
}
/// SwiftProtobuf Internal: Support for Encoding/Decoding.
public struct _ProtobufEnumMap<KeyType: MapKeyType, ValueType: Enum>
{
public typealias Key = KeyType.BaseType
public typealias Value = ValueType
public typealias BaseType = Dictionary<Key, Value>
}

View File

@ -0,0 +1,268 @@
// Sources/SwiftProtobuf/SelectiveVisitor.swift - Base for custom Visitors
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// A base for Visitors that only expect a subset of things to called.
///
// -----------------------------------------------------------------------------
import Foundation
/// A base for Visitors that only expects a subset of things to called.
internal protocol SelectiveVisitor: Visitor {
// Adds nothing.
}
/// Default impls for everything so things using this only have to write the
/// methods they expect. Asserts to catch developer errors, but becomes
/// nothing in release to keep code size small.
///
/// NOTE: This is an impl for *everything*. This means the default impls
/// provided by Visitor to bridge packed->repeated, repeated->singular, etc
/// won't kick in.
extension SelectiveVisitor {
internal mutating func visitSingularFloatField(value: Float, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularInt32Field(value: Int32, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularUInt32Field(value: UInt32, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularSInt32Field(value: Int32, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularSInt64Field(value: Int64, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularFixed32Field(value: UInt32, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularFixed64Field(value: UInt64, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularSFixed32Field(value: Int32, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularSFixed64Field(value: Int64, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularEnumField<E: Enum>(value: E, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularMessageField<M: Message>(value: M, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitSingularGroupField<G: Message>(value: G, fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedFloatField(value: [Float], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedDoubleField(value: [Double], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedSInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedSInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedBoolField(value: [Bool], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedStringField(value: [String], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedBytesField(value: [Data], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedMessageField<M: Message>(value: [M], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitRepeatedGroupField<G: Message>(value: [G], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedFloatField(value: [Float], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedDoubleField(value: [Double], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedSInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedSInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedBoolField(value: [Bool], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitPackedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitMapField<KeyType, ValueType: MapValueType>(
fieldType: _ProtobufMap<KeyType, ValueType>.Type,
value: _ProtobufMap<KeyType, ValueType>.BaseType,
fieldNumber: Int) throws {
assert(false)
}
internal mutating func visitMapField<KeyType, ValueType>(
fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
value: _ProtobufEnumMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws where ValueType.RawValue == Int {
assert(false)
}
internal mutating func visitMapField<KeyType, ValueType>(
fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
value: _ProtobufMessageMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws {
assert(false)
}
internal mutating func visitExtensionFields(fields: ExtensionFieldValueSet, start: Int, end: Int) throws {
assert(false)
}
internal mutating func visitExtensionFieldsAsMessageSet(
fields: ExtensionFieldValueSet,
start: Int,
end: Int
) throws {
assert(false)
}
internal mutating func visitUnknown(bytes: Data) throws {
assert(false)
}
}

View File

@ -0,0 +1,112 @@
// Sources/SwiftProtobuf/SimpleExtensionMap.swift - Extension support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// A default implementation of ExtensionMap.
///
// -----------------------------------------------------------------------------
// Note: The generated code only relies on ExpressibleByArrayLiteral
public struct SimpleExtensionMap: ExtensionMap, ExpressibleByArrayLiteral, CustomDebugStringConvertible {
public typealias Element = AnyMessageExtension
// Since type objects aren't Hashable, we can't do much better than this...
internal var fields = [Int: Array<AnyMessageExtension>]()
public init() {}
public init(arrayLiteral: Element...) {
insert(contentsOf: arrayLiteral)
}
public init(_ others: SimpleExtensionMap...) {
for other in others {
formUnion(other)
}
}
public subscript(messageType: Message.Type, fieldNumber: Int) -> AnyMessageExtension? {
get {
if let l = fields[fieldNumber] {
for e in l {
if messageType == e.messageType {
return e
}
}
}
return nil
}
}
public func fieldNumberForProto(messageType: Message.Type, protoFieldName: String) -> Int? {
// TODO: Make this faster...
for (_, list) in fields {
for e in list {
if e.fieldName == protoFieldName && e.messageType == messageType {
return e.fieldNumber
}
}
}
return nil
}
public mutating func insert(_ newValue: Element) {
let fieldNumber = newValue.fieldNumber
if let l = fields[fieldNumber] {
let messageType = newValue.messageType
var newL = l.filter { return $0.messageType != messageType }
newL.append(newValue)
fields[fieldNumber] = newL
} else {
fields[fieldNumber] = [newValue]
}
}
public mutating func insert(contentsOf: [Element]) {
for e in contentsOf {
insert(e)
}
}
public mutating func formUnion(_ other: SimpleExtensionMap) {
for (fieldNumber, otherList) in other.fields {
if let list = fields[fieldNumber] {
var newList = list.filter {
for o in otherList {
if $0.messageType == o.messageType { return false }
}
return true
}
newList.append(contentsOf: otherList)
fields[fieldNumber] = newList
} else {
fields[fieldNumber] = otherList
}
}
}
public func union(_ other: SimpleExtensionMap) -> SimpleExtensionMap {
var out = self
out.formUnion(other)
return out
}
public var debugDescription: String {
var names = [String]()
for (_, list) in fields {
for e in list {
names.append("\(e.fieldName):(\(e.fieldNumber))")
}
}
let d = names.joined(separator: ",")
return "SimpleExtensionMap(\(d))"
}
}

View File

@ -0,0 +1,73 @@
// Sources/SwiftProtobuf/StringUtils.swift - String utility functions
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Utility functions for converting UTF8 bytes into Strings.
/// These functions must:
/// * Accept any valid UTF8, including a zero byte (which is
/// a valid UTF8 encoding of U+0000)
/// * Return nil for any invalid UTF8
/// * Be fast (since they're extensively used by all decoders
/// and even some of the encoders)
///
// -----------------------------------------------------------------------------
import Foundation
// Wrapper that takes a buffer and start/end offsets
internal func utf8ToString(
bytes: UnsafeRawBufferPointer,
start: UnsafeRawBufferPointer.Index,
end: UnsafeRawBufferPointer.Index
) -> String? {
return utf8ToString(bytes: bytes.baseAddress! + start, count: end - start)
}
// Swift 4 introduced new faster String facilities
// that seem to work consistently across all platforms.
// Notes on performance:
//
// The pre-verification here only takes about 10% of
// the time needed for constructing the string.
// Eliminating it would provide only a very minor
// speed improvement.
//
// On macOS, this is only about 25% faster than
// the Foundation initializer used below for Swift 3.
// On Linux, the Foundation initializer is much
// slower than on macOS, so this is a much bigger
// win there.
internal func utf8ToString(bytes: UnsafeRawPointer, count: Int) -> String? {
if count == 0 {
return String()
}
let codeUnits = UnsafeRawBufferPointer(start: bytes, count: count)
let sourceEncoding = Unicode.UTF8.self
// Verify that the UTF-8 is valid.
var p = sourceEncoding.ForwardParser()
var i = codeUnits.makeIterator()
Loop:
while true {
switch p.parseScalar(from: &i) {
case .valid(_):
break
case .error:
return nil
case .emptyInput:
break Loop
}
}
// This initializer is fast but does not reject broken
// UTF-8 (which is why we validate the UTF-8 above).
return String(decoding: codeUnits, as: sourceEncoding)
}

View File

@ -0,0 +1,713 @@
// Sources/SwiftProtobuf/TextFormatDecoder.swift - Text format decoding
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Test format decoding engine.
///
// -----------------------------------------------------------------------------
import Foundation
///
/// Provides a higher-level interface to the token stream coming
/// from a TextFormatScanner. In particular, this provides
/// single-token pushback and convenience functions for iterating
/// over complex structures.
///
internal struct TextFormatDecoder: Decoder {
internal var scanner: TextFormatScanner
private var fieldCount = 0
private var terminator: UInt8?
private var fieldNameMap: _NameMap?
private var messageType: Message.Type?
internal var complete: Bool {
mutating get {
return scanner.complete
}
}
internal init(messageType: Message.Type, utf8Pointer: UnsafeRawPointer, count: Int, extensions: ExtensionMap?) throws {
scanner = TextFormatScanner(utf8Pointer: utf8Pointer, count: count, extensions: extensions)
guard let nameProviding = (messageType as? _ProtoNameProviding.Type) else {
throw TextFormatDecodingError.missingFieldNames
}
fieldNameMap = nameProviding._protobuf_nameMap
self.messageType = messageType
}
internal init(messageType: Message.Type, scanner: TextFormatScanner, terminator: UInt8?) throws {
self.scanner = scanner
self.terminator = terminator
guard let nameProviding = (messageType as? _ProtoNameProviding.Type) else {
throw TextFormatDecodingError.missingFieldNames
}
fieldNameMap = nameProviding._protobuf_nameMap
self.messageType = messageType
}
mutating func handleConflictingOneOf() throws {
throw TextFormatDecodingError.conflictingOneOf
}
mutating func nextFieldNumber() throws -> Int? {
if let terminator = terminator {
if scanner.skipOptionalObjectEnd(terminator) {
return nil
}
}
if fieldCount > 0 {
scanner.skipOptionalSeparator()
}
if let key = try scanner.nextOptionalExtensionKey() {
// Extension key; look up in the extension registry
if let fieldNumber = scanner.extensions?.fieldNumberForProto(messageType: messageType!, protoFieldName: key) {
fieldCount += 1
return fieldNumber
} else {
throw TextFormatDecodingError.unknownField
}
} else if let fieldNumber = try scanner.nextFieldNumber(names: fieldNameMap!) {
fieldCount += 1
return fieldNumber
} else if terminator == nil {
return nil
} else {
throw TextFormatDecodingError.truncated
}
}
mutating func decodeSingularFloatField(value: inout Float) throws {
try scanner.skipRequiredColon()
value = try scanner.nextFloat()
}
mutating func decodeSingularFloatField(value: inout Float?) throws {
try scanner.skipRequiredColon()
value = try scanner.nextFloat()
}
mutating func decodeRepeatedFloatField(value: inout [Float]) throws {
try scanner.skipRequiredColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
let n = try scanner.nextFloat()
value.append(n)
}
} else {
let n = try scanner.nextFloat()
value.append(n)
}
}
mutating func decodeSingularDoubleField(value: inout Double) throws {
try scanner.skipRequiredColon()
value = try scanner.nextDouble()
}
mutating func decodeSingularDoubleField(value: inout Double?) throws {
try scanner.skipRequiredColon()
value = try scanner.nextDouble()
}
mutating func decodeRepeatedDoubleField(value: inout [Double]) throws {
try scanner.skipRequiredColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
let n = try scanner.nextDouble()
value.append(n)
}
} else {
let n = try scanner.nextDouble()
value.append(n)
}
}
mutating func decodeSingularInt32Field(value: inout Int32) throws {
try scanner.skipRequiredColon()
let n = try scanner.nextSInt()
if n > Int64(Int32.max) || n < Int64(Int32.min) {
throw TextFormatDecodingError.malformedNumber
}
value = Int32(truncatingIfNeeded: n)
}
mutating func decodeSingularInt32Field(value: inout Int32?) throws {
try scanner.skipRequiredColon()
let n = try scanner.nextSInt()
if n > Int64(Int32.max) || n < Int64(Int32.min) {
throw TextFormatDecodingError.malformedNumber
}
value = Int32(truncatingIfNeeded: n)
}
mutating func decodeRepeatedInt32Field(value: inout [Int32]) throws {
try scanner.skipRequiredColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
let n = try scanner.nextSInt()
if n > Int64(Int32.max) || n < Int64(Int32.min) {
throw TextFormatDecodingError.malformedNumber
}
value.append(Int32(truncatingIfNeeded: n))
}
} else {
let n = try scanner.nextSInt()
if n > Int64(Int32.max) || n < Int64(Int32.min) {
throw TextFormatDecodingError.malformedNumber
}
value.append(Int32(truncatingIfNeeded: n))
}
}
mutating func decodeSingularInt64Field(value: inout Int64) throws {
try scanner.skipRequiredColon()
value = try scanner.nextSInt()
}
mutating func decodeSingularInt64Field(value: inout Int64?) throws {
try scanner.skipRequiredColon()
value = try scanner.nextSInt()
}
mutating func decodeRepeatedInt64Field(value: inout [Int64]) throws {
try scanner.skipRequiredColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
let n = try scanner.nextSInt()
value.append(n)
}
} else {
let n = try scanner.nextSInt()
value.append(n)
}
}
mutating func decodeSingularUInt32Field(value: inout UInt32) throws {
try scanner.skipRequiredColon()
let n = try scanner.nextUInt()
if n > UInt64(UInt32.max) {
throw TextFormatDecodingError.malformedNumber
}
value = UInt32(truncatingIfNeeded: n)
}
mutating func decodeSingularUInt32Field(value: inout UInt32?) throws {
try scanner.skipRequiredColon()
let n = try scanner.nextUInt()
if n > UInt64(UInt32.max) {
throw TextFormatDecodingError.malformedNumber
}
value = UInt32(truncatingIfNeeded: n)
}
mutating func decodeRepeatedUInt32Field(value: inout [UInt32]) throws {
try scanner.skipRequiredColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
let n = try scanner.nextUInt()
if n > UInt64(UInt32.max) {
throw TextFormatDecodingError.malformedNumber
}
value.append(UInt32(truncatingIfNeeded: n))
}
} else {
let n = try scanner.nextUInt()
if n > UInt64(UInt32.max) {
throw TextFormatDecodingError.malformedNumber
}
value.append(UInt32(truncatingIfNeeded: n))
}
}
mutating func decodeSingularUInt64Field(value: inout UInt64) throws {
try scanner.skipRequiredColon()
value = try scanner.nextUInt()
}
mutating func decodeSingularUInt64Field(value: inout UInt64?) throws {
try scanner.skipRequiredColon()
value = try scanner.nextUInt()
}
mutating func decodeRepeatedUInt64Field(value: inout [UInt64]) throws {
try scanner.skipRequiredColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
let n = try scanner.nextUInt()
value.append(n)
}
} else {
let n = try scanner.nextUInt()
value.append(n)
}
}
mutating func decodeSingularSInt32Field(value: inout Int32) throws {
try decodeSingularInt32Field(value: &value)
}
mutating func decodeSingularSInt32Field(value: inout Int32?) throws {
try decodeSingularInt32Field(value: &value)
}
mutating func decodeRepeatedSInt32Field(value: inout [Int32]) throws {
try decodeRepeatedInt32Field(value: &value)
}
mutating func decodeSingularSInt64Field(value: inout Int64) throws {
try decodeSingularInt64Field(value: &value)
}
mutating func decodeSingularSInt64Field(value: inout Int64?) throws {
try decodeSingularInt64Field(value: &value)
}
mutating func decodeRepeatedSInt64Field(value: inout [Int64]) throws {
try decodeRepeatedInt64Field(value: &value)
}
mutating func decodeSingularFixed32Field(value: inout UInt32) throws {
try decodeSingularUInt32Field(value: &value)
}
mutating func decodeSingularFixed32Field(value: inout UInt32?) throws {
try decodeSingularUInt32Field(value: &value)
}
mutating func decodeRepeatedFixed32Field(value: inout [UInt32]) throws {
try decodeRepeatedUInt32Field(value: &value)
}
mutating func decodeSingularFixed64Field(value: inout UInt64) throws {
try decodeSingularUInt64Field(value: &value)
}
mutating func decodeSingularFixed64Field(value: inout UInt64?) throws {
try decodeSingularUInt64Field(value: &value)
}
mutating func decodeRepeatedFixed64Field(value: inout [UInt64]) throws {
try decodeRepeatedUInt64Field(value: &value)
}
mutating func decodeSingularSFixed32Field(value: inout Int32) throws {
try decodeSingularInt32Field(value: &value)
}
mutating func decodeSingularSFixed32Field(value: inout Int32?) throws {
try decodeSingularInt32Field(value: &value)
}
mutating func decodeRepeatedSFixed32Field(value: inout [Int32]) throws {
try decodeRepeatedInt32Field(value: &value)
}
mutating func decodeSingularSFixed64Field(value: inout Int64) throws {
try decodeSingularInt64Field(value: &value)
}
mutating func decodeSingularSFixed64Field(value: inout Int64?) throws {
try decodeSingularInt64Field(value: &value)
}
mutating func decodeRepeatedSFixed64Field(value: inout [Int64]) throws {
try decodeRepeatedInt64Field(value: &value)
}
mutating func decodeSingularBoolField(value: inout Bool) throws {
try scanner.skipRequiredColon()
value = try scanner.nextBool()
}
mutating func decodeSingularBoolField(value: inout Bool?) throws {
try scanner.skipRequiredColon()
value = try scanner.nextBool()
}
mutating func decodeRepeatedBoolField(value: inout [Bool]) throws {
try scanner.skipRequiredColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
let n = try scanner.nextBool()
value.append(n)
}
} else {
let n = try scanner.nextBool()
value.append(n)
}
}
mutating func decodeSingularStringField(value: inout String) throws {
try scanner.skipRequiredColon()
value = try scanner.nextStringValue()
}
mutating func decodeSingularStringField(value: inout String?) throws {
try scanner.skipRequiredColon()
value = try scanner.nextStringValue()
}
mutating func decodeRepeatedStringField(value: inout [String]) throws {
try scanner.skipRequiredColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
let n = try scanner.nextStringValue()
value.append(n)
}
} else {
let n = try scanner.nextStringValue()
value.append(n)
}
}
mutating func decodeSingularBytesField(value: inout Data) throws {
try scanner.skipRequiredColon()
value = try scanner.nextBytesValue()
}
mutating func decodeSingularBytesField(value: inout Data?) throws {
try scanner.skipRequiredColon()
value = try scanner.nextBytesValue()
}
mutating func decodeRepeatedBytesField(value: inout [Data]) throws {
try scanner.skipRequiredColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
let n = try scanner.nextBytesValue()
value.append(n)
}
} else {
let n = try scanner.nextBytesValue()
value.append(n)
}
}
private mutating func decodeEnum<E: Enum>() throws -> E where E.RawValue == Int {
if let name = try scanner.nextOptionalEnumName() {
if let b = E(rawUTF8: name) {
return b
} else {
throw TextFormatDecodingError.unrecognizedEnumValue
}
}
let number = try scanner.nextSInt()
if number >= Int64(Int32.min) && number <= Int64(Int32.max) {
let n = Int32(truncatingIfNeeded: number)
if let e = E(rawValue: Int(n)) {
return e
} else {
throw TextFormatDecodingError.unrecognizedEnumValue
}
}
throw TextFormatDecodingError.malformedText
}
mutating func decodeSingularEnumField<E: Enum>(value: inout E?) throws where E.RawValue == Int {
try scanner.skipRequiredColon()
let e: E = try decodeEnum()
value = e
}
mutating func decodeSingularEnumField<E: Enum>(value: inout E) throws where E.RawValue == Int {
try scanner.skipRequiredColon()
let e: E = try decodeEnum()
value = e
}
mutating func decodeRepeatedEnumField<E: Enum>(value: inout [E]) throws where E.RawValue == Int {
try scanner.skipRequiredColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
let e: E = try decodeEnum()
value.append(e)
}
} else {
let e: E = try decodeEnum()
value.append(e)
}
}
mutating func decodeSingularMessageField<M: Message>(value: inout M?) throws {
_ = scanner.skipOptionalColon()
if value == nil {
value = M()
}
let terminator = try scanner.skipObjectStart()
var subDecoder = try TextFormatDecoder(messageType: M.self,scanner: scanner, terminator: terminator)
if M.self == Google_Protobuf_Any.self {
var any = value as! Google_Protobuf_Any?
try any!.decodeTextFormat(decoder: &subDecoder)
value = any as! M?
} else {
try value!.decodeMessage(decoder: &subDecoder)
}
scanner = subDecoder.scanner
}
mutating func decodeRepeatedMessageField<M: Message>(value: inout [M]) throws {
_ = scanner.skipOptionalColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
let terminator = try scanner.skipObjectStart()
var subDecoder = try TextFormatDecoder(messageType: M.self,scanner: scanner, terminator: terminator)
if M.self == Google_Protobuf_Any.self {
var message = Google_Protobuf_Any()
try message.decodeTextFormat(decoder: &subDecoder)
value.append(message as! M)
} else {
var message = M()
try message.decodeMessage(decoder: &subDecoder)
value.append(message)
}
scanner = subDecoder.scanner
}
} else {
let terminator = try scanner.skipObjectStart()
var subDecoder = try TextFormatDecoder(messageType: M.self,scanner: scanner, terminator: terminator)
if M.self == Google_Protobuf_Any.self {
var message = Google_Protobuf_Any()
try message.decodeTextFormat(decoder: &subDecoder)
value.append(message as! M)
} else {
var message = M()
try message.decodeMessage(decoder: &subDecoder)
value.append(message)
}
scanner = subDecoder.scanner
}
}
mutating func decodeSingularGroupField<G: Message>(value: inout G?) throws {
try decodeSingularMessageField(value: &value)
}
mutating func decodeRepeatedGroupField<G: Message>(value: inout [G]) throws {
try decodeRepeatedMessageField(value: &value)
}
private mutating func decodeMapEntry<KeyType, ValueType: MapValueType>(mapType: _ProtobufMap<KeyType, ValueType>.Type, value: inout _ProtobufMap<KeyType, ValueType>.BaseType) throws {
var keyField: KeyType.BaseType?
var valueField: ValueType.BaseType?
let terminator = try scanner.skipObjectStart()
while true {
if scanner.skipOptionalObjectEnd(terminator) {
if let keyField = keyField, let valueField = valueField {
value[keyField] = valueField
return
} else {
throw TextFormatDecodingError.malformedText
}
}
if let key = try scanner.nextKey() {
switch key {
case "key", "1":
try KeyType.decodeSingular(value: &keyField, from: &self)
case "value", "2":
try ValueType.decodeSingular(value: &valueField, from: &self)
default:
throw TextFormatDecodingError.unknownField
}
scanner.skipOptionalSeparator()
}
}
}
mutating func decodeMapField<KeyType, ValueType: MapValueType>(fieldType: _ProtobufMap<KeyType, ValueType>.Type, value: inout _ProtobufMap<KeyType, ValueType>.BaseType) throws {
_ = scanner.skipOptionalColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
try decodeMapEntry(mapType: fieldType, value: &value)
}
} else {
try decodeMapEntry(mapType: fieldType, value: &value)
}
}
private mutating func decodeMapEntry<KeyType, ValueType>(mapType: _ProtobufEnumMap<KeyType, ValueType>.Type, value: inout _ProtobufEnumMap<KeyType, ValueType>.BaseType) throws where ValueType.RawValue == Int {
var keyField: KeyType.BaseType?
var valueField: ValueType?
let terminator = try scanner.skipObjectStart()
while true {
if scanner.skipOptionalObjectEnd(terminator) {
if let keyField = keyField, let valueField = valueField {
value[keyField] = valueField
return
} else {
throw TextFormatDecodingError.malformedText
}
}
if let key = try scanner.nextKey() {
switch key {
case "key", "1":
try KeyType.decodeSingular(value: &keyField, from: &self)
case "value", "2":
try decodeSingularEnumField(value: &valueField)
default:
throw TextFormatDecodingError.unknownField
}
scanner.skipOptionalSeparator()
}
}
}
mutating func decodeMapField<KeyType, ValueType>(fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type, value: inout _ProtobufEnumMap<KeyType, ValueType>.BaseType) throws where ValueType.RawValue == Int {
_ = scanner.skipOptionalColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
try decodeMapEntry(mapType: fieldType, value: &value)
}
} else {
try decodeMapEntry(mapType: fieldType, value: &value)
}
}
private mutating func decodeMapEntry<KeyType, ValueType>(mapType: _ProtobufMessageMap<KeyType, ValueType>.Type, value: inout _ProtobufMessageMap<KeyType, ValueType>.BaseType) throws {
var keyField: KeyType.BaseType?
var valueField: ValueType?
let terminator = try scanner.skipObjectStart()
while true {
if scanner.skipOptionalObjectEnd(terminator) {
if let keyField = keyField, let valueField = valueField {
value[keyField] = valueField
return
} else {
throw TextFormatDecodingError.malformedText
}
}
if let key = try scanner.nextKey() {
switch key {
case "key", "1":
try KeyType.decodeSingular(value: &keyField, from: &self)
case "value", "2":
try decodeSingularMessageField(value: &valueField)
default:
throw TextFormatDecodingError.unknownField
}
scanner.skipOptionalSeparator()
}
}
}
mutating func decodeMapField<KeyType, ValueType>(fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type, value: inout _ProtobufMessageMap<KeyType, ValueType>.BaseType) throws {
_ = scanner.skipOptionalColon()
if scanner.skipOptionalBeginArray() {
var firstItem = true
while true {
if scanner.skipOptionalEndArray() {
return
}
if firstItem {
firstItem = false
} else {
try scanner.skipRequiredComma()
}
try decodeMapEntry(mapType: fieldType, value: &value)
}
} else {
try decodeMapEntry(mapType: fieldType, value: &value)
}
}
mutating func decodeExtensionField(values: inout ExtensionFieldValueSet, messageType: Message.Type, fieldNumber: Int) throws {
if let ext = scanner.extensions?[messageType, fieldNumber] {
var fieldValue = values[fieldNumber]
if fieldValue != nil {
try fieldValue!.decodeExtensionField(decoder: &self)
} else {
fieldValue = try ext._protobuf_newField(decoder: &self)
}
if fieldValue != nil {
values[fieldNumber] = fieldValue
} else {
// Really things should never get here, for TextFormat, decoding
// the value should always work or throw an error. This specific
// error result is to allow this to be more detectable.
throw TextFormatDecodingError.internalExtensionError
}
}
}
}

View File

@ -0,0 +1,40 @@
// Sources/SwiftProtobuf/TextFormatDecodingError.swift - Protobuf text format decoding errors
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Protobuf text format decoding errors
///
// -----------------------------------------------------------------------------
public enum TextFormatDecodingError: Error {
/// Text data could not be parsed
case malformedText
/// A number could not be parsed
case malformedNumber
/// Extraneous data remained after decoding should have been complete
case trailingGarbage
/// The data stopped before we expected
case truncated
/// A string was not valid UTF8
case invalidUTF8
/// The data being parsed does not match the type specified in the proto file
case schemaMismatch
/// Field names were not compiled into the binary
case missingFieldNames
/// A field identifier (name or number) was not found on the message
case unknownField
/// The enum value was not recognized
case unrecognizedEnumValue
/// Text format rejects conflicting values for the same oneof field
case conflictingOneOf
/// An internal error happened while decoding. If this is ever encountered,
/// please file an issue with SwiftProtobuf with as much details as possible
/// for what happened (proto definitions, bytes being decoded (if possible)).
case internalExtensionError
}

View File

@ -0,0 +1,296 @@
// Sources/SwiftProtobuf/TextFormatEncoder.swift - Text format encoding support
//
// Copyright (c) 2014 - 2019 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Text format serialization engine.
///
// -----------------------------------------------------------------------------
import Foundation
private let asciiSpace = UInt8(ascii: " ")
private let asciiColon = UInt8(ascii: ":")
private let asciiComma = UInt8(ascii: ",")
private let asciiMinus = UInt8(ascii: "-")
private let asciiBackslash = UInt8(ascii: "\\")
private let asciiDoubleQuote = UInt8(ascii: "\"")
private let asciiZero = UInt8(ascii: "0")
private let asciiOpenCurlyBracket = UInt8(ascii: "{")
private let asciiCloseCurlyBracket = UInt8(ascii: "}")
private let asciiOpenSquareBracket = UInt8(ascii: "[")
private let asciiCloseSquareBracket = UInt8(ascii: "]")
private let asciiNewline = UInt8(ascii: "\n")
private let asciiUpperA = UInt8(ascii: "A")
private let tabSize = 2
private let tab = [UInt8](repeating: asciiSpace, count: tabSize)
/// TextFormatEncoder has no public members.
internal struct TextFormatEncoder {
private var data = [UInt8]()
private var indentString: [UInt8] = []
var stringResult: String {
get {
return String(bytes: data, encoding: String.Encoding.utf8)!
}
}
internal mutating func append(staticText: StaticString) {
let buff = UnsafeBufferPointer(start: staticText.utf8Start, count: staticText.utf8CodeUnitCount)
data.append(contentsOf: buff)
}
internal mutating func append(name: _NameMap.Name) {
data.append(contentsOf: name.utf8Buffer)
}
internal mutating func append(bytes: [UInt8]) {
data.append(contentsOf: bytes)
}
private mutating func append(text: String) {
data.append(contentsOf: text.utf8)
}
init() {}
internal mutating func indent() {
data.append(contentsOf: indentString)
}
mutating func emitFieldName(name: UnsafeRawBufferPointer) {
indent()
data.append(contentsOf: name)
}
mutating func emitFieldName(name: StaticString) {
let buff = UnsafeRawBufferPointer(start: name.utf8Start, count: name.utf8CodeUnitCount)
emitFieldName(name: buff)
}
mutating func emitFieldName(name: [UInt8]) {
indent()
data.append(contentsOf: name)
}
mutating func emitExtensionFieldName(name: String) {
indent()
data.append(asciiOpenSquareBracket)
append(text: name)
data.append(asciiCloseSquareBracket)
}
mutating func emitFieldNumber(number: Int) {
indent()
appendUInt(value: UInt64(number))
}
mutating func startRegularField() {
append(staticText: ": ")
}
mutating func endRegularField() {
data.append(asciiNewline)
}
// In Text format, a message-valued field writes the name
// without a trailing colon:
// name_of_field {key: value key2: value2}
mutating func startMessageField() {
append(staticText: " {\n")
indentString.append(contentsOf: tab)
}
mutating func endMessageField() {
indentString.removeLast(tabSize)
indent()
append(staticText: "}\n")
}
mutating func startArray() {
data.append(asciiOpenSquareBracket)
}
mutating func arraySeparator() {
append(staticText: ", ")
}
mutating func endArray() {
data.append(asciiCloseSquareBracket)
}
mutating func putEnumValue<E: Enum>(value: E) {
if let name = value.name {
data.append(contentsOf: name.utf8Buffer)
} else {
appendInt(value: Int64(value.rawValue))
}
}
mutating func putFloatValue(value: Float) {
if value.isNaN {
append(staticText: "nan")
} else if !value.isFinite {
if value < 0 {
append(staticText: "-inf")
} else {
append(staticText: "inf")
}
} else {
data.append(contentsOf: value.debugDescription.utf8)
}
}
mutating func putDoubleValue(value: Double) {
if value.isNaN {
append(staticText: "nan")
} else if !value.isFinite {
if value < 0 {
append(staticText: "-inf")
} else {
append(staticText: "inf")
}
} else {
data.append(contentsOf: value.debugDescription.utf8)
}
}
private mutating func appendUInt(value: UInt64) {
if value >= 1000 {
appendUInt(value: value / 1000)
}
if value >= 100 {
data.append(asciiZero + UInt8((value / 100) % 10))
}
if value >= 10 {
data.append(asciiZero + UInt8((value / 10) % 10))
}
data.append(asciiZero + UInt8(value % 10))
}
private mutating func appendInt(value: Int64) {
if value < 0 {
data.append(asciiMinus)
// This is the twos-complement negation of value,
// computed in a way that won't overflow a 64-bit
// signed integer.
appendUInt(value: 1 + ~UInt64(bitPattern: value))
} else {
appendUInt(value: UInt64(bitPattern: value))
}
}
mutating func putInt64(value: Int64) {
appendInt(value: value)
}
mutating func putUInt64(value: UInt64) {
appendUInt(value: value)
}
mutating func appendUIntHex(value: UInt64, digits: Int) {
if digits == 0 {
append(staticText: "0x")
} else {
appendUIntHex(value: value >> 4, digits: digits - 1)
let d = UInt8(truncatingIfNeeded: value % 16)
data.append(d < 10 ? asciiZero + d : asciiUpperA + d - 10)
}
}
mutating func putUInt64Hex(value: UInt64, digits: Int) {
appendUIntHex(value: value, digits: digits)
}
mutating func putBoolValue(value: Bool) {
append(staticText: value ? "true" : "false")
}
mutating func putStringValue(value: String) {
data.append(asciiDoubleQuote)
for c in value.unicodeScalars {
switch c.value {
// Special two-byte escapes
case 8:
append(staticText: "\\b")
case 9:
append(staticText: "\\t")
case 10:
append(staticText: "\\n")
case 11:
append(staticText: "\\v")
case 12:
append(staticText: "\\f")
case 13:
append(staticText: "\\r")
case 34:
append(staticText: "\\\"")
case 92:
append(staticText: "\\\\")
case 0...31, 127: // Octal form for C0 control chars
data.append(asciiBackslash)
data.append(asciiZero + UInt8(c.value / 64))
data.append(asciiZero + UInt8(c.value / 8 % 8))
data.append(asciiZero + UInt8(c.value % 8))
case 0...127: // ASCII
data.append(UInt8(truncatingIfNeeded: c.value))
case 0x80...0x7ff:
data.append(0xc0 + UInt8(c.value / 64))
data.append(0x80 + UInt8(c.value % 64))
case 0x800...0xffff:
data.append(0xe0 + UInt8(truncatingIfNeeded: c.value >> 12))
data.append(0x80 + UInt8(truncatingIfNeeded: (c.value >> 6) & 0x3f))
data.append(0x80 + UInt8(truncatingIfNeeded: c.value & 0x3f))
default:
data.append(0xf0 + UInt8(truncatingIfNeeded: c.value >> 18))
data.append(0x80 + UInt8(truncatingIfNeeded: (c.value >> 12) & 0x3f))
data.append(0x80 + UInt8(truncatingIfNeeded: (c.value >> 6) & 0x3f))
data.append(0x80 + UInt8(truncatingIfNeeded: c.value & 0x3f))
}
}
data.append(asciiDoubleQuote)
}
mutating func putBytesValue(value: Data) {
data.append(asciiDoubleQuote)
value.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
if let p = body.baseAddress, body.count > 0 {
for i in 0..<body.count {
let c = p[i]
switch c {
// Special two-byte escapes
case 8:
append(staticText: "\\b")
case 9:
append(staticText: "\\t")
case 10:
append(staticText: "\\n")
case 11:
append(staticText: "\\v")
case 12:
append(staticText: "\\f")
case 13:
append(staticText: "\\r")
case 34:
append(staticText: "\\\"")
case 92:
append(staticText: "\\\\")
case 32...126: // printable ASCII
data.append(c)
default: // Octal form for non-printable chars
data.append(asciiBackslash)
data.append(asciiZero + UInt8(c / 64))
data.append(asciiZero + UInt8(c / 8 % 8))
data.append(asciiZero + UInt8(c % 8))
}
}
}
}
data.append(asciiDoubleQuote)
}
}

View File

@ -0,0 +1,22 @@
// Sources/SwiftProtobuf/TextFormatEncodingOptions.swift - Text format encoding options
//
// Copyright (c) 2014 - 2019 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Text format encoding options
///
// -----------------------------------------------------------------------------
/// Options for TextFormatEncoding.
public struct TextFormatEncodingOptions {
/// Default: Do print unknown fields using numeric notation
public var printUnknownFields: Bool = true
public init() {}
}

View File

@ -0,0 +1,661 @@
// Sources/SwiftProtobuf/TextFormatEncodingVisitor.swift - Text format encoding support
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Text format serialization engine.
///
// -----------------------------------------------------------------------------
import Foundation
private let mapNameResolver: [Int:StaticString] = [1: "key", 2: "value"]
/// Visitor that serializes a message into protobuf text format.
internal struct TextFormatEncodingVisitor: Visitor {
private var encoder: TextFormatEncoder
private var nameMap: _NameMap?
private var nameResolver: [Int:StaticString]
private var extensions: ExtensionFieldValueSet?
private let options: TextFormatEncodingOptions
/// The protobuf text produced by the visitor.
var result: String {
return encoder.stringResult
}
/// Creates a new visitor that serializes the given message to protobuf text
/// format.
init(message: Message, options: TextFormatEncodingOptions) {
self.init(message: message, encoder: TextFormatEncoder(), options: options)
}
/// Creates a new visitor that serializes the given message to protobuf text
/// format, using an existing encoder.
private init(message: Message, encoder: TextFormatEncoder, options: TextFormatEncodingOptions) {
let nameMap: _NameMap?
if let nameProviding = message as? _ProtoNameProviding {
nameMap = type(of: nameProviding)._protobuf_nameMap
} else {
nameMap = nil
}
let extensions = (message as? ExtensibleMessage)?._protobuf_extensionFieldValues
self.init(nameMap: nameMap, nameResolver: [:], extensions: extensions, encoder: encoder, options: options)
}
private init(
nameMap: _NameMap?,
nameResolver: [Int:StaticString],
extensions: ExtensionFieldValueSet?,
encoder: TextFormatEncoder,
options: TextFormatEncodingOptions
) {
self.nameMap = nameMap
self.nameResolver = nameResolver
self.extensions = extensions
self.encoder = encoder
self.options = options
}
// TODO: This largely duplicates emitFieldName() below.
// But, it's slower so we don't want to just have emitFieldName() use
// formatFieldName(). Also, we need to measure whether the optimization
// this provides to repeated fields is worth the effort; consider just
// removing this and having repeated fields just re-run emitFieldName()
// for each item.
private func formatFieldName(lookingUp fieldNumber: Int) -> [UInt8] {
var bytes = [UInt8]()
if let protoName = nameMap?.names(for: fieldNumber)?.proto {
bytes.append(contentsOf: protoName.utf8Buffer)
} else if let protoName = nameResolver[fieldNumber] {
let buff = UnsafeBufferPointer(start: protoName.utf8Start, count: protoName.utf8CodeUnitCount)
bytes.append(contentsOf: buff)
} else if let extensionName = extensions?[fieldNumber]?.protobufExtension.fieldName {
bytes.append(UInt8(ascii: "["))
bytes.append(contentsOf: extensionName.utf8)
bytes.append(UInt8(ascii: "]"))
} else {
bytes.append(contentsOf: fieldNumber.description.utf8)
}
return bytes
}
private mutating func emitFieldName(lookingUp fieldNumber: Int) {
if let protoName = nameMap?.names(for: fieldNumber)?.proto {
encoder.emitFieldName(name: protoName.utf8Buffer)
} else if let protoName = nameResolver[fieldNumber] {
encoder.emitFieldName(name: protoName)
} else if let extensionName = extensions?[fieldNumber]?.protobufExtension.fieldName {
encoder.emitExtensionFieldName(name: extensionName)
} else {
encoder.emitFieldNumber(number: fieldNumber)
}
}
mutating func visitUnknown(bytes: Data) throws {
if options.printUnknownFields {
try bytes.withUnsafeBytes { (body: UnsafeRawBufferPointer) -> () in
if let baseAddress = body.baseAddress, body.count > 0 {
// All fields will be directly handled, so there is no need for
// the unknown field buffering/collection (when scannings to see
// if something is a message, this would be extremely wasteful).
var binaryOptions = BinaryDecodingOptions()
binaryOptions.discardUnknownFields = true
var decoder = BinaryDecoder(forReadingFrom: baseAddress,
count: body.count,
options: binaryOptions)
try visitUnknown(decoder: &decoder)
}
}
}
}
/// Helper for printing out unknowns.
///
/// The implementation tries to be "helpful" and if a length delimited field
/// appears to be a submessage, it prints it as such. However, that opens the
/// door to someone sending a message with an unknown field that is a stack
/// bomb, i.e. - it causes this code to recurse, exhausing the stack and
/// thus opening up an attack vector. To keep this "help", but avoid the
/// attack, a limit is placed on how many times it will recurse before just
/// treating the length delimted fields as bytes and not trying to decode
/// them.
private mutating func visitUnknown(
decoder: inout BinaryDecoder,
recursionBudget: Int = 10
) throws {
// This stack serves to avoid recursion for groups within groups within
// groups..., this avoid the stack attack that the message detection
// hits. No limit is placed on this because there is no stack risk with
// recursion, and because if a limit was hit, there is no other way to
// encode the group (the message field can just print as length
// delimited, groups don't have an option like that).
var groupFieldNumberStack: [Int] = []
while let tag = try decoder.getTag() {
switch tag.wireFormat {
case .varint:
encoder.emitFieldNumber(number: tag.fieldNumber)
var value: UInt64 = 0
encoder.startRegularField()
try decoder.decodeSingularUInt64Field(value: &value)
encoder.putUInt64(value: value)
encoder.endRegularField()
case .fixed64:
encoder.emitFieldNumber(number: tag.fieldNumber)
var value: UInt64 = 0
encoder.startRegularField()
try decoder.decodeSingularFixed64Field(value: &value)
encoder.putUInt64Hex(value: value, digits: 16)
encoder.endRegularField()
case .lengthDelimited:
encoder.emitFieldNumber(number: tag.fieldNumber)
var bytes = Data()
try decoder.decodeSingularBytesField(value: &bytes)
bytes.withUnsafeBytes { (body: UnsafeRawBufferPointer) -> () in
if let baseAddress = body.baseAddress, body.count > 0 {
var encodeAsBytes: Bool
if (recursionBudget > 0) {
do {
// Walk all the fields to test if it looks like a message
var testDecoder = BinaryDecoder(forReadingFrom: baseAddress,
count: body.count,
parent: decoder)
while let _ = try testDecoder.nextFieldNumber() {
}
// No error? Output the message body.
encodeAsBytes = false
var subDecoder = BinaryDecoder(forReadingFrom: baseAddress,
count: bytes.count,
parent: decoder)
encoder.startMessageField()
try visitUnknown(decoder: &subDecoder,
recursionBudget: recursionBudget - 1)
encoder.endMessageField()
} catch {
encodeAsBytes = true
}
} else {
encodeAsBytes = true
}
if (encodeAsBytes) {
encoder.startRegularField()
encoder.putBytesValue(value: bytes)
encoder.endRegularField()
}
}
}
case .startGroup:
encoder.emitFieldNumber(number: tag.fieldNumber)
encoder.startMessageField()
groupFieldNumberStack.append(tag.fieldNumber)
case .endGroup:
let groupFieldNumber = groupFieldNumberStack.popLast()
// Unknown data is scanned and verified by the
// binary parser, so this can never fail.
assert(tag.fieldNumber == groupFieldNumber)
encoder.endMessageField()
case .fixed32:
encoder.emitFieldNumber(number: tag.fieldNumber)
var value: UInt32 = 0
encoder.startRegularField()
try decoder.decodeSingularFixed32Field(value: &value)
encoder.putUInt64Hex(value: UInt64(value), digits: 8)
encoder.endRegularField()
}
}
// Unknown data is scanned and verified by the binary parser, so this can
// never fail.
assert(groupFieldNumberStack.isEmpty)
}
// Visitor.swift defines default versions for other singular field types
// that simply widen and dispatch to one of the following. Since Text format
// does not distinguish e.g., Fixed64 vs. UInt64, this is sufficient.
mutating func visitSingularFloatField(value: Float, fieldNumber: Int) throws {
emitFieldName(lookingUp: fieldNumber)
encoder.startRegularField()
encoder.putFloatValue(value: value)
encoder.endRegularField()
}
mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
emitFieldName(lookingUp: fieldNumber)
encoder.startRegularField()
encoder.putDoubleValue(value: value)
encoder.endRegularField()
}
mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
emitFieldName(lookingUp: fieldNumber)
encoder.startRegularField()
encoder.putInt64(value: value)
encoder.endRegularField()
}
mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
emitFieldName(lookingUp: fieldNumber)
encoder.startRegularField()
encoder.putUInt64(value: value)
encoder.endRegularField()
}
mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
emitFieldName(lookingUp: fieldNumber)
encoder.startRegularField()
encoder.putBoolValue(value: value)
encoder.endRegularField()
}
mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
emitFieldName(lookingUp: fieldNumber)
encoder.startRegularField()
encoder.putStringValue(value: value)
encoder.endRegularField()
}
mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
emitFieldName(lookingUp: fieldNumber)
encoder.startRegularField()
encoder.putBytesValue(value: value)
encoder.endRegularField()
}
mutating func visitSingularEnumField<E: Enum>(value: E, fieldNumber: Int) throws {
emitFieldName(lookingUp: fieldNumber)
encoder.startRegularField()
encoder.putEnumValue(value: value)
encoder.endRegularField()
}
mutating func visitSingularMessageField<M: Message>(value: M,
fieldNumber: Int) throws {
emitFieldName(lookingUp: fieldNumber)
// Cache old encoder state
let oldNameMap = self.nameMap
let oldNameResolver = self.nameResolver
let oldExtensions = self.extensions
// Update encoding state for new message
self.nameMap = (M.self as? _ProtoNameProviding.Type)?._protobuf_nameMap
self.nameResolver = [:]
self.extensions = (value as? ExtensibleMessage)?._protobuf_extensionFieldValues
// Restore state before returning
defer {
self.extensions = oldExtensions
self.nameResolver = oldNameResolver
self.nameMap = oldNameMap
}
// Encode submessage
encoder.startMessageField()
if let any = value as? Google_Protobuf_Any {
any.textTraverse(visitor: &self)
} else {
try! value.traverse(visitor: &self)
}
encoder.endMessageField()
}
// Emit the full "verbose" form of an Any. This writes the typeURL
// as a field name in `[...]` followed by the fields of the
// contained message.
internal mutating func visitAnyVerbose(value: Message, typeURL: String) {
encoder.emitExtensionFieldName(name: typeURL)
encoder.startMessageField()
var visitor = TextFormatEncodingVisitor(message: value, encoder: encoder, options: options)
if let any = value as? Google_Protobuf_Any {
any.textTraverse(visitor: &visitor)
} else {
try! value.traverse(visitor: &visitor)
}
encoder = visitor.encoder
encoder.endMessageField()
}
// Write a single special field called "#json". This
// is used for Any objects with undecoded JSON contents.
internal mutating func visitAnyJSONDataField(value: Data) {
encoder.indent()
encoder.append(staticText: "#json: ")
encoder.putBytesValue(value: value)
encoder.append(staticText: "\n")
}
// The default implementations in Visitor.swift provide the correct
// results, but we get significantly better performance by only doing
// the name lookup once for the array, rather than once for each element:
mutating func visitRepeatedFloatField(value: [Float], fieldNumber: Int) throws {
assert(!value.isEmpty)
let fieldName = formatFieldName(lookingUp: fieldNumber)
for v in value {
encoder.emitFieldName(name: fieldName)
encoder.startRegularField()
encoder.putFloatValue(value: v)
encoder.endRegularField()
}
}
mutating func visitRepeatedDoubleField(value: [Double], fieldNumber: Int) throws {
assert(!value.isEmpty)
let fieldName = formatFieldName(lookingUp: fieldNumber)
for v in value {
encoder.emitFieldName(name: fieldName)
encoder.startRegularField()
encoder.putDoubleValue(value: v)
encoder.endRegularField()
}
}
mutating func visitRepeatedInt32Field(value: [Int32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let fieldName = formatFieldName(lookingUp: fieldNumber)
for v in value {
encoder.emitFieldName(name: fieldName)
encoder.startRegularField()
encoder.putInt64(value: Int64(v))
encoder.endRegularField()
}
}
mutating func visitRepeatedInt64Field(value: [Int64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let fieldName = formatFieldName(lookingUp: fieldNumber)
for v in value {
encoder.emitFieldName(name: fieldName)
encoder.startRegularField()
encoder.putInt64(value: v)
encoder.endRegularField()
}
}
mutating func visitRepeatedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
assert(!value.isEmpty)
let fieldName = formatFieldName(lookingUp: fieldNumber)
for v in value {
encoder.emitFieldName(name: fieldName)
encoder.startRegularField()
encoder.putUInt64(value: UInt64(v))
encoder.endRegularField()
}
}
mutating func visitRepeatedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
assert(!value.isEmpty)
let fieldName = formatFieldName(lookingUp: fieldNumber)
for v in value {
encoder.emitFieldName(name: fieldName)
encoder.startRegularField()
encoder.putUInt64(value: v)
encoder.endRegularField()
}
}
mutating func visitRepeatedSInt32Field(value: [Int32], fieldNumber: Int) throws {
try visitRepeatedInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedSInt64Field(value: [Int64], fieldNumber: Int) throws {
try visitRepeatedInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
try visitRepeatedUInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
try visitRepeatedUInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
try visitRepeatedInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
try visitRepeatedInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitRepeatedBoolField(value: [Bool], fieldNumber: Int) throws {
assert(!value.isEmpty)
let fieldName = formatFieldName(lookingUp: fieldNumber)
for v in value {
encoder.emitFieldName(name: fieldName)
encoder.startRegularField()
encoder.putBoolValue(value: v)
encoder.endRegularField()
}
}
mutating func visitRepeatedStringField(value: [String], fieldNumber: Int) throws {
assert(!value.isEmpty)
let fieldName = formatFieldName(lookingUp: fieldNumber)
for v in value {
encoder.emitFieldName(name: fieldName)
encoder.startRegularField()
encoder.putStringValue(value: v)
encoder.endRegularField()
}
}
mutating func visitRepeatedBytesField(value: [Data], fieldNumber: Int) throws {
assert(!value.isEmpty)
let fieldName = formatFieldName(lookingUp: fieldNumber)
for v in value {
encoder.emitFieldName(name: fieldName)
encoder.startRegularField()
encoder.putBytesValue(value: v)
encoder.endRegularField()
}
}
mutating func visitRepeatedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
assert(!value.isEmpty)
let fieldName = formatFieldName(lookingUp: fieldNumber)
for v in value {
encoder.emitFieldName(name: fieldName)
encoder.startRegularField()
encoder.putEnumValue(value: v)
encoder.endRegularField()
}
}
// Messages and groups
mutating func visitRepeatedMessageField<M: Message>(value: [M],
fieldNumber: Int) throws {
assert(!value.isEmpty)
// Look up field name against outer message encoding state
let fieldName = formatFieldName(lookingUp: fieldNumber)
// Cache old encoder state
let oldNameMap = self.nameMap
let oldNameResolver = self.nameResolver
let oldExtensions = self.extensions
// Update encoding state for new message type
self.nameMap = (M.self as? _ProtoNameProviding.Type)?._protobuf_nameMap
self.nameResolver = [:]
self.extensions = (value as? ExtensibleMessage)?._protobuf_extensionFieldValues
// Iterate and encode each message
for v in value {
encoder.emitFieldName(name: fieldName)
encoder.startMessageField()
if let any = v as? Google_Protobuf_Any {
any.textTraverse(visitor: &self)
} else {
try! v.traverse(visitor: &self)
}
encoder.endMessageField()
}
// Restore state
self.extensions = oldExtensions
self.nameResolver = oldNameResolver
self.nameMap = oldNameMap
}
// Google's C++ implementation of Text format supports two formats
// for repeated numeric fields: "short" format writes the list as a
// single field with values enclosed in `[...]`, "long" format
// writes a separate field name/value for each item. They provide
// an option for callers to select which output version they prefer.
// Since this distinction mirrors the difference in Protobuf Binary
// between "packed" and "non-packed", I've chosen to use the short
// format for packed fields and the long version for repeated
// fields. This provides a clear visual distinction between these
// fields (including proto3's default use of packed) without
// introducing the baggage of a separate option.
private mutating func _visitPacked<T>(
value: [T], fieldNumber: Int,
encode: (T, inout TextFormatEncoder) -> ()
) throws {
assert(!value.isEmpty)
emitFieldName(lookingUp: fieldNumber)
encoder.startRegularField()
var firstItem = true
encoder.startArray()
for v in value {
if !firstItem {
encoder.arraySeparator()
}
encode(v, &encoder)
firstItem = false
}
encoder.endArray()
encoder.endRegularField()
}
mutating func visitPackedFloatField(value: [Float], fieldNumber: Int) throws {
try _visitPacked(value: value, fieldNumber: fieldNumber) {
(v: Float, encoder: inout TextFormatEncoder) in
encoder.putFloatValue(value: v)
}
}
mutating func visitPackedDoubleField(value: [Double], fieldNumber: Int) throws {
try _visitPacked(value: value, fieldNumber: fieldNumber) {
(v: Double, encoder: inout TextFormatEncoder) in
encoder.putDoubleValue(value: v)
}
}
mutating func visitPackedInt32Field(value: [Int32], fieldNumber: Int) throws {
try _visitPacked(value: value, fieldNumber: fieldNumber) {
(v: Int32, encoder: inout TextFormatEncoder) in
encoder.putInt64(value: Int64(v))
}
}
mutating func visitPackedInt64Field(value: [Int64], fieldNumber: Int) throws {
try _visitPacked(value: value, fieldNumber: fieldNumber) {
(v: Int64, encoder: inout TextFormatEncoder) in
encoder.putInt64(value: v)
}
}
mutating func visitPackedUInt32Field(value: [UInt32], fieldNumber: Int) throws {
try _visitPacked(value: value, fieldNumber: fieldNumber) {
(v: UInt32, encoder: inout TextFormatEncoder) in
encoder.putUInt64(value: UInt64(v))
}
}
mutating func visitPackedUInt64Field(value: [UInt64], fieldNumber: Int) throws {
try _visitPacked(value: value, fieldNumber: fieldNumber) {
(v: UInt64, encoder: inout TextFormatEncoder) in
encoder.putUInt64(value: v)
}
}
mutating func visitPackedSInt32Field(value: [Int32], fieldNumber: Int) throws {
try visitPackedInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitPackedSInt64Field(value: [Int64], fieldNumber: Int) throws {
try visitPackedInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitPackedFixed32Field(value: [UInt32], fieldNumber: Int) throws {
try visitPackedUInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitPackedFixed64Field(value: [UInt64], fieldNumber: Int) throws {
try visitPackedUInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitPackedSFixed32Field(value: [Int32], fieldNumber: Int) throws {
try visitPackedInt32Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitPackedSFixed64Field(value: [Int64], fieldNumber: Int) throws {
try visitPackedInt64Field(value: value, fieldNumber: fieldNumber)
}
mutating func visitPackedBoolField(value: [Bool], fieldNumber: Int) throws {
try _visitPacked(value: value, fieldNumber: fieldNumber) {
(v: Bool, encoder: inout TextFormatEncoder) in
encoder.putBoolValue(value: v)
}
}
mutating func visitPackedEnumField<E: Enum>(value: [E], fieldNumber: Int) throws {
try _visitPacked(value: value, fieldNumber: fieldNumber) {
(v: E, encoder: inout TextFormatEncoder) in
encoder.putEnumValue(value: v)
}
}
/// Helper to encapsulate the common structure of iterating over a map
/// and encoding the keys and values.
private mutating func _visitMap<K, V>(
map: Dictionary<K, V>,
fieldNumber: Int,
coder: (inout TextFormatEncodingVisitor, K, V) throws -> ()
) throws {
for (k,v) in map {
emitFieldName(lookingUp: fieldNumber)
encoder.startMessageField()
var visitor = TextFormatEncodingVisitor(nameMap: nil, nameResolver: mapNameResolver, extensions: nil, encoder: encoder, options: options)
try coder(&visitor, k, v)
encoder = visitor.encoder
encoder.endMessageField()
}
}
mutating func visitMapField<KeyType, ValueType: MapValueType>(
fieldType: _ProtobufMap<KeyType, ValueType>.Type,
value: _ProtobufMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws {
try _visitMap(map: value, fieldNumber: fieldNumber) {
(visitor: inout TextFormatEncodingVisitor, key, value) throws -> () in
try KeyType.visitSingular(value: key, fieldNumber: 1, with: &visitor)
try ValueType.visitSingular(value: value, fieldNumber: 2, with: &visitor)
}
}
mutating func visitMapField<KeyType, ValueType>(
fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
value: _ProtobufEnumMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws where ValueType.RawValue == Int {
try _visitMap(map: value, fieldNumber: fieldNumber) {
(visitor: inout TextFormatEncodingVisitor, key, value) throws -> () in
try KeyType.visitSingular(value: key, fieldNumber: 1, with: &visitor)
try visitor.visitSingularEnumField(value: value, fieldNumber: 2)
}
}
mutating func visitMapField<KeyType, ValueType>(
fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
value: _ProtobufMessageMap<KeyType, ValueType>.BaseType,
fieldNumber: Int
) throws {
try _visitMap(map: value, fieldNumber: fieldNumber) {
(visitor: inout TextFormatEncodingVisitor, key, value) throws -> () in
try KeyType.visitSingular(value: key, fieldNumber: 1, with: &visitor)
try visitor.visitSingularMessageField(value: value, fieldNumber: 2)
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
// Sources/SwiftProtobuf/TimeUtils.swift - Generally useful time/calendar functions
//
// Copyright (c) 2014 - 2017 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Generally useful time/calendar functions and constants
///
// -----------------------------------------------------------------------------
let minutesPerDay: Int32 = 1440
let minutesPerHour: Int32 = 60
let secondsPerDay: Int32 = 86400
let secondsPerHour: Int32 = 3600
let secondsPerMinute: Int32 = 60
let nanosPerSecond: Int32 = 1000000000
internal func timeOfDayFromSecondsSince1970(seconds: Int64) -> (hh: Int32, mm: Int32, ss: Int32) {
let secondsSinceMidnight = Int32(mod(seconds, Int64(secondsPerDay)))
let ss = mod(secondsSinceMidnight, secondsPerMinute)
let mm = mod(div(secondsSinceMidnight, secondsPerMinute), minutesPerHour)
let hh = Int32(div(secondsSinceMidnight, secondsPerHour))
return (hh: hh, mm: mm, ss: ss)
}
internal func julianDayNumberFromSecondsSince1970(seconds: Int64) -> Int64 {
// January 1, 1970 is Julian Day Number 2440588.
// See http://aa.usno.navy.mil/faq/docs/JD_Formula.php
return div(seconds + 2440588 * Int64(secondsPerDay), Int64(secondsPerDay))
}
internal func gregorianDateFromSecondsSince1970(seconds: Int64) -> (YY: Int32, MM: Int32, DD: Int32) {
// The following implements Richards' algorithm (see the Wikipedia article
// for "Julian day").
// If you touch this code, please test it exhaustively by playing with
// Test_Timestamp.testJSON_range.
let JJ = julianDayNumberFromSecondsSince1970(seconds: seconds)
let f = JJ + 1401 + div(div(4 * JJ + 274277, 146097) * 3, 4) - 38
let e = 4 * f + 3
let g = Int64(div(mod(e, 1461), 4))
let h = 5 * g + 2
let DD = div(mod(h, 153), 5) + 1
let MM = mod(div(h, 153) + 2, 12) + 1
let YY = div(e, 1461) - 4716 + div(12 + 2 - MM, 12)
return (YY: Int32(YY), MM: Int32(MM), DD: Int32(DD))
}

View File

@ -0,0 +1,46 @@
// Sources/SwiftProtobuf/UnknownStorage.swift - Handling unknown fields
//
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Proto2 binary coding requires storing and recoding of unknown fields.
/// This simple support class handles that requirement. A property of this type
/// is compiled into every proto2 message.
///
// -----------------------------------------------------------------------------
import Foundation
/// Contains any unknown fields in a decoded message; that is, fields that were
/// sent on the wire but were not recognized by the generated message
/// implementation or were valid field numbers but with mismatching wire
/// formats (for example, a field encoded as a varint when a fixed32 integer
/// was expected).
public struct UnknownStorage: Equatable {
/// The raw protocol buffer binary-encoded bytes that represent the unknown
/// fields of a decoded message.
public private(set) var data = Data()
#if !swift(>=4.1)
public static func ==(lhs: UnknownStorage, rhs: UnknownStorage) -> Bool {
return lhs.data == rhs.data
}
#endif
public init() {}
internal mutating func append(protobufData: Data) {
data.append(protobufData)
}
public func traverse<V: Visitor>(visitor: inout V) throws {
if !data.isEmpty {
try visitor.visitUnknown(bytes: data)
}
}
}

View File

@ -0,0 +1,37 @@
// Sources/SwiftProtobuf/UnsafeBufferPointer+Shims.swift - Shims for UnsafeBufferPointer
//
// Copyright (c) 2019 Apple Inc. and the project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See LICENSE.txt for license information:
// https://github.com/apple/swift-protobuf/blob/master/LICENSE.txt
//
// -----------------------------------------------------------------------------
///
/// Shims for UnsafeBufferPointer
///
// -----------------------------------------------------------------------------
extension UnsafeMutableBufferPointer {
#if !swift(>=4.2)
internal static func allocate(capacity: Int) -> UnsafeMutableBufferPointer<Element> {
let pointer = UnsafeMutablePointer<Element>.allocate(capacity: capacity)
return UnsafeMutableBufferPointer(start: pointer, count: capacity)
}
#endif
#if !swift(>=4.1)
internal func deallocate() {
self.baseAddress?.deallocate(capacity: self.count)
}
#endif
}
extension UnsafeMutableRawBufferPointer {
#if !swift(>=4.1)
internal func copyMemory<C: Collection>(from source: C) where C.Element == UInt8 {
self.copyBytes(from: source)
}
#endif
}

Some files were not shown because too many files have changed in this diff Show More