GKD.RoboCtrl
载入中...
搜索中...
未找到
base.hpp
浏览该文件的文档.
1
13#pragma once
14
15#include <algorithm>
16#include <array>
17#include <concepts>
18#include <cstddef>
19#include <cstring>
20#include <span>
21#include <tuple>
22#include <type_traits>
23#include <map>
24#include <memory>
25#include <utility>
26
27#include "core/async.hpp"
28#include "utils/callback.hpp"
29#include "utils/utils.hpp"
30#include "utils/concepts.hpp"
31
32namespace roboctrl::io{
33
37using data_ptr = std::shared_ptr<std::vector<std::byte>>;
38
42using byte_span = std::span<std::byte>;
43
48template<utils::byte_container T>
50 auto res = std::make_shared<std::vector<std::byte>>(t.size());
51 if (t.size() > 0)
52 std::memcpy(res->data(), t.data(), t.size());
53 return res;
54}
55
63 :public utils::immovable_base,
65{
66public:
67 inline bare_io_base(){}
68
72 inline void on_data(callback_fn<byte_span> auto fn){
73 callback_.add([fn](data_ptr data) mutable -> auto {
74 return fn(std::span{data->data(), data->size()});
75 });
76 }
77
78 template<typename Fn>
79 requires (!std::same_as<utils::function_arg_t<Fn>,byte_span>)
80 inline void on_data(Fn&& fn)
81 {
82 using Arg = utils::function_arg_t<Fn>;
84
85 on_data([fn = std::forward<Fn>(fn)](byte_span bytes) mutable {
86 return fn(utils::from_bytes<std::remove_cvref_t<Arg>>(bytes));
87 });
88 }
89
90 template<roboctrl::utils::package T>
94 requires (!std::same_as<T, byte_span>)
95 inline awaitable<void> send(const T& data){
96 co_await send(utils::to_bytes(data));
97 }
98protected:
104
105 callback_(make_shared_from(bytes));
106 }
107
108private:
109 callback<data_ptr> callback_;
110};
111
116template<typename TK>
118 :public utils::immovable_base,
120{
121public:
122 inline keyed_io_base(){};
123
127 void on_data(const TK& key,callback_fn<byte_span> auto fn,size_t size = 0){
128 sizes_[key] = size;
129 callbacks_[key].add([fn](data_ptr data) mutable -> auto{
130 return fn(std::span{data->data(),data->size()});
131 });
132 }
133
137 template<typename Fn>
138 requires (!std::same_as<utils::function_arg_t<Fn>,byte_span>)
139 inline void on_data(const TK& key,Fn&& fn)
140 {
141 using Arg = utils::function_arg_t<Fn>;
143
144 on_data(key,[fn = std::forward<Fn>(fn)](byte_span bytes) mutable {
145 return fn(utils::from_bytes<std::remove_cvref_t<Arg>>(bytes));
146 },sizeof(Arg));
147 }
148protected:
152 inline void dispatch(const TK& key,byte_span data){
153 auto pd = make_shared_from(data);
154 if(callbacks_.contains(key)){
155 callbacks_.at(key)(pd);
156 }
157 }
158
159 inline size_t package_size(const TK& key){
160 return sizes_[key];
161 }
162
163private:
164 std::map<TK,callback<data_ptr>> callbacks_;
165 std::map<TK,size_t> sizes_;
166};
167
171template<typename T>
172concept bare_io = std::is_base_of_v<bare_io_base, T> && requires (T t){
173 {t.task()} -> std::same_as<awaitable<void>>;
174 {t.send(std::declval<byte_span>())} -> std::same_as<awaitable<void>>;
175};
176
180template<typename T>
181concept keyed_io = std::is_base_of_v<keyed_io_base<typename T::key_type>, T> && requires (T t) {
182 typename T::key_type;
183 {t.task()} -> std::same_as<awaitable<void>>;
184 {t.send(std::declval<typename T::key_type>(),std::declval<byte_span>())} -> std::same_as<awaitable<void>>;
185};
186
190template<typename T>
191concept data_parser = requires (T t,byte_span bytes){
192 typename T::data_type;
193 {t.parse(std::declval<size_t>(),bytes)} -> std::same_as<std::size_t>;
194 {t.data()} -> std::same_as<typename T::data_type>;
195};
196
200template<data_parser... parser_types>
202 template<int N>
203 using parser_type = std::tuple_element_t<N,std::tuple<parser_types...>>;
204
205 template<int N>
206 using data_type = typename parser_type<N>::data_type;
207
213 size_t pos = 0;
214 for(auto& parser : parsers){
215 size_t diff = parser.parse(pos,data);
216
217 if(!diff)
218 return false;
219
220 pos += diff;
221 }
222
223 return pos;
224 }
225
229 template<int N>
231 return std::get<N>(parsers).data();
232 }
233
234 std::tuple<parser_types...> parsers;
235};
236
241template<int N>
242struct nbytes{
243 using data_type = std::array<std::byte,N>;
244
245 std::size_t parse(byte_span bytes){
246 if(bytes.size() < N){
247 return 0;
248 }
249 std::copy_n(bytes.begin(), N, data_.begin());
250 return N;
251 }
252
253 data_type data(){
254 return data_;
255 }
256
257 data_type data_;
258};
259
263template<roboctrl::utils::package T>
265 using data_type = T;
266
267 std::size_t parse(byte_span bytes){
268 if(bytes.size() < sizeof(T)){
269 return 0;
270 }
271 std::memcpy(static_cast<void*>(&data_), static_cast<const void*>(bytes.data()), sizeof(T));
272 return sizeof(T);
273 }
274
275 data_type data(){
276 return data_;
277 }
278
279 data_type data_;
280};
281
285template<std::byte... bytes>
287 using data_type = std::array<std::byte,sizeof...(bytes)>;
288
289 constexpr static std::array<std::byte,sizeof...(bytes)> bytes_data{bytes...};
290
291 std::size_t parse(byte_span data){
292 if(data.size() < sizeof...(bytes)){
293 return 0;
294 }
295
296 for(size_t i = 0; i < sizeof...(bytes); ++i)
297 if(data[i] != bytes_data[i])
298 return 0;
299
300 return sizeof...(bytes);
301 }
302
303 data_type data(){
304 return bytes_data;
305 }
306};
307
312 using data_type = byte_span;
313
314 size_t parse(byte_span data){
315 data_ = data;
316 return data.size();
317 }
318
319 data_type data(){
320 return data_;
321 }
322
323 data_type data_;
324};
325
334template<bare_io io_type>
336 co_await io.send(data);
337}
338
347template<bare_io io_type>
348awaitable<void> send(const typename io_type::info_type::key_type& key,byte_span data){
349 auto& io = roboctrl::get<io_type>(key);
350 co_await io.send(data);
351}
352
361template<bare_io io_type,utils::package T>
363 co_await send(io,utils::to_bytes(pkg));
364}
365
374template<bare_io io_type,utils::package T>
375awaitable<void> send(const typename io_type::info_type::key_type& key,const T& pkg){
376 co_await send(key,utils::to_bytes(pkg));
377}
378}
379
异步任务上下文组件。
协程回调收集器。
void add(F &&f)
添加一个新的回调。
Definition callback.hpp:54
裸IO组件。
Definition base.hpp:65
awaitable< void > send(const T &data)
发送平凡类型数据。
Definition base.hpp:95
void dispatch(byte_span bytes)
分发收到的字节流。
Definition base.hpp:103
void on_data(callback_fn< byte_span > auto fn)
注册字节级别的回调。
Definition base.hpp:72
带 key 的 IO 基类,根据键值派发数据。
Definition base.hpp:120
void dispatch(const TK &key, byte_span data)
将数据派发给对应 key 的回调。
Definition base.hpp:152
void on_data(const TK &key, callback_fn< byte_span > auto fn, size_t size=0)
注册指定 key 的回调。
Definition base.hpp:127
void on_data(const TK &key, Fn &&fn)
注册平凡类型包的回调。
Definition base.hpp:139
约束回调类型可被调用且返回 void 或 awaitable<void>。
Definition callback.hpp:25
裸 IO 概念,要求具备 send/task 协程接口。
Definition base.hpp:172
数据解析器概念,负责按需消费字节并返回结果。
Definition base.hpp:191
带 key 的 IO 概念,要求具备 send/task 协程接口。
Definition base.hpp:181
用于约束“可安全作为报文搬运”的平凡类型。
Definition concepts.hpp:78
公共Concept与元类型工具。
std::span< std::byte > byte_span
byte span,实际上就是一个std::span<std::byte>;
Definition base.hpp:42
std::shared_ptr< std::vector< std::byte > > data_ptr
数据指针,实际上是一个std::shared_ptr<std::vector<std::byte>>;
Definition base.hpp:37
awaitable< void > send(io_type &io, byte_span data)
发送原始字节流,适配任意裸 IO。
Definition base.hpp:335
data_ptr make_shared_from(const T &t)
将任意满足 byte_container 的数据拷贝到共享缓冲。
Definition base.hpp:49
asio::awaitable< T > awaitable
协程任务类型。
Definition async.hpp:42
T from_bytes(const C &bytes)
将字节容器内容反序列化为平凡类型。
Definition utils.hpp:121
void to_bytes(const T &t, C &container)
将平凡类型序列化到指定容器。
Definition utils.hpp:140
组合式解析器,可顺序堆叠多个数据解析单元。
Definition base.hpp:201
auto data() -> data_type< N >
获取指定序号解析器的解析结果。
Definition base.hpp:230
size_t parse(byte_span data)
依次执行所有解析器。
Definition base.hpp:212
固定内容匹配解析器。
Definition base.hpp:286
固定长度字节解析器。
Definition base.hpp:242
吃掉剩余全部数据的解析器。
Definition base.hpp:311
平凡结构体解析器。
Definition base.hpp:264
快速继承获得“不可移动”约束的基类。
Definition concepts.hpp:59
快速继承获得“不可复制”约束的基类。
Definition concepts.hpp:68
常用数值与字节工具集合。