Branch data Line data Source code
1 : : /*
2 : : * Copyright 2025 Jinwoo Sung
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #pragma once
18 : :
19 : : #include <optional>
20 : : #include <string>
21 : : #include <string_view>
22 : : #include <vector>
23 : :
24 : : #include "wirestead/base/visibility.hpp"
25 : : #include "wirestead/framer/iframer.hpp"
26 : :
27 : : namespace wirestead {
28 : : namespace framer {
29 : :
30 : : /**
31 : : * @brief Framer for text-based protocols (e.g., ASCII, NMEA).
32 : : *
33 : : * Buffers incoming data and extracts messages delimited by a specific sequence (e.g., "\n").
34 : : */
35 : : class WIRESTEAD_API LineFramer : public IFramer {
36 : : public:
37 : : /**
38 : : * @brief Construct a new Line Framer
39 : : *
40 : : * @param delimiter The delimiter string (default: "\n")
41 : : * @param include_delimiter Whether to include the delimiter in the extracted message (default: false)
42 : : * @param max_length Maximum message length before forcing a reset (default: 65536)
43 : : */
44 : : explicit LineFramer(std::string_view delimiter = "\n", bool include_delimiter = false, size_t max_length = 65536);
45 : :
46 : 114 : ~LineFramer() override = default;
47 : :
48 : : void push_bytes(memory::ConstByteSpan data) override;
49 : : void on_message(MessageCallback cb) override;
50 : : void reset() override;
51 : :
52 : : private:
53 : : std::string delimiter_;
54 : : bool include_delimiter_;
55 : : size_t max_length_;
56 : :
57 : : size_t scanned_idx_ = 0;
58 : : std::vector<uint8_t> buffer_;
59 : : MessageCallback on_message_;
60 : :
61 : : // Set when an in-progress message exceeded max_length_ and buffer_ was
62 : : // discarded before a delimiter was found. While true, push_bytes_internal
63 : : // discards incoming bytes (instead of buffering them) until it finds a
64 : : // delimiter, so the untransmitted tail of the discarded message can't be
65 : : // mistaken for the start of a fresh, valid message.
66 : : bool discarding_ = false;
67 : :
68 : : /**
69 : : * @brief Helper to scan data for delimiters and process messages.
70 : : *
71 : : * @param data The data to scan.
72 : : * @param search_start_offset The offset in data to start searching from.
73 : : * @return The number of bytes processed (emitted as messages).
74 : : */
75 : : size_t scan_and_process(memory::ConstByteSpan data, size_t search_start_offset);
76 : :
77 : : /**
78 : : * @brief Find the end of the next delimiter in data, if any.
79 : : *
80 : : * @param data The data to scan (searched from the beginning).
81 : : * @return The number of bytes up to and including the delimiter, or
82 : : * std::nullopt if no delimiter was found in data.
83 : : */
84 : : std::optional<size_t> skip_until_delimiter(memory::ConstByteSpan data) const;
85 : :
86 : : /**
87 : : * @brief Internal helper to process a manageable chunk of data.
88 : : */
89 : : void push_bytes_internal(memory::ConstByteSpan data);
90 : : };
91 : :
92 : : } // namespace framer
93 : : } // namespace wirestead
|