32namespace roboctrl::io{
37using data_ptr = std::shared_ptr<std::vector<std::byte>>;
48template<utils::
byte_container T>
50 auto res = std::make_shared<std::vector<std::byte>>(
t.size());
52 std::memcpy(
res->data(),
t.data(),
t.size());
74 return fn(std::span{data->data(), data->size()});
79 requires (!std::same_as<utils::function_arg_t<Fn>,
byte_span>)
82 using Arg = utils::function_arg_t<Fn>;
90 template<roboctrl::utils::package T>
94 requires (!std::same_as<T, byte_span>)
129 callbacks_[key].add([fn](
data_ptr data)
mutable ->
auto{
130 return fn(std::span{data->data(),data->size()});
137 template<
typename Fn>
138 requires (!std::same_as<utils::function_arg_t<Fn>,
byte_span>)
141 using Arg = utils::function_arg_t<Fn>;
154 if(callbacks_.contains(key)){
155 callbacks_.at(key)(
pd);
159 inline size_t package_size(
const TK& key){
164 std::map<TK,callback<data_ptr>> callbacks_;
165 std::map<TK,size_t> sizes_;
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>>;
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>>;
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>;
203 using parser_type = std::tuple_element_t<
N,std::tuple<
parser_types...>>;
206 using data_type =
typename parser_type<N>::data_type;
214 for(
auto&
parser : parsers){
231 return std::get<N>(parsers).data();
243 using data_type = std::array<std::byte,N>;
249 std::copy_n(
bytes.begin(),
N, data_.begin());
263template<roboctrl::utils::package T>
268 if(
bytes.size() <
sizeof(T)){
271 std::memcpy(
static_cast<void*
>(&data_),
static_cast<const void*
>(
bytes.data()),
sizeof(T));
285template<std::byte...
bytes>
287 using data_type = std::array<std::byte,
sizeof...(bytes)>;
289 constexpr static std::array<std::byte,
sizeof...(bytes)> bytes_data{
bytes...};
292 if(data.size() <
sizeof...(bytes)){
296 for(
size_t i = 0;
i <
sizeof...(bytes); ++
i)
297 if(data[
i] != bytes_data[
i])
300 return sizeof...(bytes);
334template<bare_io io_type>
336 co_await io.send(data);
347template<bare_io io_type>
350 co_await io.send(data);
361template<bare_io io_type,utils::package T>
374template<bare_io io_type,utils::package T>
awaitable< void > send(const T &data)
发送平凡类型数据。
void dispatch(byte_span bytes)
分发收到的字节流。
void on_data(callback_fn< byte_span > auto fn)
注册字节级别的回调。
void dispatch(const TK &key, byte_span data)
将数据派发给对应 key 的回调。
void on_data(const TK &key, callback_fn< byte_span > auto fn, size_t size=0)
注册指定 key 的回调。
void on_data(const TK &key, Fn &&fn)
注册平凡类型包的回调。
约束回调类型可被调用且返回 void 或 awaitable<void>。
裸 IO 概念,要求具备 send/task 协程接口。
带 key 的 IO 概念,要求具备 send/task 协程接口。
std::span< std::byte > byte_span
byte span,实际上就是一个std::span<std::byte>;
std::shared_ptr< std::vector< std::byte > > data_ptr
数据指针,实际上是一个std::shared_ptr<std::vector<std::byte>>;
awaitable< void > send(io_type &io, byte_span data)
发送原始字节流,适配任意裸 IO。
data_ptr make_shared_from(const T &t)
将任意满足 byte_container 的数据拷贝到共享缓冲。
asio::awaitable< T > awaitable
协程任务类型。
T from_bytes(const C &bytes)
将字节容器内容反序列化为平凡类型。
void to_bytes(const T &t, C &container)
将平凡类型序列化到指定容器。
auto data() -> data_type< N >
获取指定序号解析器的解析结果。
size_t parse(byte_span data)
依次执行所有解析器。