Spicy
sink.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <hilti/ast/operator.h>
6 #include <hilti/ast/operators/common.h>
7 #include <hilti/ast/types/bool.h>
8 #include <hilti/ast/types/bytes.h>
9 #include <hilti/ast/types/enum.h>
10 #include <hilti/ast/types/library.h>
11 #include <hilti/ast/types/reference.h>
12 #include <hilti/ast/types/void.h>
13 
14 #include <spicy/ast/types/sink.h>
15 #include <spicy/ast/types/unit.h>
16 
17 namespace spicy::operator_ {
18 
19 STANDARD_OPERATOR_1x(sink, SizeValue, Size, type::UnsignedInteger(64), type::constant(type::Sink()), R"(
20 Returns the number of bytes written into the sink so far. If the sink has
21 filters attached, this returns the value after filtering.
22 )");
23 
24 STANDARD_OPERATOR_1x(sink, SizeReference, Size, type::UnsignedInteger(64), hilti::type::StrongReference(type::Sink()),
25  R"(
26 Returns the number of bytes written into the referenced sink so far. If the sink has
27 filters attached, this returns the value after filtering.
28 )");
29 
30 BEGIN_METHOD(sink, Close)
31  const auto& signature() const {
32  static auto _signature = hilti::operator_::Signature{.self = spicy::type::Sink(),
33  .result = type::void_,
34  .id = "close",
35  .args = {},
36  .doc = R"(
37 Closes a sink by disconnecting all parsing units. Afterwards the sink's state
38 is as if it had just been created (so new units can be connected). Note that a
39 sink is automatically closed when the unit it is part of is done parsing. Also
40 note that a previously connected parsing unit can *not* be reconnected; trying
41 to do so will still throw a ``UnitAlreadyConnected`` exception.
42 )"};
43  return _signature;
44  }
45 END_METHOD
46 
47 BEGIN_METHOD(sink, Connect)
48  const auto& signature() const {
49  static auto _signature =
51  .result = type::void_,
52  .id = "connect",
53  .args = {{"u", type::StrongReference(type::Unit(type::Wildcard()))}},
54  .doc = R"(
55 Connects a parsing unit to a sink. All subsequent write operations to the sink will pass their
56 data on to this parsing unit. Each unit can only be connected to a single sink. If
57 the unit is already connected, a ``UnitAlreadyConnected`` exception is thrown.
58 However, a sink can have more than one unit connected to it.
59 )"};
60  return _signature;
61  }
62 END_METHOD
63 
64 BEGIN_METHOD(sink, ConnectMIMETypeString)
65  const auto& signature() const {
66  static auto _signature = hilti::operator_::Signature{.self = spicy::type::Sink(),
67  .result = type::void_,
68  .id = "connect_mime_type",
69  .args = {{"mt", type::String()}},
70  .doc = R"(
71 Connects parsing units to a sink for all parsers that support a given MIME
72 type. All subsequent write operations to the sink will pass their data on to
73 these parsing units. The MIME type may have wildcards for type or subtype, and
74 the method will then connect units for all matching parsers.
75 )"};
76  return _signature;
77  }
78 END_METHOD
79 
80 BEGIN_METHOD(sink, ConnectMIMETypeBytes)
81  const auto& signature() const {
82  static auto _signature = hilti::operator_::Signature{.self = spicy::type::Sink(),
83  .result = type::void_,
84  .id = "connect_mime_type",
85  .args = {{"mt", type::constant(type::Bytes())}},
86  .doc = R"(
87 Connects parsing units to a sink for all parsers that support a given MIME
88 type. All subsequent write operations to the sink will pass their data on to
89 these parsing units. The MIME type may have wildcards for type or subtype, and
90 the method will then connect units for all matching parsers.
91 )"};
92  return _signature;
93  }
94 END_METHOD
95 
96 BEGIN_METHOD(sink, ConnectFilter)
97  const auto& signature() const {
98  static auto _signature =
100  .result = hilti::type::void_,
101  .id = "connect_filter",
102  .args = {{"filter",
103  hilti::type::StrongReference(spicy::type::Unit(type::Wildcard()))}},
104  .doc = R"(
105 Connects a filter unit to the sink that will transform its input transparently
106 before forwarding it for parsing to other connected units.
107 
108 Multiple filters can be added to a sink, in which case they will be chained
109 into a pipeline and the data will be passed through them in the order they have been
110 added. The parsing will then be carried out on the output of the last filter in
111 the chain.
112 
113 Filters must be added before the first data chunk is written into the sink. If
114 data has already been written when a filter is added, an error is triggered.
115 )"};
116  return _signature;
117  }
118 END_METHOD
119 
120 BEGIN_METHOD(sink, Gap)
121  const auto& signature() const {
122  static auto _signature = hilti::operator_::Signature{.self = spicy::type::Sink(),
123  .result = type::void_,
124  .id = "gap",
125  .args = {{"seq", type::UnsignedInteger(64)},
126  {"len", type::UnsignedInteger(64)}},
127  .doc = R"(
128 Reports a gap in the input stream. *seq* is the sequence number of the first
129 byte missing, *len* is the length of the gap.
130 )"};
131  return _signature;
132  }
133 END_METHOD
134 
135 BEGIN_METHOD(sink, SequenceNumber)
136  const auto& signature() const {
137  static auto _signature = hilti::operator_::Signature{.self = type::constant(spicy::type::Sink()),
138  .result = type::UnsignedInteger(64),
139  .id = "sequence_number",
140  .args = {},
141  .doc = R"(
142 Returns the current sequence number of the sink's input stream, which is one
143 beyond the index of the last byte that has been put in order and delivered so far.
144 )"};
145  return _signature;
146  }
147 END_METHOD
148 
149 BEGIN_METHOD(sink, SetAutoTrim)
150  const auto& signature() const {
151  static auto _signature = hilti::operator_::Signature{.self = spicy::type::Sink(),
152  .result = type::void_,
153  .id = "set_auto_trim",
154  .args = {{"enable", type::Bool()}},
155  .doc = R"(
156 Enables or disables auto-trimming. If enabled (which is the default) sink input
157 data is trimmed automatically once in-order and processed. See ``trim()`` for
158 more information about trimming.
159 )"};
160  return _signature;
161  }
162 END_METHOD
163 
164 BEGIN_METHOD(sink, SetInitialSequenceNumber)
165  const auto& signature() const {
166  static auto _signature = hilti::operator_::Signature{.self = spicy::type::Sink(),
167  .result = type::void_,
168  .id = "set_initial_sequence_number",
169  .args =
170  {
171  {"seq", type::UnsignedInteger(64)},
172  },
173  .doc = R"(
174 Sets the sink's initial sequence number. All sequence numbers given to other
175 methods are then assumed to be absolute numbers beyond that initial number. If
176 the initial number is not set, the sink implicitly uses zero instead.
177 )"};
178  return _signature;
179  }
180 END_METHOD
181 
182 BEGIN_METHOD(sink, SetPolicy)
183  const auto& signature() const {
184  static auto _signature =
186  .result = type::void_,
187  .id = "set_policy",
188  .args =
189  {
190  {"policy",
191  type::Enum(type::Wildcard())}, // TODO(robin): Specify full type
192  },
193  .doc = R"(
194 Sets a sink's reassembly policy for ambiguous input. As long as data hasn't
195 been trimmed, a sink will detect overlapping chunks. This policy decides how to
196 handle ambiguous overlaps. The default (and currently only) policy is
197 ``ReassemblerPolicy::First``, which resolves ambiguities by taking the data
198 from the chunk that came first.
199 )"};
200  return _signature;
201  }
202 END_METHOD
203 
204 BEGIN_METHOD(sink, Skip)
205  const auto& signature() const {
206  static auto _signature = hilti::operator_::Signature{.self = spicy::type::Sink(),
207  .result = type::void_,
208  .id = "skip",
209  .args =
210  {
211  {"seq", type::UnsignedInteger(64)},
212  },
213  .doc = R"(
214 Skips ahead in the input stream. *seq* is the sequence number where to continue
215 parsing. If there's still data buffered before that position it will be
216 ignored; if auto-skip is also active, it will be immediately deleted as well.
217 If new data is passed in later that comes before *seq*, that will likewise be
218 ignored. If the input stream is currently stuck inside a gap, and *seq* lies
219 beyond that gap, the stream will resume processing at *seq*.
220 )"};
221  return _signature;
222  }
223 END_METHOD
224 
225 BEGIN_METHOD(sink, Trim)
226  const auto& signature() const {
227  static auto _signature = hilti::operator_::Signature{.self = spicy::type::Sink(),
228  .result = type::void_,
229  .id = "trim",
230  .args =
231  {
232  {"seq", type::UnsignedInteger(64)},
233  },
234  .doc = R"(
235 Deletes all data that's still buffered internally up to *seq*. If processing the
236 input stream hasn't reached *seq* yet, parsing will also skip ahead to *seq*.
237 
238 Trimming the input stream releases the memory, but that means that the sink won't be
239 able to detect any further data mismatches.
240 
241 Note that by default, auto-trimming is enabled, which means all data is trimmed
242 automatically once in-order and processed.
243 )"};
244  return _signature;
245  }
246 END_METHOD
247 
248 BEGIN_METHOD(sink, Write)
249  const auto& signature() const {
250  static auto _signature = hilti::operator_::Signature{.self = spicy::type::Sink(),
251  .result = type::void_,
252  .id = "write",
253  .args = {{"data", type::constant(type::Bytes())},
254  {"seq", type::UnsignedInteger(64), true},
255  {"len", type::UnsignedInteger(64), true}},
256  .doc = R"(
257 Passes data on to all connected parsing units. Multiple *write* calls act like
258 passing input in incrementally: The units will parse the pieces as if they were
259 a single stream of data. If no sequence number *seq* is provided, the data is
260 assumed to represent a chunk to be appended to the current end of the input
261 stream. If a sequence number is provided, out-of-order data will be buffered
262 and reassembled before being passed on. If *len* is provided, the data is assumed
263 to represent that many bytes inside the sequence space; if not provided, *len*
264 defaults to the length of *data*.
265 
266 If no units are connected, the call does not have any effect. If multiple units are
267 connected and one parsing unit throws an exception, parsing of subsequent units
268 does not proceed. Note that the order in which the data is parsed to each unit
269 is undefined.
270 
271 .. todo:: The error semantics for multiple units aren't great.
272 
273 )"};
274  return _signature;
275  }
276 END_METHOD
277 
278 } // namespace spicy::operator_
Definition: sink.h:12
Definition: unit.h:57
Definition: reference.h:15
Type self
Definition: operator.h:255
Definition: bitfield.h:17
Definition: operator.h:254