summaryrefslogtreecommitdiff
path: root/upb/pb/encoder.h
blob: 2df57976b48aff918667e14dbf9f16069c8afad6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 * upb - a minimalist implementation of protocol buffers.
 *
 * Copyright (c) 2009-2010 Google Inc.  See LICENSE for details.
 * Author: Josh Haberman <jhaberman@gmail.com>
 *
 * Implements a set of upb_handlers that write protobuf data to the binary wire
 * format.
 *
 * This encoder implementation does not have any access to any out-of-band or
 * precomputed lengths for submessages, so it must buffer submessages internally
 * before it can emit the first byte.
 */

#ifndef UPB_ENCODER_H_
#define UPB_ENCODER_H_

#include "upb/sink.h"

#ifdef __cplusplus
namespace upb {
namespace pb {
class Encoder;
}  // namespace pb
}  // namespace upb
#endif

UPB_DECLARE_TYPE(upb::pb::Encoder, upb_pb_encoder);

#define UPB_PBENCODER_MAX_NESTING 100

/* upb::pb::Encoder ***********************************************************/

// The output buffer is divided into segments; a segment is a string of data
// that is "ready to go" -- it does not need any varint lengths inserted into
// the middle.  The seams between segments are where varints will be inserted
// once they are known.
//
// We also use the concept of a "run", which is a range of encoded bytes that
// occur at a single submessage level.  Every segment contains one or more runs.
//
// A segment can span messages.  Consider:
//
//                  .--Submessage lengths---------.
//                  |       |                     |
//                  |       V                     V
//                  V      | |---------------    | |-----------------
// Submessages:    | |-----------------------------------------------
// Top-level msg: ------------------------------------------------------------
//
// Segments:          -----   -------------------   -----------------
// Runs:              *----   *--------------*---   *----------------
// (* marks the start)
//
// Note that the top-level menssage is not in any segment because it does not
// have any length preceding it.
//
// A segment is only interrupted when another length needs to be inserted.  So
// observe how the second segment spans both the inner submessage and part of
// the next enclosing message.
typedef struct {
 UPB_PRIVATE_FOR_CPP
  uint32_t msglen;  // The length to varint-encode before this segment.
  uint32_t seglen;  // Length of the segment.
} upb_pb_encoder_segment;

UPB_DEFINE_CLASS0(upb::pb::Encoder,
 public:
  Encoder(const upb::Handlers* handlers);
  ~Encoder();

  static reffed_ptr<const Handlers> NewHandlers(const upb::MessageDef* msg);

  // Resets the state of the printer, so that it will expect to begin a new
  // document.
  void Reset();

  // Resets the output pointer which will serve as our closure.
  void ResetOutput(BytesSink* output);

  // The input to the encoder.
  Sink* input();

 private:
  UPB_DISALLOW_COPY_AND_ASSIGN(Encoder);
,
UPB_DEFINE_STRUCT0(upb_pb_encoder, UPB_QUOTE(
  // Our input and output.
  upb_sink input_;
  upb_bytessink *output_;

  // The "subclosure" -- used as the inner closure as part of the bytessink
  // protocol.
  void *subc;

  // The output buffer and limit, and our current write position.  "buf"
  // initially points to "initbuf", but is dynamically allocated if we need to
  // grow beyond the initial size.
  char *buf, *ptr, *limit;

  // The beginning of the current run, or undefined if we are at the top level.
  char *runbegin;

  // The list of segments we are accumulating.
  upb_pb_encoder_segment *segbuf, *segptr, *seglimit;

  // The stack of enclosing submessages.  Each entry in the stack points to the
  // segment where this submessage's length is being accumulated.
  int stack[UPB_PBENCODER_MAX_NESTING], *top, *stacklimit;

  // Depth of startmsg/endmsg calls.
  int depth;

  // Initial buffers for the output buffer and segment buffer.  If we outgrow
  // these we will dynamically allocate bigger ones.
  char initbuf[256];
  upb_pb_encoder_segment seginitbuf[32];
)));

UPB_BEGIN_EXTERN_C

const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m,
                                               const void *owner);
void upb_pb_encoder_reset(upb_pb_encoder *e);
upb_sink *upb_pb_encoder_input(upb_pb_encoder *p);
void upb_pb_encoder_init(upb_pb_encoder *e, const upb_handlers *h);
void upb_pb_encoder_resetoutput(upb_pb_encoder *e, upb_bytessink *output);
void upb_pb_encoder_uninit(upb_pb_encoder *e);

UPB_END_EXTERN_C

#ifdef __cplusplus

namespace upb {
namespace pb {
inline Encoder::Encoder(const upb::Handlers* handlers) {
  upb_pb_encoder_init(this, handlers);
}
inline Encoder::~Encoder() {
  upb_pb_encoder_uninit(this);
}
inline void Encoder::Reset() {
  upb_pb_encoder_reset(this);
}
inline void Encoder::ResetOutput(BytesSink* output) {
  upb_pb_encoder_resetoutput(this, output);
}
inline Sink* Encoder::input() {
  return upb_pb_encoder_input(this);
}
inline reffed_ptr<const Handlers> Encoder::NewHandlers(
    const upb::MessageDef *md) {
  const Handlers* h = upb_pb_encoder_newhandlers(md, &h);
  return reffed_ptr<const Handlers>(h, &h);
}
}  // namespace pb
}  // namespace upb

#endif

#endif  /* UPB_ENCODER_H_ */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback